Могу ли я получить ссылку на класс владельца в методе дескриптора __init__?

1

Можно ли получить доступ к классу "владелец" внутри дескриптора во время функции __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)
  • 2
    Почему setattr(owner, 'bar_attribute', 'bar_value') вместо owner.bar_attribute = 'bar_value' ?
  • 1
    Я уверен, что нет (без магии стека вызовов, которую я ожидал увидеть в ответе). Нет ничего особенного в том, чтобы FooDecoractor / создавать FooDecoractor . Pythonic путь, как правило, «быть явным».
Показать ещё 2 комментария
Теги:
python-2.5

2 ответа

4
Лучший ответ

Один из способов сделать что-то вроде метакласса. Просто убедитесь, что это действительно то, что вы хотите, и не просто копируйте вслепую, если вы не понимаете, как это работает.

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.

  • 0
    Вероятно, следует переименовать последний аргумент, переданный __new__() что-то отличное от dict ...
  • 0
    @martineau: Ну, может , может быть, для ns ; это dict потому что он соответствует типу __dict__ , хотя. Сокрытие встроенного dict не так уж и страшно и здесь не очень важно.
Показать ещё 1 комментарий
0

Начиная с 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 для более подробной информации.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню