Skip to content

treatment of private attributes is obscure, nearly undocumented, perhaps not ideal in all cases #171

Closed
@glyph

Description

@glyph

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 do Foo(1) and never realize that they've done something unsupported. Therefore attr.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 as self._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.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions