You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The way how attributes are collected from super classes is different comparing to how attributes and methods are searched by getattr (based on MRO for new-style classes).
Example:
@attr.sclassA(object):
x=attr.ib(10)
defxx(self):
return10@attr.sclassB(A):
y=attr.ib(20)
@attr.sclassC(A):
x=attr.ib(50)
defxx(self):
return50classD(B, C):
passd=D()
print(d.x) # prints 10print(d.xx()) # prints 50
I think it would be great to the use the same approach for collecting attributes as used for searching methods and attributes.
The difference is caused by the fact that the function _transform_attrs in attrs/_make.py considers all attributes (own+inherited stored in __attrs_attrs__) and not only own attributes of super classes:
The underlying issue is that attrs always writes all methods optimized for the current class to avoid super() calls/traversal which means we have to simulate the __mro__ ourselves when building the lists of attributes. FTR, dataclasses handle it the same way.
As such, I was able to make your test case work by ignoring inherited attributes iff D is also decorated with @attr.s because then attrs has the chance to intervene.
There's another problem too: users expect the attributes to be ordered (in __init__ parameter lists and reprs for example) in the order they are defined. E.g. if you have:
The attribute order is c, b, a, x, d (N.B. that x changed position due to overwrite).
If I ignore inherited attributes and walk the mro, the order becomes a, x, d, c, b.
I'm open to suggestions how to resolve this to make everyone happy but I banged my head against it for over an hour and didn't really come up with anything viable. :(
I guess traversing it twice would work? Once for getting the order of the names right and then again to resolve them to the correct classes? 🤔
Activity
hynek commentedon Sep 1, 2018
Hm that’s unfortunate and fixing it likely means breakage. :|
hynek commentedon Aug 19, 2019
So this is interesting.
The underlying issue is that
attrsalways writes all methods optimized for the current class to avoidsuper()calls/traversal which means we have to simulate the__mro__ourselves when building the lists of attributes. FTR, dataclasses handle it the same way.As such, I was able to make your test case work by ignoring inherited attributes iff D is also decorated with
@attr.sbecause then attrs has the chance to intervene.There's another problem too: users expect the attributes to be ordered (in
__init__parameter lists and reprs for example) in the order they are defined. E.g. if you have:The attribute order is c, b, a, x, d (N.B. that x changed position due to overwrite).
If I ignore inherited attributes and walk the mro, the order becomes a, x, d, c, b.
I'm open to suggestions how to resolve this to make everyone happy but I banged my head against it for over an hour and didn't really come up with anything viable. :(
I guess traversing it twice would work? Once for getting the order of the names right and then again to resolve them to the correct classes? 🤔
hynek commentedon Mar 30, 2020
If you don't mind, have a look at #635 whether it covers everything you'd expect.
hynek commentedon Apr 6, 2020
I have merged it now, please let me know if something is not OK.
jacobg commentedon Aug 18, 2020