Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Support Python 3.6 attribute annotations. #151
Python 3.6 allows this:
The annotation is available as
This might be an easy one for someone looking to get started contributing.
I'm having a look into this. Some brief thoughts and questions:
Actually, here's a more fundamental problem with this proposal which I think means it can't/shouldn't work as written: It's flat out lying to the type checker.
In the provided example you've declared that A.a should be an int, but it's actually an Attribute object. Thus correct code using it won't type check, and incorrect code using it will.
Ok, I'm a little upset this was closed without at least waiting on my input.
Note that type annotations have other uses than mypy. attrs does declarative classes, which is a foreign concept to core Python, so of course there will be some friction, but for example
works just fine with the PyCharm type checker. And how is it lying to the type checker? It's setting the type checker straight.
Actually, I'd have to had used
Also note this example from the official Python docs:
Lying to the type checker too?
Sure, but a number of those other uses are also type checking. e.g. pycharm. I think using them for things other than type checking is great, but using them in ways that are incompatible with type checking is problematic.
No, because there are no values assigned that are not of the claimed type (though I admit it's weird).
I think Tinche's syntax suggestion, e.g. using variable annotations /
We'll need some plumbing to make it work. Would be good for 3.6+ if
But first let's address @DRMacIver's concerns around lying to the type checker. Let's look at what
Attribute use on instances
mypy will do the intuitive thing here. Consider the following snippet:
@attr.s() class Yeah: name: str = attr.ib() age: int = attr.ib(convert=int, default=0) def main() -> None: y = Yeah('Sue', '16') print(y.name.upper()) print('Next year:', y.age + 1)
First of all look at the snippet again. It looks obvious to human readers, at least the ones familiar with attrs. They understand the
But let's get back to mypy. It type-checks the attribute usage in
But try flipping the attributes instead in
print(y.age.upper()) print('Next year:', y.name + 1)
and you'll see it complain about invalid operations, as you'd expect:
So far, so good.
Attribute use on classes
Here mypy gets it wrong. If we want to access
If we try to mistakenly access the class attribute as an instance attribute (for example by treating
Even though mypy will get the class-level access wrong, I still prefer using type annotations because:
The fundamental issue is that
The first one is the most important because it generates false positives in the common case.
I basically agree with @ambv but I'm going to share my two Croatian lipa anyway.
In order to get full mypy support we're almost certainly going to have to do extra work, like writing a mypy plugin when that's available. There's probably no chance mypy is going to be competent enough to grok our
I see the main bone of contention here is that the core premise of attrs is you write one thing in order to declare another. So this would be the proper way of writing a class:
This describes exactly what's happening while you're inside the class, defining the attributes. The only benefit this has is it might help you if you're using another function, like a wrapper for
The downsides are it's kind of misleading you, the reader. When
The proposed approach,
is, yes, basically lying to the type checker. But I would argue it's intuitively much clearer to human readers.
Also consider that the point of attrs is reducing boilerplate and making writing classes fun, and compare the two approaches:
One is, imo, more beautiful/readable than the other :)