Movatterモバイル変換


[0]ホーム

URL:


ContentsMenuExpandLight modeDark modeAuto light/dark, in light modeAuto light/dark, in dark modeSkip to content
mypy 1.19.1 documentation
Logo
mypy 1.19.1 documentation

First steps

Type system reference

Configuring and running mypy

Miscellaneous

Project Links

Back to top

Kinds of types

We’ve mostly restricted ourselves to built-in types until now. Thissection introduces several additional kinds of types. You are likelyto need at least some of them to type check any non-trivial programs.

Class types

Every class is also a valid type. Any instance of a subclass is alsocompatible with all superclasses – it follows that every value is compatiblewith theobject type (and incidentally also theAny type, discussedbelow). Mypy analyzes the bodies of classes to determine which methods andattributes are available in instances. This example uses subclassing:

classA:deff(self)->int:# Type of self inferred (A)return2classB(A):deff(self)->int:return3defg(self)->int:return4deffoo(a:A)->None:print(a.f())# 3a.g()# Error: "A" has no attribute "g"foo(B())# OK (B is a subclass of A)

The Any type

A value with theAny type is dynamically typed. Mypy doesn’t knowanything about the possible runtime types of such value. Anyoperations are permitted on the value, and the operations are only checkedat runtime. You can useAny as an “escape hatch” when you can’t usea more precise type for some reason.

This should not be confused with theobject type, which represents the set of all values.Unlikeobject,Any introduces type unsafety — seeAny vs. object for more.

Any is compatible with every other type, and vice versa. You can freelyassign a value of typeAny to a variable with a more precise type:

a:Any=Nones:str=''a=2# OK (assign "int" to "Any")s=a# OK (assign "Any" to "str")

Declared (and inferred) types are ignored (orerased) at runtime. They arebasically treated as comments, and thus the above code does notgenerate a runtime error, even thoughs gets anint value whenthe program is run, while the declared type ofs is actuallystr! You need to be careful withAny types, since they let youlie to mypy, and this could easily hide bugs.

If you do not define a function return value or argument types, thesedefault toAny:

defshow_heading(s)->None:print('=== '+s+' ===')# No static type checking, as s has type Anyshow_heading(1)# OK (runtime error only; mypy won't generate an error)

You should give a statically typed function an explicitNonereturn type even if it doesn’t return a value, as this lets mypy catchadditional type errors:

defwait(t:float):# Implicit Any return valueprint('Waiting...')time.sleep(t)ifwait(2)>1:# Mypy doesn't catch this error!...

If we had used an explicitNone return type, mypy would have caughtthe error:

defwait(t:float)->None:print('Waiting...')time.sleep(t)ifwait(2)>1:# Error: can't compare None and int...

TheAny type is discussed in more detail in sectionDynamically typed code.

Note

A function without any types in the signature is dynamicallytyped. The body of a dynamically typed function is not checkedstatically, and local variables have implicitAny types.This makes it easier to migrate legacy Python code to mypy, asmypy won’t complain about dynamically typed functions.

Tuple types

The typetuple[T1,...,Tn] represents a tuple with the item typesT1, …,Tn:

# Use `typing.Tuple` in Python 3.8 and earlierdeff(t:tuple[int,str])->None:t=1,'foo'# OKt='foo',1# Type check error

A tuple type of this kind has exactly a specific number of items (2 inthe above example). Tuples can also be used as immutable,varying-length sequences. You can use the typetuple[T,...] (witha literal... – it’s part of the syntax) for thispurpose. Example:

defprint_squared(t:tuple[int,...])->None:fornint:print(n,n**2)print_squared(())# OKprint_squared((1,3,5))# OKprint_squared([1,2])# Error: only a tuple is valid

Note

Usually it’s a better idea to useSequence[T] instead oftuple[T,...], asSequence is also compatible with lists and other non-tuple sequences.

Note

tuple[...] is valid as a base class in Python 3.6 and later, andalways in stub files. In earlier Python versions you can sometimes work around thislimitation by using a named tuple as a base class (see sectionNamed tuples).

Callable types (and lambdas)

You can pass around function objects and bound methods in staticallytyped code. The type of a function that accepts argumentsA1, …,Anand returnsRt isCallable[[A1,...,An],Rt]. Example:

fromcollections.abcimportCallabledeftwice(i:int,next:Callable[[int],int])->int:returnnext(next(i))defadd(i:int)->int:returni+1print(twice(3,add))# 5

Note

ImportCallable[...] fromtyping insteadofcollections.abc if you use Python 3.8 or earlier.

