How to specify that an attribute must be a list of

2020-03-17 03:51发布

问题:

Using the attrs libary and Python 3.6, I thought the following would allow me to specify that x and y can only contain integers:

import attr

@attr.s
class C:
  x : List[int] = attr.ib()   # not working
  y = attr.ib(type=List[int]) # not working either

Both of the commented lines throw a NameError: name 'List' is not defined.

The reasons I expected that to work are these:

(1) The types section of the attr documentation includes the following passage: "attrs also allows you to associate a type with an attribute using either the type argument to attr.ib() or – as of Python 3.6 – using PEP 526-annotations". It then demonstrates both methods:

@attr.s
class C:
    x = attr.ib(type=int)
    y: int = attr.ib()

(2) PEP 526 states that the following syntax for type annotation is valid: primes: List[int] = [].

回答1:

The syntax is indeed valid. But the generic type annotation objects added by PEP 484 are not in the builtins namespace, but in the typing module.

So, you need to do what all of the examples in the attrs docs you linked, and PEP 484, PEP 483, PEP 526, and the typing docs do:

from typing import List

Also, note that this is just an annotation. You can still write c = C(x=[], y=[1.0]) and you won't get a TypeError. As the docs you linked say:

attrs itself doesn’t have any features that work on top of type metadata yet. However it’s useful for writing your own validators or serialization frameworks.

It's not at all clear what attrs should do with this metadata. It's a central part of the design of PEP 483/PEP 484 that type annotations are nothing more than annotations are runtime, and do not affect the types of values or what's legal to store where; they're only there to be used by static type checkers and other tools that runs separately from Python.

In particular, Mypy (the reference-standard static type checker), some linters, and some IDEs should flag this as an error. If they don't support attrib annotations yet, they're almost certainly working on it (since they're roughly equivalent to annotated attributes in 3.7/PEP 557 dataclass).