self __setter setter self __name__ getter __name__ the class' initializer takes one or two functions as arguments if it is used as decoratorit will get just the decorated function and this becomes the getterwhile the setter is set to none we use the getter' name as the property' name so for each propertywe have getterpossibly setterand name def __get__(selfinstanceowner=none)if instance is nonereturn self return self __getter(instancewhen property is accessed we return the result of calling the getter function where we have passed the instance as its first parameter at first sightself __getter(looks like method callbut it is not in factself __getter is an attributeone that happens to hold an object reference to method that was passed in so what happens is that first we retrieve the attribute (self __getter)and then we call it as function (and because it is called as function rather than as method we must pass in the relevant self object explicitly ourselves and in the case of descriptor the self object (from the class that is using the descriptoris called instance (since self is the descriptor objectthe same applies to the __set__(method def __set__(selfinstancevalue)if self __setter is noneraise attributeerror("'{ }is read-onlyformatself __name__)return self __setter(instancevalueif no setter has been specifiedwe raise an attributeerrorotherwisewe call the setter with the instance and the new value def setter(selfsetter)self __setter setter return self __setter this method is called when the interpreter reachesfor example@extension setterwith the function it decorates as its setter argument it stores the setter method it has been given (which can now be used in the __set__(method)and returns the settersince decorators should return the function or method they decorate we have now looked at three quite different uses of descriptors descriptors are very powerful and flexible feature that can be used to do lots of underthe-hood work while appearing to be simple attributes in their client (ownerclass