为什么实例属性定义的描述符没有被调用?

12 投票
1 回答
1978 浏览
提问于 2025-04-18 04:21

当我把“data”这个变量设为类变量时,下面的代码可以正常运行。但是当我把它设为对象变量时,描述符没有被调用。请帮帮我。

class Data(object):
    products = {
        'milk': {'price': 1.50, 'quantity': 10},
        'eggs': {'price': 0.20, 'quantity': 100},
        'cheese': {'price': 2.00, 'quantity': 10}
    }
    def __get__(self, obj, klas):
        print "Here in descriptor"
        return self.products

class BusinessLogic(object):
    def __init__(self):         # When I remove these 2 lines 
        self.data = Data()
    #data = Data()             # and enable this line it does work !

def main():
    b = BusinessLogic()
    b.data

if __name__ == '__main__':
    main()

1 个回答

16

这是因为描述符应该只作为类的属性来定义,而不是实例的属性:

根据文档

以下方法仅在包含该方法的类的实例(也就是所谓的描述符类)出现在拥有者类中时适用(描述符必须在拥有者的类字典中,或者在其父类的类字典中)。

如果你想让描述符也能和实例属性一起工作,你需要重写__getattribute__方法在BusinessLogic类中。(虽然我没有彻底测试过,但在你的情况下应该没问题):

def __getattribute__(self, attr):
        obj = object.__getattribute__(self, attr)
        if hasattr(obj, '__get__'):
            return obj.__get__(self, type(self))
        return obj

如果你有数据描述符,那么你还需要处理__setattr__部分。

def __setattr__(self, attr, val):
    try:
        obj = object.__getattribute__(self, attr)
    except AttributeError:
        # This will be raised if we are setting the attribute for the first time
        # i.e inside `__init__` in your case.
        object.__setattr__(self, attr, val)
    else:
        if hasattr(obj, '__set__'):
            obj.__set__(self, val)
        else:
            object.__setattr__(self, attr, val)

撰写回答