-1

I was searching the rationale about descriptors cannot be instance variables, and found this post. In @nneonneo's answer he quoted an answer from Python mail list. I put the quote here.

The answer listed two reasons that I have doubts: for the first reason, it said

if the "M" descriptor is defined by some instances rather than by the class, then knowing that the object "reg" is an instance of Register does not tell me anything about whether "reg.M" is a valid attribute or an error.

But my question is that if "M" descriptor was defined in __init__(), how come it is defined by some instances? Every instance should have an "M" descritor attribute after initialization. Then "reg.M" should always be valid attribute.

for the second reason, the ObjectHolder example,

Instead of treating "holder.obj" as a simple data attribute, it would start invoking the descriptor protocol on accesses to "holder.obj" and ultimately redirect them to the non-existent and meaningless "holder.foo" attribute, which is certainly not what the author of the class intended.

the original question is about why descriptors cannot be instance variables, this second reason just uses existing mechanism to explain a hypothetical situation. I mean if descriptors are going to be valid as instance variables, there should be some checks and transforms coming along to make it work. I dont' think you can use the mechanism for "descriptors as class variables" to explain "descriptors as instance variables", especially the latter does not exist for now and maybe can be developed to valid in future.

Thanks,

password636
  • 981
  • 1
  • 7
  • 18

1 Answers1

2

I cannot stress this enough:

The behavior is by design. [1]

That's it. This is they way the language was implemented and why decorators work better with classes is a consequence of that. Resources you provided go into detail why decorators on classes work better, so I will no repeat myself.


Regarding your questions...

If "M" descriptor was defined in init(), how come it is defined by some instances?

It is not, you're right. Ian was presententing the point that, in general, per-instance initialisation based on some conditions may not quarantee that the "reg.M" will not raise AttributeError. This is not the case with class decorators. If you're always initializting in the __init__ then you're fine. Until, for example, someone overrides your __init__ or does del on the attribute. With class, you only need to watch the class.


Instead of treating "holder.obj" as a simple data attribute, it would start invoking the descriptor protocol on accesses to "holder.obj" and ultimately redirect them to the non-existent and meaningless "holder.foo" attribute, which is certainly not what the author of the class intended.

Ok, let's assume we have an object:

>>> a = property(lambda o: o.eggs)
>>> a
<property object at 0x7f9db318a838>

This is perfectly legal, right? Ok, what if I want to store it on an instance of some class? I would do:

>>> class Foo: pass
...
>>> foo = Foo()
>>> foo.a = a
>>> foo.a
<property object at 0x7f9db318a838>

Ok, so this works, cool!

The problem with instance decorators here is that this would not be possible if Python applied decorator protocol to a. Typing foo.a would make it try to evaluate eggs yielding AttributeError. Therefore, in order to have two behaviours possible, the decorator protocol is not invoked on the instance foo.

I hope this clears it up a bit. :)



[1] https://mail.python.org/pipermail/python-list/2012-January/618572.html
[2] https://mail.python.org/pipermail/python-list/2012-January/618570.html

Siegmeyer
  • 4,312
  • 6
  • 26
  • 43