You can only have positional arguments, and only ones without defaultvalues, in callable types. These cover the vast majority of uses ofcallable types, but sometimes this isn’t quite enough. Mypy recognizesa special formCallable[...,T] (with a literal...) which canbe used in less typical cases. It is compatible with arbitrarycallable objects that return a type compatible withT, independentof the number, types or kinds of arguments. Mypy lets you call suchcallable values with arbitrary arguments, without any checking – inthis respect they are treated similar to a(*args:Any,**kwargs:Any) function signature. Example:

fromcollections.abcimportCallabledefarbitrary_call(f:Callable[...,int])->int:returnf('x')+f(y=2)# OKarbitrary_call(ord)# No static error, but fails at runtimearbitrary_call(open)# Error: does not return an intarbitrary_call(1)# Error: 'int' is not callable

In situations where more precise or complex types of callbacks arenecessary one can use flexiblecallback protocols.Lambdas are also supported. The lambda argument and return value typescannot be given explicitly; they are always inferred based on contextusing bidirectional type inference:

l=map(lambdax:x+1,[1,2,3])# Infer x as int and l as list[int]

If you want to give the argument or return value types explicitly, usean ordinary, perhaps nested function definition.

Callables can also be used against type objects, matching their__init__ or__new__ signature:

fromcollections.abcimportCallableclassC:def__init__(self,app:str)->None:passCallableType=Callable[[str],C]defclass_or_callable(arg:CallableType)->None:inst=arg("my_app")reveal_type(inst)# Revealed type is "C"

This is useful if you wantarg to be either aCallable returning aninstance ofC or the type ofC itself. This also works withcallback protocols.

Union types

Python functions often accept values of two or more differenttypes. You can useoverloading torepresent this, but union types are often more convenient.

UseT1|...|Tn to construct a uniontype. For example, if an argument has typeint|str, bothintegers and strings are valid argument values.

You can use anisinstance() check to narrow down a union type to amore specific type:

deff(x:int|str)->None:x+1# Error: str + int is not validifisinstance(x,int):# Here type of x is int.x+1# OKelse:# Here type of x is str.x+'a'# OKf(1)# OKf('x')# OKf(1.1)# Error

Note

Operations are valid for union types only if they are valid foreveryunion item. This is why it’s often necessary to use anisinstance()check to first narrow down a union type to a non-union type. This alsomeans that it’s recommended to avoid union types as function return types,since the caller may have to useisinstance() before doing anythinginteresting with the value.

Python 3.9 and older only partially support this syntax. Instead, you canuse the legacyUnion[T1,...,Tn] type constructor. Example:

fromtypingimportUniondeff(x:Union[int,str])->None:...

It is also possible to use the new syntax with versions of Python where itisn’t supported by the runtime with some limitations, if you usefrom__future__importannotations (seeAnnotation issues at runtime):

from__future__importannotationsdeff(x:int|str)->None:# OK on Python 3.7 and later...

Optional types and the None type

You can useT|None to define a type variant that allowsNone values,such asint|None. This is called anoptional type:

defstrlen(s:str)->int|None:ifnots:returnNone# OKreturnlen(s)defstrlen_invalid(s:str)->int:ifnots:returnNone# Error: None not compatible with intreturnlen(s)

To support Python 3.9 and earlier, you can use theOptionaltype modifier instead, such asOptional[int] (Optional[X] isthe preferred shorthand forUnion[X,None]):

fromtypingimportOptionaldefstrlen(s:str)->Optional[int]:...

Most operations will not be allowed on unguardedNone oroptional values(values with an optional type):

defmy_inc(x:int|None)->int:returnx+1# Error: Cannot add None and int

Instead, an explicitNone check is required. Mypy haspowerful type inference that lets you use regular Pythonidioms to guard againstNone values. For example, mypyrecognizesisNone checks:

defmy_inc(x:int|None)->int:ifxisNone:return0else:# The inferred type of x is just int here.returnx+1

Mypy will infer the type ofx to beint in the else block due to thecheck againstNone in the if condition.

Other supported checks for guarding against aNone value includeifxisnotNone,ifx andifnotx. Additionally, mypy understandsNone checks within logical expressions:

defconcat(x:str|None,y:str|None)->str|None:ifxisnotNoneandyisnotNone:# Both x and y are not None herereturnx+yelse:returnNone

Sometimes mypy doesn’t realize that a value is neverNone. This notablyhappens when a class instance can exist in a partially defined state,where some attribute is initialized toNone during objectconstruction, but a method assumes that the attribute is no longerNone. Mypywill complain about the possibleNone value. You can useassertxisnotNone to work around this in the method:

