Если «переменная» является переменной экземпляра - так, если в любой точке цепи __init__
методов вы:
def __init__(self):
self.findMe = "Here I am!"
Это переменная экземпляра с этого момента, и не может, для все эффекты должны быть отличны от любой другой переменной экземпляра. (Если вы не создадите механизм, например класс со специальным методом __setattr__
, который будет отслеживать изменения атрибутов и заново проверять, какая часть кода устанавливает атрибут - см. Последний пример этого ответа)
также обратите внимание, что на вашем примере,
class parent(object):
def __init__(self):
findMe = "Here I am!"
findMe
определяется как локальная переменная к этому методу и даже не существует после того, как __init__
закончена.
Теперь, если ваша переменная установлена в качестве атрибута класса где-то на наследование цепи:
class parent(object):
findMe = False
class childone(parent):
...
можно найти класс, где findMe
определяется по интроспекции каждого класса __dict__
в (метод MRO порядок разрешения). Конечно, нет никакого способа, и нет смысла, делая это без интроспекции всех классов в цепочке MRO, за исключением того, что если отслеживать атрибуты как определенные, как в приведенном ниже примере, но и самоанализ сам MRO является oneliner в Python:
def __init__(self):
super().__init__()
...
findme_definer = [cls for cls in self.__class__.__mro__ if "findMe" in cls.__dict__][0]
Опять же - можно было бы иметь метакласс к вашей наследственной цепи, которая будет следить за все определенные атрибуты в дереве наследования, а также использовать словарь для извлечения, где определяются каждый атрибут. Тот же метакласс также может автоматически украсить все __init__
(или все методы) и установить специальный __setitem__
, чтобы он мог отслеживать атрибуты экземпляра по мере их создания, как указано выше.
Это можно сделать, немного сложно, было бы сложно поддерживать, и, вероятно, это сигнал, по которому вы неправильно подходите к своей проблеме.
Таким образом, метаклас для записи только атрибутов класса может быть просто (синтаксис python3 - определить атрибут __metaclass__
для тела класса, если вы все еще используете Python 2.7):
class MetaBase(type):
definitions = {}
def __init__(cls, name, bases, dct):
for attr in dct.keys():
cls.__class__.definitions[attr] = cls
class parent(metaclass=MetaBase):
findMe = 5
def __init__(self):
print(self.__class__.definitions["findMe"])
Теперь, если кто-то хочет, чтобы выяснить, какие из суперкласса определен атрибут currentclass, только «живой» механизм отслеживания, обернув каждый метод в каждом классе может работать - это намного сложнее ,
Я сделал это - даже если вам это не понадобится, это сочетает в себе оба метода - отслеживание атрибутов класса в классе класса definitions
и в экземпляре словаря _definitions
- поскольку в каждом созданном экземпляре произвольный метод, возможно, был последним, чтобы установить конкретный атрибут экземпляра: (Это чистый Python3 и, возможно, не тот перенос переноса на Python2 из-за «несвязанного метода», который использует Python2, и является простой функцией в Python3)
from threading import current_thread
from functools import wraps
from types import MethodType
from collections import defaultdict
def method_decorator(func, cls):
@wraps(func)
def wrapper(self, *args, **kw):
self.__class__.__class__.current_running_class[current_thread()].append(cls)
result = MethodType(func, self)(*args, **kw)
self.__class__.__class__.current_running_class[current_thread()].pop()
return result
return wrapper
class MetaBase(type):
definitions = {}
current_running_class = defaultdict(list)
def __init__(cls, name, bases, dct):
for attrname, attr in dct.items():
cls.__class__.definitions[attr] = cls
if callable(attr) and attrname != "__setattr__":
setattr(cls, attrname, method_decorator(attr, cls))
class Base(object, metaclass=MetaBase):
def __setattr__(self, attr, value):
if not hasattr(self, "_definitions"):
super().__setattr__("_definitions", {})
self._definitions[attr] = self.__class__.current_running_class[current_thread()][-1]
return super().__setattr__(attr,value)
Примеры классов для кода:
class Parent(Base):
def __init__(self):
super().__init__()
self.findMe = 10
class Child1(Parent):
def __init__(self):
super().__init__()
self.findMe1 = 20
class Child2(Parent):
def __init__(self):
super().__init__()
self.findMe2 = 30
class GrandChild(Child1, Child2):
def __init__(self):
super().__init__()
def findall(self):
for attr in "findMe findMe1 findMe2".split():
print("Attr '{}' defined in class '{}' ".format(attr, self._definitions[attr].__name__))
А на консоли один получит этот результат:
In [87]: g = GrandChild()
In [88]: g.findall()
Attr 'findMe' defined in class 'Parent'
Attr 'findMe1' defined in class 'Child1'
Attr 'findMe2' defined in class 'Child2'
... и когда вы говорите, 'возможно, называя какой-то function', вы не хотите, чтобы функция для навигации по иерархии наследования либо, правильно? – Gerrat