【问题标题】:Can I get a reference to the 'owner' class during the __init__ method of a descriptor?我可以在描述符的 __init__ 方法中获得对“所有者”类的引用吗?
【发布时间】:2011-05-21 18:41:38
【问题描述】:

是否可以在描述符的__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)

【问题讨论】:

  • 为什么是setattr(owner, 'bar_attribute', 'bar_value') 而不是owner.bar_attribute = 'bar_value'
  • 我很确定 No (没有调用堆栈魔术,我希望在响应中看到)。像这样调用/创建FooDecoractor 并没有什么特别之处。 Pythonic 方式通常是“显式”。
  • 有关调用堆栈魔法,请参阅SO: How to get the callers method name?
  • 仔细检查后,我什至无法将拥有的类作为参考传递,因为那时它还没有定义。我将不得不找到另一个解决方案。谢谢大家。

标签: python python-2.5


【解决方案1】:

做这样的事情的一种方法是使用元类。只要确保它确实是您想要的,如果您不了解它是如何工作的,请不要盲目复制。

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...
  • @martineau:嗯,可以,也许是ns;它是dict,因为它对应于类型的__dict__。隐藏内置的dict 并没有那么可怕,而且在这里几乎无关紧要。
  • classdict 是个好名字。真正的重点是当dict 出现在any 代码中时,恕我直言,它应该是内置的——不管内置的当前是否正在使用,甚至可能曾经使用过。无论如何,聪明的答案。 +1
【解决方案2】:

从 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

【讨论】:

    猜你喜欢
    • 2015-10-04
    • 2021-09-23
    • 1970-01-01
    • 1970-01-01
    • 2011-07-13
    • 2019-09-11
    • 2012-05-01
    • 1970-01-01
    相关资源
    最近更新 更多