classResource:path:str|None=Nonedefinitialize(self,path:str)->None:self.path=pathdefread(self)->str:# We require that the object has been initialized.assertself.pathisnotNonewithopen(self.path)asf:# OKreturnf.read()r=Resource()r.initialize('/foo/bar')r.read()

When initializing a variable asNone,None is usually anempty place-holder value, and the actual value has a different type.This is why you need to annotate an attribute in cases like the classResource above:

classResource:path:str|None=None...

This also works for attributes defined within methods:

classCounter:def__init__(self)->None:self.count:int|None=None

Often it’s easier to not use any initial value for an attribute.This way you don’t need to use an optional type and can avoidassert...isnotNonechecks. No initial value is needed if you annotate an attribute in the class body:

classContainer:items:list[str]# No initial value

Mypy generally uses the first assignment to a variable toinfer the type of the variable. However, if you assign both aNonevalue and a non-None value in the same scope, mypy can usually dothe right thing without an annotation:

deff(i:int)->None:n=None# Inferred type 'int | None' because of the assignment belowifi>0:n=i...

Sometimes you may get the error “Cannot determine type of <something>”. In thiscase you should add an explicit...|None annotation.

Note

None is a type with only one value,None.None is also usedas the return type for functions that don’t return a value, i.e. functionsthat implicitly returnNone.

Note

The Python interpreter internally uses the nameNoneType forthe type ofNone, butNone is always used in typeannotations. The latter is shorter and reads better. (NoneTypeis available astypes.NoneType on Python 3.10+, but isnot exposed at all on earlier versions of Python.)

Note

The typeOptional[T]does not mean a function parameter with a default value.It simply means thatNone is a valid argument value. This isa common confusion becauseNone is a common default value for parameters,and parameters with default values are sometimes calledoptional parameters(or arguments).

Type aliases

In certain situations, type names may end up being long and painful to type,especially if they are used frequently:

deff()->list[dict[tuple[int,str],set[int]]]|tuple[str,list[str]]:...

When cases like this arise, you can define a type alias by simplyassigning the type to a variable (this is animplicit type alias):

AliasType=list[dict[tuple[int,str],set[int]]]|tuple[str,list[str]]# Now we can use AliasType in place of the full name:deff()->AliasType:...

Note

A type alias does not create a new type. It’s just a shorthand notation foranother type – it’s equivalent to the target type except forgeneric aliases.

Python 3.12 introduced thetype statement for definingexplicit type aliases.Explicit type aliases are unambiguous and can also improve readability bymaking the intent clear:

typeAliasType=list[dict[tuple[int,str],set[int]]]|tuple[str,list[str]]# Now we can use AliasType in place of the full name:deff()->AliasType:...

There can be confusion about exactly when an assignment defines an implicit type alias –for example, when the alias contains forward references, invalid types, or violates some otherrestrictions on type alias declarations. Because thedistinction between an unannotated variable and a type alias is implicit,ambiguous or incorrect type alias declarations default to defininga normal variable instead of a type alias.

Aliases defined using thetype statement have these properties, whichdistinguish them from implicit type aliases:

  • The definition may contain forward references without having to use stringliteral escaping, since it is evaluated lazily.

  • The alias can be used in type annotations, type arguments, and casts, butit can’t be used in contexts which require a class object. For example, it’snot valid as a base class and it can’t be used to construct instances.

There is also use an older syntax for defining explicit type aliases, which wasintroduced in Python 3.10 (PEP 613):

fromtypingimportTypeAlias# "from typing_extensions" in Python 3.9 and earlierAliasType:TypeAlias=list[dict[tuple[int,str],set[int]]]|tuple[str,list[str]]

Named tuples

Mypy recognizes named tuples and can type check code that defines oruses them. In this example, we can detect code trying to access amissing attribute:

Point=namedtuple('Point',['x','y'])p=Point(x=1,y=2)print(p.z)# Error: Point has no attribute 'z'

If you usenamedtuple to define your named tuple, all the itemsare assumed to haveAny types. That is, mypy doesn’t know anythingabout item types. You can useNamedTuple to also defineitem types:

fromtypingimportNamedTuplePoint=NamedTuple('Point',[('x',int),('y',int)])p=Point(x=1,y='x')# Argument has incompatible type "str"; expected "int"

Python 3.6 introduced an alternative, class-based syntax for named tuples with types:

fromtypingimportNamedTupleclassPoint(NamedTuple):x:inty:intp=Point(x=1,y='x')# Argument has incompatible type "str"; expected "int"

