__set__ method is not called for class attribute access

Duncan Booth duncan.booth at invalid.invalid
Fri Aug 5 14:16:09 CEST 2011


Ryan <heniser at yahoo.com> 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 :-/

The descriptor protocol only works when a value is being accessed or set 
on an instance and there is no instance attribute of that name so the 
value is fetched from the underlying class.

Classes are instances too, so you may get some of what you want from:

class MyMeta(type):
	x = RevealAccess(10, 'var "x"')

class MyClass(object):
	__metaclass__ = MyMeta
	y = 5

>>> MyClass.x = 20
Updating var "x"
>>> MyClass.x
Retrieving var "x"
20

However note that if you do this you can access "x" only directly on the 
class not on an instance of the class:

>>> MyClass().x

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


-- 
Duncan Booth http://kupuguy.blogspot.com



More information about the Python-list mailing list