Python Descriptor Methods
What does these attributes do exactly: __get/set/delattr__
?
This is a hard one to start with, and fairly advanced - most Python programmers don't need to know this, they just memorize how objects (mostly methods and method decorators) that use this work.
They are special methods that make an object a "descriptor". If that object is looked up through another object, they get invoked. They are how property
, classmethod
, and staticmethod
work. The are also how normal functions can become bound methods.
For example:
>>> class Foo:
... def __init__(self, bar):
... self.bar = bar
... @property
... def baz(self):
... return bar * 2
>>> Foo.__init__.__get__
<method-wrapper '__get__' of function object at 0x7f1c1d23b158>
The __get__
is invoked when you do Foo.__init__
(which is invoked by Foo()
). It binds the instance to the first argument (we usually call it self
) to the method on the dotted lookup.
>>> Foo.baz.__set__
<method-wrapper '__set__' of property object at 0x7f1c1d225e58>
That __set__
method is what is invoked when we try to assign to the baz
name on the dotted lookup on the left hand side of the assignment (since we didn't define a setter, baz is read-only) and that method raises the following error:
>>> f = Foo('bar')
>>> f.baz = 'boink'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
I wrote a canonical and very thorough answer on this subject on StackOverflow here.
Assignment versus __setattr__
(versus setattr
)
Why not use just Myclass.NewAttr = value
instead of __setattr__
?
Yes, you should do that. __setattr__
should only be used when implementing special behavior on an object.
There is also a builtin function called setattr
- it works if you need to programmatically determine the name you are assigning to, and can't just use a static name in your code.
__dict__
versus dir
Why does Python use __dict__
? It keeps the attributes in the end of dir()
anyway.
Actually, the attributes (data members) are stored in the dictionary - dir()
just looks their names up there.