Note

You can use the rawNamedTuple “pseudo-class” in type annotationsif anyNamedTuple object is valid.

For example, it can be useful for deserialization:

defdeserialize_named_tuple(arg:NamedTuple)->Dict[str,Any]:returnarg._asdict()Point=namedtuple('Point',['x','y'])Person=NamedTuple('Person',[('name',str),('age',int)])deserialize_named_tuple(Point(x=1,y=2))# okdeserialize_named_tuple(Person(name='Nikita',age=18))# ok# Error: Argument 1 to "deserialize_named_tuple" has incompatible type# "Tuple[int, int]"; expected "NamedTuple"deserialize_named_tuple((1,2))

Note that this behavior is highly experimental, non-standard,and may not be supported by other type checkers and IDEs.

The type of class objects

(Freely afterPEP 484: The type of class objects.)

Sometimes you want to talk about class objects that inherit from agiven class. This can be spelled astype[C] (or, on Python 3.8 and lower,typing.Type[C]) whereC is aclass. In other words, whenC is the name of a class, usingCto annotate an argument declares that the argument is an instance ofC (or of a subclass ofC), but usingtype[C] as anargument annotation declares that the argument is a class objectderiving fromC (orC itself).

For example, assume the following classes:

classUser:# Defines fields like name, emailclassBasicUser(User):defupgrade(self):"""Upgrade to Pro"""classProUser(User):defpay(self):"""Pay bill"""

Note thatProUser doesn’t inherit fromBasicUser.

Here’s a function that creates an instance of one of these classes ifyou pass it the right class object:

defnew_user(user_class):user=user_class()# (Here we could write the user object to a database)returnuser

How would we annotate this function? Without the ability to parameterizetype, the best wecould do would be:

defnew_user(user_class:type)->User:# Same  implementation as before

This seems reasonable, except that in the following example, mypydoesn’t see that thebuyer variable has typeProUser:

buyer=new_user(ProUser)buyer.pay()# Rejected, not a method on User

However, using thetype[C] syntax and a type variable with an upper bound (seeType variables with upper bounds) we can do better (Python 3.12 syntax):

defnew_user[U:User](user_class:type[U])->U:# Same implementation as before

Here is the example using the legacy syntax (Python 3.11 and earlier):

U=TypeVar('U',bound=User)defnew_user(user_class:type[U])->U:# Same implementation as before

Now mypy will infer the correct type of the result when we callnew_user() with a specific subclass ofUser:

beginner=new_user(BasicUser)# Inferred type is BasicUserbeginner.upgrade()# OK

Note

The value corresponding totype[C] must be an actual classobject that’s a subtype ofC. Its constructor must becompatible with the constructor ofC. IfC is a typevariable, its upper bound must be a class object.

For more details abouttype[] andtyping.Type[], seePEP 484: The type ofclass objects.

Generators

A basic generator that only yields values can be succinctly annotated as having a returntype of eitherIterator[YieldType] orIterable[YieldType]. For example:

defsquares(n:int)->Iterator[int]:foriinrange(n):yieldi*i

A good rule of thumb is to annotate functions with the most specific returntype possible. However, you should also take care to avoid leaking implementationdetails into a function’s public API. In keeping with these two principles, preferIterator[YieldType] overIterable[YieldType] as the return-type annotation for agenerator function, as it lets mypy know that users are able to callnext() onthe object returned by the function. Nonetheless, bear in mind thatIterable maysometimes be the better option, if you consider it an implementation detail thatnext() can be called on the object returned by your function.

If you want your generator to accept values via thesend() method or returna value, on the other hand, you should use theGenerator[YieldType,SendType,ReturnType] generic type instead ofeitherIterator orIterable. For example:

defecho_round()->Generator[int,float,str]:sent=yield0whilesent>=0:sent=yieldround(sent)return'Done'

Note that unlike many other generics in the typing module, theSendType ofGenerator behaves contravariantly, not covariantly or invariantly.

If you do not plan on receiving or returning values, then set theSendTypeorReturnType toNone, as appropriate. For example, we could haveannotated the first example as the following:

defsquares(n:int)->Generator[int,None,None]:foriinrange(n):yieldi*i

This is slightly different from usingIterator[int] orIterable[int],since generators haveclose(),send(), andthrow() methods thatgeneric iterators and iterables don’t. If you plan to call these methods on the returnedgenerator, use theGenerator type instead ofIterator orIterable.

On this page

[8]ページ先頭

©2009-2025 Movatter.jp