This question probably has an answer somewhere, but I couldn't find it.
I'm using setattr to add a long list of descriptors to a class, and I have discovered that __set_name__ of the descriptor is not called when I use setattr.
It is not a big issue for me because I can just set the name of the descriptor through __init__ instead, I just want to understand why __set_name__ is not called and if it's because I'm doing something wrong.
class MyDescriptor:
def __set_name__(self, owner, name):
self._owner = owner
self._name = name
def __get__(self, instance, owner):
return self._name
class MyClass:
a = MyDescriptor()
setattr(MyClass, 'b', MyDescriptor()) # dynamically adding descriptor, __set_name__ is not called!
mc = MyClass()
print(mc.a) # prints 'a'
print(mc.b) # raises AttributeError: 'MyDescriptor' object has no attribute '_name'
__set_name__is called for each descriptor when the class is created in thetype.__new__function: it is not a "reactive protocol", so to say, to be triggered whenever a descriptor is created.The plain fix to that is to call
__set_name__manually just after you call setattr:Although it is possible to have a metaclass with a custom
__setattr__method that will do that for you.__setattr__method implementation in your classes is Pythons way of adding reactive behavior to attribute setting - its only that this time you need the behavior in a class, instead of in an instance.If you do this in a lot of places, and really would like it to be transparent it could be a thing to do:
And now, checking it on the interactive prompt: