Description
Some folks, presented with the attr.s
API, make the entirely reasonable inference that this:
@attr.s
class Foo:
_bar = attr.ib()
is a class you should use like this:
Foo(_bar=1)
This is further exacerbated by the fact that Foo
's repr
actually shows you exactly that string.
The only example in the docs that I can find is the code example at the bottom of the attr.s
API doc.
This behavior should be thoroughly documented and explained, and, um, maybe tweaked a little bit, since there are some issues with it. As it stands now, for example, there's no publicly-named attribute for API doc generation tools, or code-completion things, to pick up to present as the constructor argument.
If I could take a stab at the rationale for this behavior, it's something like this:
In Python, if you have a function with "private" arguments, they all have positional names, which makes them effectively public. Therefore, there is no point in trying to "hide" your constructor arguments behind
_
prefixes, since a user might happily doFoo(1)
and never realize that they've done something unsupported. Thereforeattr.s
always makes the keyword-arg names of your constructor arguments "public" by removing their underscores; the attributes themselves are of course private and can still have the_
prefix when accessed asself._something
.
Except, in Python 3, this isn't true any more, because the advent of keyword-only arguments means you can't pass the argument without actually having to type in an _
in a namespace you don't own, which means it's totally valid to have internal "don't pass me this in the constructor" state. IMHO this is great - it's a way to force public users through a class-method constructor or factory function without hiding the type itself (and all the methods on it) or resorting to any gross shenanigans to make the constructor literally private. So it turns out I really would like "private attributes" that don't show up in the constructor either! (And of course, at the metaprogramming level where Attrs itself lives, the kwarg-only behavior can be emulated on python 2.)