Pregunta

I simulate some data using python descriptor.

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)

the output:

9

It seems successfully call the method __get__ and __set__, but i don't know why there's no output message is getting number or is setting number.

I'm not sure whether python call the descriptor method or not.

my question is when descriptor method would be called?

I summary my origin guess:

  1. get

    • When use obj.prop to get property and the prop is another object which is setting descriptor
    • when calculate some expression should get value such as a + 5. If a is have descriptor and will call __get__
    • If a object simulate a function will call __get__ to get function body first, and then call __call__ to run the function.
  2. set

    • When the object appear in the left side of assignment statement such as obj = 5

But I must be wrong, i need someone to tell me the right concept.

¿Fue útil?

Solución

Your descriptors are not being called, and there is no way to write a descriptor or anything else to do what you seem to want.

When you do num = 2, you have thrown away your Number object and set the variable num to the ordinary number 2. When you then add 7 to it, it equals 9, because it's just a regular number. Your Number class is not involved in any way.

Descriptors allow you to hook into what happens when you do obj.foo or obj.foo = blah. In these cases it is foo that is the descriptor, not obj, and the descriptor only works when it is an attribute. There is no way to change what happens when you do obj = blah, where obj is a bare name (i.e., no dots or []). In relation to your guess:

  1. get

    • When use obj.prop to get property and the prop is another object which is setting descriptor
      • Yes, basically. When you do obj.prop and prop is a descriptor, then its __get__ is called. Note that prop is the descriptor, not obj.
    • when calculate some expression should get value such as a + 5. If a is have descriptor and will call __get__
      • No. You can override such behavior with the __add__ magic method, or similar methods for other operators
    • If a object simulate a function will call __get__ to get function body first, and then call __call__ to run the function.
      • I don't understand what this means, but I think no. If the object defines __call__, then obj() calls its __call__ without involving any descriptor.
  2. set

    • When the object appear in the left side of assignment statement such as obj = 5
      • No. Only when the descriptor is accessed as an attribute on the left side, as in obj.prop = 5, where prop is a descriptor.

The bottom line is that descriptors only work when they are attributes of classes. Just creating a "bare" descriptor as you're trying to do (i.e., doing obj = SomeDescriptorClass()) won't do anything.

Also, as a side note, descriptors only work when set on new-style classes. If you're using Python 2, this means that the class holding the descriptor has to inherit from object.

Otros consejos

num = 2 makes num an int but not Number anymore.

Descriptor needs to be an attribute of instance and inherited from 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)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top