在描述符的__init__方法中,我能获取'owner'类的引用吗?

2 投票
2 回答
2054 浏览
提问于 2025-04-16 18:05

在描述符的__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 个回答

4

从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

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 做成一个装饰器,这样它就可以返回一个只在构造函数中接受一个参数的类。

撰写回答