__set__ method is not called for class attribute access

Peter Otten __peter__ at web.de
Fri Aug 5 08:10:52 EDT 2011


Ryan wrote:

> In the context of descriptors, the __set__ method is not called for
> class attribute access. __set__ is only
> called to set the attribute on an instance instance of the owner class
> to a new value, value. WHY? Is there some other mechanism for
> accomplishing this outcome. This subtle difference from __get__cost me
> some time to track down. Might think about pointing that out the
> documentation.
> 
> 
> class RevealAccess(object):
>     """A data descriptor that sets and returns values
>        normally and prints a message logging their access.
>     """
> 
>     def __init__(self, initval=None, name='var'):
>         self.val = initval
>         self.name = name
> 
>     def __get__(self, obj, objtype):
>         print 'Retrieving', self.name
>         return self.val
> 
>     def __set__(self, obj, val):
>         print 'Updating' , self.name
>         self.val = val
> 
> class MyClass(object):
>     x = RevealAccess(10, 'var "x"')
>     y = 5
> 
> print MyClass.x
> MyClass.x = 20
> print MyClass.x
> MyClass.x = 30
> print MyClass.x
> 
> Retrieving var "x"
> 10
> 20
> 30
> 
> I am at a lost on how to intercept class attribute sets. Can anyone
> help :-/

A class is just an instance of its metaclass, so you could move the 
descriptor into the metaclass to see the expected behaviour in the class:

>>> class A:
...     class __metaclass__(type):
...             x = RevealAccess(10, 'var "x"')
...
>>> A.x = 42
Updating var "x"
>>> A.x
Retrieving var "x"
42

However:

>>> A().x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'x'

So you'd need two descriptors if you want to intercept variable access on 
both the instance and class level.





More information about the Python-list mailing list