Possible undefined behavior on creating a method named "__dict__"
I just came across a code snippet that would define a method with the "__dict__" name - like in: class A: def __dict__(self): return () The resulting class's instances can be assigned dynamic attributes as usual, but one can never acess its actual local variables through instance.__dict__ - the method is retrieved instead. Calling "vars" will also fail on objects of this class. This behavior is weird, and I believe is actually a side-effect of implementation details on CPython. I am not sure whether it shoud just: 1 - be left as is - whoever reuses __dict__ as a method had it coming 2 - document CPythn behavior 3 - file that as a bug to disallow __dict__ override in class declaration 4 - file that as a bug to not-create class __dict__ when one is explictly created in Python code (the same that happens when one have "__slots__". I have the feeling that (1) is just good - but then, I am at least posting this e-mail here. Similar weird things go when one creates a method named "__class__", and possible other names. (I just checked that pypy3 mimics the behavior) js -><-
On Wed, Apr 11, 2018 at 08:21:01AM -0300, Joao S. O. Bueno wrote:
I just came across a code snippet that would define a method with the "__dict__" name - like in:
class A: def __dict__(self): return ()
That's a strange thing to do, but I don't think it ought to be illegal. Consenting adults and all that.
The resulting class's instances can be assigned dynamic attributes as usual, but one can never acess its actual local variables through instance.__dict__ - the method is retrieved instead.
Yes, I believe that is expected behaviour for attribute access since the descriptor protocol was added. Methods take priority over data attributes, if I recall correctly.
Calling "vars" will also fail on objects of this class.
I consider that a pseudo-bug. I can't call it an actual bug, because vars() doesn't document that it will work even when __dict__ is shadowed in this way, but I think it should. So its a bug against a future feature :-) Attribute access still works correctly even with such a shadow: py> class W: ... def __dict__(self): ... return () ... py> obj = W() py> obj.spam = 1 py> obj.spam 1 so there is still an instance dict somewhere inside the instance, and the C attribute-access machinary can access it. I think vars() should be able to do the same. (I'm not saying this in order to encourage people to shadow __dict__.)
This behavior is weird, and I believe is actually a side-effect of implementation details on CPython.
Its certain a weird thing to do, but I don't believe it is an implementation detail. Apart from the behaviour of vars(), I think the behaviour here all follows from the documented behaviour of the descriptor protocol.
I am not sure whether it shoud just: 1 - be left as is - whoever reuses __dict__ as a method had it coming 2 - document CPythn behavior 3 - file that as a bug to disallow __dict__ override in class declaration 4 - file that as a bug to not-create class __dict__ when one is explictly created in Python code (the same that happens when one have "__slots__".
I have the feeling that (1) is just good - but then, I am at least posting this e-mail here.
I agree that (1) is the best, but vars() ought to work even in the precence of a method shadowing __dict__.
Similar weird things go when one creates a method named "__class__", and possible other names.
type(instance) still works correctly when instance.__class__ is shadowed by a method. -- Steve
On Wed, 11 Apr 2018 at 05:09 Steven D'Aprano
On Wed, Apr 11, 2018 at 08:21:01AM -0300, Joao S. O. Bueno wrote:
I just came across a code snippet that would define a method with the "__dict__" name - like in:
class A: def __dict__(self): return ()
That's a strange thing to do, but I don't think it ought to be illegal. Consenting adults and all that.
The resulting class's instances can be assigned dynamic attributes as usual, but one can never acess its actual local variables through instance.__dict__ - the method is retrieved instead.
Yes, I believe that is expected behaviour for attribute access since the descriptor protocol was added. Methods take priority over data attributes, if I recall correctly.
Yep, they do.
Calling "vars" will also fail on objects of this class.
I consider that a pseudo-bug. I can't call it an actual bug, because vars() doesn't document that it will work even when __dict__ is shadowed in this way, but I think it should. So its a bug against a future feature :-)
Attribute access still works correctly even with such a shadow:
py> class W: ... def __dict__(self): ... return () ... py> obj = W() py> obj.spam = 1 py> obj.spam 1
so there is still an instance dict somewhere inside the instance, and the C attribute-access machinary can access it. I think vars() should be able to do the same.
(I'm not saying this in order to encourage people to shadow __dict__.)
This behavior is weird, and I believe is actually a side-effect of implementation details on CPython.
Its certain a weird thing to do, but I don't believe it is an implementation detail. Apart from the behaviour of vars(), I think the behaviour here all follows from the documented behaviour of the descriptor protocol.
I am not sure whether it should just: 1 - be left as is - whoever reuses __dict__ as a method had it coming 2 - document CPython behavior 3 - file that as a bug to disallow __dict__ override in class declaration 4 - file that as a bug to not-create class __dict__ when one is explictly created in Python code (the same that happens when one have "__slots__".
I have the feeling that (1) is just good - but then, I am at least posting this e-mail here.
I agree that (1) is the best, but vars() ought to work even in the presence of a method shadowing __dict__.
I say option 1 as well. -Brett
Similar weird things go when one creates a method named "__class__", and possible other names.
type(instance) still works correctly when instance.__class__ is shadowed by a method.
-- Steve _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/brett%40python.org
On Wed, Apr 11, 2018 at 5:08 AM, Steven D'Aprano
On Wed, Apr 11, 2018 at 08:21:01AM -0300, Joao S. O. Bueno wrote:
I just came across a code snippet that would define a method with the "__dict__" name - like in:
class A: def __dict__(self): return ()
That's a strange thing to do, but I don't think it ought to be illegal. Consenting adults and all that.
Python's guarantee in this case goes no further than that it promises not to crash in C code. There's a rule in the language reference that says that all __dunder__ names are reserved for the implementation and they should only be used according to the documentation. So, indeed, it's not illegal, but you are not guaranteed that anything works, either. -- --Guido van Rossum (python.org/~guido)
participants (4)
-
Brett Cannon
-
Guido van Rossum
-
Joao S. O. Bueno
-
Steven D'Aprano