Neat. I often use namedtuple but as mentioned in the article, it has weird/surprising behaviour. For example its __equals__ has caught me out in the past:
scala> case class Foo(x: Int)
scala> case class Bar(y: Int)
scala> Foo(x=7) == Bar(y=7)
<console>:16: warning: comparing case class values of types Foo and Bar using `==' will always yield false
Foo(x=7) == Bar(y=7)
^
res0: Boolean = false
I’m glad to see that attr has the latter behaviour:
>>> @attr.s
... class Foo(object): x = attr.ib()
>>> @attr.s
... class Bar(object): y = attr.ib()
>>> Foo(x=7) == Bar(y=7)
False
I’m a long-time Pythonista, but the approach of macropy’s @case class decorator surprised me. When I stared at the example for a moment, I thought, “This can’t possibly be right – an unknown global in the class bases list?”
But then I realized that the class decorator was sugar on top of an actual Python AST source transformation at import-time, clarified by reading macropy’s README. Some deep magic there!
I’m not sure if I love the idea of “re-using” Python’s syntax tree in this way. But, then again, even namedtuple is a bit of magic in this vein. It actually constructs the namedtuple implementation as a string template and calls exec on the result.
I enjoyed Glyph’s post on the attrs module, though I found the naming of its functions a bit too “cute” for my taste. I spent awhile puzzling what s() and ib() could possibly mean, before realizing it was playing on the module name of attr for function calls that “look like” attrs and attrib, with the dots stripped.
Anyway, all approaches – the @case decorator, @attr.s, and namedtuple(...) – seem to indicate that Python might benefit from a way to make lightweight classes with “correct” type/equality semantics and simple initializers that was a bit more blessed by the language. Perhaps something someone can suggest for future Python 3.x versions. Personally, I just point people toward namedtuple for this use case, despite its warts, because it’s part of the stdlib and widely-used.
Neat. I often use
namedtuplebut as mentioned in the article, it has weird/surprising behaviour. For example its__equals__has caught me out in the past:whereas in some other languages:
I’m glad to see that attr has the latter behaviour:
To get this behaviour you could also use https://github.com/lihaoyi/macropy#case-classes :
I’m a long-time Pythonista, but the approach of macropy’s
@caseclass decorator surprised me. When I stared at the example for a moment, I thought, “This can’t possibly be right – an unknown global in the classbaseslist?”But then I realized that the class decorator was sugar on top of an actual Python AST source transformation at import-time, clarified by reading macropy’s README. Some deep magic there!
I’m not sure if I love the idea of “re-using” Python’s syntax tree in this way. But, then again, even
namedtupleis a bit of magic in this vein. It actually constructs the namedtuple implementation as a string template and callsexecon the result.I enjoyed Glyph’s post on the
attrsmodule, though I found the naming of its functions a bit too “cute” for my taste. I spent awhile puzzling whats()andib()could possibly mean, before realizing it was playing on the module name ofattrfor function calls that “look like”attrsandattrib, with the dots stripped.Anyway, all approaches – the
@casedecorator,@attr.s, andnamedtuple(...)– seem to indicate that Python might benefit from a way to make lightweight classes with “correct” type/equality semantics and simple initializers that was a bit more blessed by the language. Perhaps something someone can suggest for future Python 3.x versions. Personally, I just point people toward namedtuple for this use case, despite its warts, because it’s part of the stdlib and widely-used.Oh I hadn’t understood the naming until you pointed it out. I’m much less excited by this module now. Too clever :-(
From the
attrsdocs:Yeah, looks nice, but it really needed to be in the standard library.