B
Brian Allen Vanderburg II
I'm trying to better understand descriptors and I've got a few questions
still after reading some sites. Here is what I 'think', but please let
me know if any of this is wrong as I'm sure it probably is.
First when accessing an attribute on a class or instance it must be
found. For an instance, it's __dict__ is first search. If not found
the class and base class __dict__ are searched. For a class, the
__dict__ and base classes __dict__ are search.
If assigning, and the attribute is found and is not a descriptor or if
the attribute is not found, then the assignment will occur in the
__dict__ of the class or instance. If it is found and is a descriptor,
then __set__ will be call.
For reading, if the attribute is found and is a descriptor, __get__ will
be called, passing the object (if it is an instance) and class. If it
is not a descriptor, the attribute will be returned directly.
Class methods are just functions:
class C(object):
def F(self):
pass
C.__dict__['F'] # function object ...
But functions are descriptors:
C.__dict__['F'].__get__ # method wrapper ...
def f1():
pass
f1.__get__ # method wrapper ...
When a lookup is done it uses this descriptor to make a bound or unbound
method:
c=C()
C.F # unbound method object, expects explicit instance when calling the
function
c.F # bound method object provides instance implicitly when calling the
function
This is also done when adding to the classes:
C.f1 = f1
f1 # function
C.f1 # unbound method
c.f1 # bound method
To prevent this it has to be decorated so the descriptor doesn't cause
the binding:
C.f2 = staticmethod(f1)
C.f2 # functon
c.f2 # function
Here is a question, why don't instance attributes do the same thing?
c.f3 = f1
c.f3 # function, not bound method
So it is not calling the __get__ method for c.f3 After it finds c.f3 in
c.__dict__, and since it has a getter, shouldn't it call the __get__ to
return the bound method. It is good that it doesn't I know, but I just
want to know why it doesn't from an implementation view.
Brian Vanderburg II
still after reading some sites. Here is what I 'think', but please let
me know if any of this is wrong as I'm sure it probably is.
First when accessing an attribute on a class or instance it must be
found. For an instance, it's __dict__ is first search. If not found
the class and base class __dict__ are searched. For a class, the
__dict__ and base classes __dict__ are search.
If assigning, and the attribute is found and is not a descriptor or if
the attribute is not found, then the assignment will occur in the
__dict__ of the class or instance. If it is found and is a descriptor,
then __set__ will be call.
For reading, if the attribute is found and is a descriptor, __get__ will
be called, passing the object (if it is an instance) and class. If it
is not a descriptor, the attribute will be returned directly.
Class methods are just functions:
class C(object):
def F(self):
pass
C.__dict__['F'] # function object ...
But functions are descriptors:
C.__dict__['F'].__get__ # method wrapper ...
def f1():
pass
f1.__get__ # method wrapper ...
When a lookup is done it uses this descriptor to make a bound or unbound
method:
c=C()
C.F # unbound method object, expects explicit instance when calling the
function
c.F # bound method object provides instance implicitly when calling the
function
This is also done when adding to the classes:
C.f1 = f1
f1 # function
C.f1 # unbound method
c.f1 # bound method
To prevent this it has to be decorated so the descriptor doesn't cause
the binding:
C.f2 = staticmethod(f1)
C.f2 # functon
c.f2 # function
Here is a question, why don't instance attributes do the same thing?
c.f3 = f1
c.f3 # function, not bound method
So it is not calling the __get__ method for c.f3 After it finds c.f3 in
c.__dict__, and since it has a getter, shouldn't it call the __get__ to
return the bound method. It is good that it doesn't I know, but I just
want to know why it doesn't from an implementation view.
Brian Vanderburg II