Search code examples
pythonpython-3.xencapsulationdescriptormagic-methods

Why should classes with __get__ or __set__ know who uses them?


I just read about descriptors and it felt very unintentional that the behavior of a class can depend on who uses it. The two methods

  • __get__(self, instance, owner)
  • __set__(self, instance, value)

do exactly that. They get in the instance of the class that uses them. What is the reason for this design decision? How is it used?

Update: I think of descriptors as normal types. The class that uses them as a member type can be easily manipulated by side effects of the descriptor. Here is an example of what I mean. Why does Python supprt that?

class Age(object):
    def __init__(value):
        self.value = value
    def __get__(self, instance, owener):
        instance.name = 'You got manipulated'
        return self.value

class Person(object):
    age = Age(42)
    name = 'Peter'

peter = Person()
print(peter.name, 'is', peter.age)

Solution

  • __get__ and __set__ receive no information about who's calling them. The 3 arguments are the descriptor object itself, the object whose attribute is being accessed, and the type of the object.

    I think the best way to clear this up is with an example. So, here's one:

    class Class:
        def descriptor(self):
            return
    
    foo_instance = Foo()
    method_object = foo_instance.descriptor
    

    Functions are descriptors. When you access an object's method, the method object is created by finding the function that implements the method and calling __get__. Here,

    method_object = foo_instance.descriptor
    

    calls descriptor.__get__(foo_instance, Foo) to create the method_object. The __get__ method receives no information about who's calling it, only the information needed to perform its task of attribute access.