1. 23
  1.  

  2. 4

    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:

    >>> Foo = namedtuple('Foo', 'x')
    >>> Bar = namedtuple('Bar', 'y')
    >>> Foo(x=7) == Bar(y=7)
    True
    

    whereas in some other languages:

    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
    

    To get this behaviour you could also use https://github.com/lihaoyi/macropy#case-classes :

    >>> @case
    ... class Foo(x): pass
    >>> @case
    ... class Bar(y): pass
    >>> Foo(x=7) == Bar(y=7)
    False
    
    1. 2

      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.

      1. 1

        Oh I hadn’t understood the naming until you pointed it out. I’m much less excited by this module now. Too clever :-(

        1. 3

          From the attrs docs:

          (If you don’t like the playful attr.s and attr.ib, you can also use their no-nonsense aliases attr.attributes and attr.attr).

    2. 1

      Yeah, looks nice, but it really needed to be in the standard library.