【问题标题】:When python descriptor method would be called?什么时候会调用 python 描述符方法?
【发布时间】:2014-01-04 09:25:26
【问题描述】:

我使用 python 描述符模拟了一些数据。

class Number:
    def __init__(self):
        self.num = 0 

    def __get__(self, instance, obj):
        print("is getting number")
        return self.number

    def __set__(self, instance, value):
        print("is setting number")
        self.number = value

    def __str__(self):
        return str(self.number)

num = Number()
num = 2 
print(num + 7)

输出:

9

好像成功调用了__get____set__方法,但是不知道为什么没有输出消息is getting number或者is setting number

我不确定python是否调用了描述符方法。

我的问题是什么时候会调用描述符方法?

我总结一下我的起源猜测:

  1. 得到

    • 当使用obj.prop获取属性时,prop是另一个设置描述符的对象
    • 在计算某些表达式时应该得到值,例如a + 5。如果 a 有描述符并将调用 __get__
    • 如果对象模拟一个函数,会先调用__get__获取函数体,再调用__call__运行函数。
  2. 设置

    • 当对象出现在赋值语句左侧如obj = 5

但我一定是错的,我需要有人告诉我正确的概念。

【问题讨论】:

    标签: python descriptor


    【解决方案1】:

    你的描述符没有被调用,也没有办法写一个描述符或其他任何东西来做你想做的事。

    当您执行num = 2 时,您已经丢弃了您的Number 对象并将变量num 设置为普通数字2。当您将7 加到它上时,它等于9,因为它只是一个普通数字.您的Number 课程不会以任何方式参与。

    描述符允许您了解当您执行obj.fooobj.foo = blah 时会发生什么。在这些情况下,描述符是foo,而不是obj,并且描述符仅在它是属性时才有效。当您执行obj = blah 时,无法更改发生的情况,其中obj 是一个简单的名称(即没有点或[])。关于你的猜测:

    1. 得到

      • 当使用 obj.prop 获取属性时,prop 是另一个正在设置描述符的对象
        • 是的,基本上。当您执行obj.prop 并且prop 是一个描述符时,它的__get__ 会被调用。请注意,prop 是描述符,而不是 obj
      • 在计算某些表达式时应该得到值,例如a + 5。如果 a 有描述符并将调用 __get__
        • 没有。您可以使用 __add__ 魔术方法或其他运算符的类似方法覆盖此类行为
      • 如果对象模拟一个函数,会先调用__get__获取函数体,再调用__call__运行函数。
        • 我不明白这是什么意思,但我认为没有。如果对象定义了__call__,则obj() 调用它的__call__ 而不涉及任何描述符。
    2. 设置

      • 当对象出现在赋值语句左侧如obj = 5
        • 没有。仅当描述符在左侧作为属性访问时,如obj.prop = 5,其中prop是描述符。

    底线是描述符仅在它们是类的属性时才有效。只是在你尝试做的时候创建一个“裸”描述符(即,做obj = SomeDescriptorClass())不会做任何事情。

    另外,作为旁注,描述符仅在新样式类上设置时才有效。如果您使用的是 Python 2,这意味着持有描述符的类必须继承自 object

    【讨论】:

    • 谢谢。那么,描述符只发生在对象的属性中吗?
    • 我解释一下我所说的emulate function。在官方doc。模拟使用__get__ 模拟@classmethod。所以,我猜调用函数会先调用__get__
    • @FreedomKnight:是的。如果您四处搜索,您可以在本网站上找到很多关于描述符的其他问题,以及网络上的描述。
    • @FreedomKnight:在那个例子中,描述符又是一个属性。它恰好返回一个可调用对象,但这与描述符协议的工作方式无关。在这种情况下,它的工作原理与在任何其他情况下相同。
    【解决方案2】:

    num = 2 使 num 成为 int 但不再是 Number

    Descriptor 需要是实例的属性,并且继承自object

    class Number(object):
        def __init__(self):
            self.num = 0
    
        def __get__(self, instance, obj):
            print("is getting number")
            return self.num
    
        def __set__(self, instance, value):
            print("is setting number")
            self.num = value
    
        # no need to define this for descriptor
        def __str__(self):
            return str(self.num)
    
    class A(object):
        num = Number()
    
    n = A()
    n.num = 5
    print(n.num + 7)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-03
      • 2015-12-15
      • 2018-12-22
      • 2011-07-21
      相关资源
      最近更新 更多