When you do obj.x = y you can't be sure that the attributed of obj named x is now equal to y. Python descriptor protocol lets define how attribute assignment is handled.
class Descriptor:
def __set__(self, obj, value):
obj.test = value
class A:
x = Descriptor()
In this example, x is never assigned, but the test attribute is assigned instead:
In : a = A()
In : a.x = 42
In : a.test
Out: 42
In : a.x
Out: <__main__.Descriptor at 0x7ff7baef51d0>
In case you actually need to change the x attribute as a part of tests or advanced metaprogramming, you have to modify __dict__ directly:
In : a.__dict__['x'] = 42
In : a.x
Out: 42