什么时候调用python描述符方法?

时间:2014-01-04 09:25:27

标签: python descriptor

我使用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 numberis setting number

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

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

我总结了我的起源猜测:

  1. 获取

    • 使用obj.prop获取属性时,prop是另一个设置描述符
    • 的对象
    • 计算某些表达式时应获取a + 5等值。如果a有描述符并将调用__get__
    • 如果对象模拟某个函数,则会先调用__get__来获取函数体,然后调用__call__来运行该函数。
    • 当对象出现在赋值语句的左侧时,例如obj = 5
  2. 但我一定是错的,我需要有人告诉我正确的概念。

2 个答案:

答案 0 :(得分:8)

您的描述符未被调用,并且无法编写描述符或其他任何内容来执行您想要的操作。

执行num = 2时,您已丢弃Number个对象并将变量num设置为普通数字2.当您向其添加7时,它等于9,因为它只是一个常规数字。您的Number课程没有任何参与。

描述符可让您了解执行obj.fooobj.foo = blah时会发生什么。在这些情况下,foo是描述符,而不是obj,描述符仅在属性时才有效。没有办法改变obj = blah时发生的事情,其中​​obj是一个裸名称(即没有点或[])。关于你的猜测:

  1. 获取

    • 当使用obj.prop获取属性时,prop是另一个设置描述符的对象
      • 是的,基本上。如果obj.propprop是描述符,则会调用其__get__。请注意,prop是描述符,而不是obj
    • 计算某些表达式时应获取a + 5等值。如果a有描述符并且会调用__get__
      • 否。您可以使用__add__魔术方法或其他运算符的类似方法覆盖此类行为
    • 如果对象模拟某个函数,则会先调用__get__来获取函数体,然后调用__call__来运行该函数。
      • 我不明白这意味着什么,但我认为不是。如果对象定义__call__,则obj()会调用其__call__而不涉及任何描述符。
    • 当对象出现在赋值语句的左侧时,例如obj = 5
      • 否。只有在左侧访问描述符作为属性时,如obj.prop = 5中,prop是描述符。
  2. 底线是描述符仅在它们是类的属性时才起作用。只是在你试图做的时候创建一个“裸”描述符(即,做obj = SomeDescriptorClass())将不会做任何事情。

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

答案 1 :(得分:3)

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

描述符必须是实例的属性,并且继承自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)