Можно ли получить доступ к классу "владелец" внутри дескриптора во время функции __init__
этого дескриптора, не передавая его вручную, как в этом примере?
class FooDescriptor(object):
def __init__(self, owner):
#do things to owner here
setattr(owner, 'bar_attribute', 'bar_value')
class BarClass(object):
foo_attribute = FooDescriptor(owner=BarClass)
Один из способов сделать что-то вроде метакласса. Просто убедитесь, что это действительно то, что вы хотите, и не просто копируйте вслепую, если вы не понимаете, как это работает.
class Descriptor(object):
pass
class Meta(type):
def __new__(cls, name, bases, attrs):
obj = type.__new__(cls, name, bases, attrs)
# obj is now a type instance
# this loop looks for Descriptor subclasses
# and instantiates them, passing the type as the first argument
for name, attr in attrs.iteritems():
if isinstance(attr, type) and issubclass(attr, Descriptor):
setattr(obj, name, attr(obj))
return obj
class FooDescriptor(Descriptor):
def __init__(self, owner):
owner.foo = 42
class BarClass(object):
__metaclass__ = Meta
foo_attribute = FooDescriptor # will be instantiated by the metaclass
print BarClass.foo
Если вам нужно передать дополнительные аргументы, вы можете использовать, например. кортеж (class, args)
вместо класса или сделать FooDescriptor
декоратор, который вернет класс, который принимает только один аргумент в ctor.
__new__()
что-то отличное от dict
...
ns
; это dict
потому что он соответствует типу __dict__
, хотя. Сокрытие встроенного dict
не так уж и страшно и здесь не очень важно.
Начиная с Python 3.6, вы можете использовать специальный метод __set_name__
:
class FooDescriptor(object):
def __set_name__(self, owner, name):
owner.foo = 42
class BarClass(object):
foo_attribute = FooDescriptor()
# foo_attribute.__set_name__(BarClass, "foo_attribute") called after class definition
__set_name__
автоматически вызывается во всех дескрипторах класса сразу после его создания. См. PEP 487 для более подробной информации.
setattr(owner, 'bar_attribute', 'bar_value')
вместоowner.bar_attribute = 'bar_value'
?FooDecoractor
/ создаватьFooDecoractor
. Pythonic путь, как правило, «быть явным».