键入-支持类型提示

3.5 版中的新Function。

源代码: Lib/typing.py

Note

Python 运行时不强制执行函数和变量类型 Comments。它们可以被第三方工具(例如类型检查器,IDE,短毛绒等)使用。


此模块为 PEP 484 PEP 526 PEP 544 PEP 586 PEP 589 PEP 591指定的类型提示提供运行时支持。最基本的支持包括类型AnyUnionTupleCallableTypeVarGeneric。有关完整规范,请参见 PEP 484。有关类型提示的简化介绍,请参见 PEP 483

下面的函数接受并返回一个字符串,其 Comments 如下:

def greeting(name: str) -> str:
    return 'Hello ' + name

在函数greeting中,参数name的类型应为str,返回类型为str。子类型被接受为参数。

Type aliases

pass将类型分配给别名来定义类型别名。在此示例中,VectorList[float]将被视为可互换的同义词:

from typing import List
Vector = List[float]

def scale(scalar: float, vector: Vector) -> Vector:
    return [scalar * num for num in vector]

# typechecks; a list of floats qualifies as a Vector.
new_vector = scale(2.0, [1.0, -4.2, 5.4])

类型别名对于简化复杂的类型签名很有用。例如:

from typing import Dict, Tuple, Sequence

ConnectionOptions = Dict[str, str]
Address = Tuple[str, int]
Server = Tuple[Address, ConnectionOptions]

def broadcast_message(message: str, servers: Sequence[Server]) -> None:
    ...

# The static type checker will treat the previous type signature as
# being exactly equivalent to this one.
def broadcast_message(
        message: str,
        servers: Sequence[Tuple[Tuple[str, int], Dict[str, str]]]) -> None:
    ...

请注意,None作为类型提示是一种特殊情况,并由type(None)代替。

NewType

使用NewType()辅助函数创建不同的类型:

from typing import NewType

UserId = NewType('UserId', int)
some_id = UserId(524313)

静态类型检查器会将新类型视为原始类型的子类。这有助于帮助捕获逻辑错误:

def get_user_name(user_id: UserId) -> str:
    ...

# typechecks
user_a = get_user_name(UserId(42351))

# does not typecheck; an int is not a UserId
user_b = get_user_name(-1)

您仍然可以对UserId类型的变量执行所有int操作,但结果始终为int类型。这使您可以在可能需要int的地方传递UserId,但可以防止您以无效的方式意外创建UserId

# 'output' is of type 'int', not 'UserId'
output = UserId(23413) + UserId(54341)

请注意,这些检查仅由静态类型检查器强制执行。在运行时,语句Derived = NewType('Derived', Base)将使Derived一个函数,该函数立即返回您传递给它的任何参数。这意味着表达式Derived(some_value)不会创建新类或引入任何常规函数调用之外的开销。

更准确地说,表达式some_value is Derived(some_value)在运行时始终为 true。

这也意味着不可能创建Derived的子类型,因为它是运行时的标识函数,而不是实际的类型:

from typing import NewType

UserId = NewType('UserId', int)

# Fails at runtime and does not typecheck
class AdminUserId(UserId): pass

但是,可以基于“派生的” NewType创建一个NewType()

from typing import NewType

UserId = NewType('UserId', int)

ProUserId = NewType('ProUserId', UserId)

并按预期检查ProUserId的类型。

有关更多详细信息,请参见 PEP 484

Note

回想一下,使用类型别名语句两种类型彼此“等效”。在所有情况下,执行Alias = Original都会使静态类型检查器将Alias等同于Original。当您要简化复杂的类型签名时,这很有用。

相反,NewType语句一种类型为另一种的子类型。进行Derived = NewType('Derived', Original)会使静态类型检查器将Derived视为Original子类,这意味着Original类型的值不能在预期值为Derived类型的地方使用。当您希望以最小的运行时成本来防止逻辑错误时,这很有用。

版本 3.5.2 中的新Function。

Callable

期望使用特定签名的回调函数的框架可以使用Callable[[Arg1Type, Arg2Type], ReturnType]进行类型提示。

For example:

from typing import Callable

def feeder(get_next_item: Callable[[], str]) -> None:
    # Body

def async_query(on_success: Callable[[int], None],
                on_error: Callable[[int, Exception], None]) -> None:
    # Body

pass用 Literals Ellipsis号代替类型提示中的参数列表Callable[..., ReturnType],可以语句可调用的返回类型而无需指定调用签名。

Generics

由于无法以通用方式静态推断有关保存在容器中的对象的类型信息,因此对抽象 Base Class 进行了扩展以支持预订,以表示容器元素的预期类型。

from typing import Mapping, Sequence

def notify_by_email(employees: Sequence[Employee],
                    overrides: Mapping[str, str]) -> None: ...

泛型可以pass使用一个新的工厂来进行参数化,该工厂可以键入TypeVar

from typing import Sequence, TypeVar

T = TypeVar('T')      # Declare type variable

def first(l: Sequence[T]) -> T:   # Generic function
    return l[0]

用户定义的通用类型

用户定义的类可以定义为通用类。

from typing import TypeVar, Generic
from logging import Logger

T = TypeVar('T')

class LoggedVar(Generic[T]):
    def __init__(self, value: T, name: str, logger: Logger) -> None:
        self.name = name
        self.logger = logger
        self.value = value

    def set(self, new: T) -> None:
        self.log('Set ' + repr(self.value))
        self.value = new

    def get(self) -> T:
        self.log('Get ' + repr(self.value))
        return self.value

    def log(self, message: str) -> None:
        self.logger.info('%s: %s', self.name, message)

Generic[T]作为 Base Class 定义了LoggedVar类采用单个类型参数T。这也使T作为类体内的类型有效。

GenericBase Class 定义class_getitem(),因此LoggedVar[t]作为类型有效:

from typing import Iterable

def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:
    for var in vars:
        var.set(0)

泛型类型可以具有任意数量的类型变量,并且类型变量可能受到约束:

from typing import TypeVar, Generic
...

T = TypeVar('T')
S = TypeVar('S', int, str)

class StrangePair(Generic[T, S]):
    ...

Generic的每个类型变量参数都必须是不同的。因此,这是无效的:

from typing import TypeVar, Generic
...

T = TypeVar('T')

class Pair(Generic[T, T]):   # INVALID
    ...

您可以对Generic使用多重继承:

from typing import TypeVar, Generic, Sized

T = TypeVar('T')

class LinkedList(Sized, Generic[T]):
    ...

从泛型类继承时,可以修复某些类型变量:

from typing import TypeVar, Mapping

T = TypeVar('T')

class MyDict(Mapping[str, T]):
    ...

在这种情况下,MyDict具有单个参数T

在不指定类型参数的情况下使用泛型类,则假定每个位置为Any。在以下示例中,MyIterable不是通用的,但隐式继承自Iterable[Any]

from typing import Iterable

class MyIterable(Iterable): # Same as Iterable[Any]

还支持用户定义的通用类型别名。例子:

from typing import TypeVar, Iterable, Tuple, Union
S = TypeVar('S')
Response = Union[Iterable[S], int]

# Return type here is same as Union[Iterable[str], int]
def response(query: str) -> Response[str]:
    ...

T = TypeVar('T', int, float, complex)
Vec = Iterable[Tuple[T, T]]

def inproduct(v: Vec[T]) -> T: # Same as Iterable[Tuple[T, T]]
    return sum(x*y for x, y in v)

在版本 3.7 中更改:Generic不再具有自定义元类。

用户定义的泛型类可以将 ABC 作为 Base Class 而不会出现元类冲突。不支持通用元类。参数化泛型的结果将被缓存,并且键入模块中的大多数类型都是可哈希化的,并且具有相等性。

任何类型

特殊类型是Any。静态类型检查器会将每种类型都视为与AnyAny兼容,从而认为每种类型都兼容。

这意味着可以对Any类型的值执行任何操作或方法调用,并将其分配给任何变量:

from typing import Any

a = None    # type: Any
a = []      # OK
a = 2       # OK

s = ''      # type: str
s = a       # OK

def foo(item: Any) -> int:
    # Typechecks; 'item' could be any type,
    # and that type might have a 'bar' method
    item.bar()
    ...

请注意,将类型Any的值分配给更精确的类型时,不会执行类型检查。例如,即使将s语句为str类型并在运行时收到int值,将a分配给s时,静态类型检查器也不会报告错误!

此外,所有没有返回类型或参数类型的函数都将默认使用Any

def legacy_parser(text):
    ...
    return data

# A static type checker will treat the above
# as having the same signature as:
def legacy_parser(text: Any) -> Any:
    ...
    return data

当您需要混合使用动态和静态类型的代码时,此行为允许Any用作“逃生 shade”。

Any的行为与object的行为进行对比。与Any相似,每种类型都是object的子类型。但是,与Any不同的是,情况并非如此:object不是所有其他类型的子类型。

这意味着,当值的类型为object时,类型检查器将拒绝对其执行的几乎所有操作,并将其分配给更专门类型的变量(或将其用作返回值)是类型错误。例如:

def hash_a(item: object) -> int:
    # Fails; an object does not have a 'magic' method.
    item.magic()
    ...

def hash_b(item: Any) -> int:
    # Typechecks
    item.magic()
    ...

# Typechecks, since ints and strs are subclasses of object
hash_a(42)
hash_a("foo")

# Typechecks, since Any is compatible with all types
hash_b(42)
hash_b("foo")

使用object以类型安全的方式指示值可以是任何类型。使用Any指示值是动态键入的。

标称与结构子类型

最初 PEP 484使用* nominal subtyping *定义了 Python 静态类型系统。这意味着,当且仅当AB的子类时,才允许A类。

以前,此要求还适用于抽象 Base Class,例如Iterable。这种方法的问题在于必须显式地标记一个类以支持它们,这是非 Python 的,并且不同于惯用的动态类型化 Python 代码通常会执行的操作。例如,这符合 PEP 484

from typing import Sized, Iterable, Iterator

class Bucket(Sized, Iterable[int]):
    ...
    def __len__(self) -> int: ...
    def __iter__(self) -> Iterator[int]: ...

PEP 544pass允许用户编写上述代码而无需在类定义中使用显式 Base Class 来解决此问题,并允许Bucket被静态类型检查器隐式视为SizedIterable[int]的子类型。这称为结构子类型(或静态鸭子类型):

from typing import Iterator, Iterable

class Bucket:  # Note: no base classes
    ...
    def __len__(self) -> int: ...
    def __iter__(self) -> Iterator[int]: ...

def collect(items: Iterable[int]) -> int: ...
result = collect(Bucket())  # Passes type check

此外,pass将特殊类Protocol子类化,用户可以定义新的自定义协议以充分享受结构性子类型化(请参见下面的示例)。

类,函数和装饰器

该模块定义了以下类,函数和装饰器:

Usage:

T = TypeVar('T')  # Can be anything
A = TypeVar('A', str, bytes)  # Must be str or bytes

类型变量的存在主要是为了使静态类型检查器受益。它们用作通用类型以及通用函数定义的参数。有关泛型类型的更多信息,请参见类 Generic。通用函数的工作方式如下:

def repeat(x: T, n: int) -> Sequence[T]:
    """Return a list containing n references to x."""
    return [x]*n

def longest(x: A, y: A) -> A:
    """Return the longest of two strings."""
    return x if len(x) >= len(y) else y

后一个示例的签名实质上是(str, str) -> str(bytes, bytes) -> bytes的重载。还要注意,如果参数是str的某些子类的实例,则返回类型仍然是str

在运行时,isinstance(x, T)将提高TypeError。通常,isinstance()issubclass()不应与类型一起使用。

pass传递covariant=Truecontravariant=True可以将类型变量标记为协变或逆变。有关更多详细信息,请参见 PEP 484。默认情况下,类型变量是不变的。或者,类型变量可以使用bound=<type>指定上限。这意味着(用显式或隐式)替换类型变量的实际类型必须是边界类型的子类,请参见 PEP 484

通常pass从具有一个或多个类型变量的此类实例化实例中继承来语句泛型类型。例如,通用 Map 类型可以定义为:

class Mapping(Generic[KT, VT]):
    def __getitem__(self, key: KT) -> VT:
        ...
        # Etc.

然后可以按如下方式使用此类:

X = TypeVar('X')
Y = TypeVar('Y')

def lookup_name(mapping: Mapping[X, Y], key: X, default: Y) -> Y:
    try:
        return mapping[key]
    except KeyError:
        return default
class Proto(Protocol):
    def meth(self) -> int:
        ...

这些类主要与识别结构子类型(静态鸭子类型)的静态类型检查器一起使用,例如:

class C:
    def meth(self) -> int:
        return 0

def func(x: Proto) -> int:
    return x.meth()

func(C())  # Passes static type check

有关详情,请参见 PEP 544。用runtime_checkable()装饰的协议类(稍后描述)充当头脑简单的运行时协议,该协议仅检查给定属性的存在,而忽略它们的类型签名。

协议类可以是通用的,例如:

class GenProto(Protocol[T]):
    def meth(self) -> T:
        ...

3.8 版的新Function。

a = 3         # Has type 'int'
b = int       # Has type 'Type[int]'
c = type(a)   # Also has type 'Type[int]'

请注意,Type[C]是协变的:

class User: ...
class BasicUser(User): ...
class ProUser(User): ...
class TeamUser(User): ...

# Accepts User, BasicUser, ProUser, TeamUser, ...
def make_new_user(user_class: Type[User]) -> User:
    # ...
    return user_class()

Type[C]是协变的事实意味着C的所有子类都应实现与C相同的构造函数签名和类方法签名。类型检查器应标记对此行为的违反,但也应允许子类中的构造函数调用与指示的 Base Class 中的构造函数调用匹配。在将来的 PEP 484修订版中,可能需要更改类型检查器的方式才能进行处理。

Type的唯一合法参数是类Anytype variables和任何这些类型的联合。例如:

def new_non_team_user(user_class: Type[Union[BaseUser, ProUser]]): ...

Type[Any]等效于Type,而Type等效于type,后者是 Python 元类层次结构的根。

版本 3.5.2 中的新Function。

3.8 版的新Function。

3.6.0 版中的新Function。

def get_position_in_index(word_list: Mapping[str, int], word: str) -> int:
    return word_list[word]

此类型表示字节序列的类型bytesbytearraymemoryview

作为此类型的简写,bytes可用于 Comments 上述任何类型的参数。

3.5.4 版中的新Function。

版本 3.6.1 中的新Function。

此类型可以按如下方式使用:

T = TypeVar('T', int, float)

def vec2(x: T, y: T) -> List[T]:
    return [x, y]

def keep_positives(vector: Sequence[T]) -> List[T]:
    return [item for item in vector if item > 0]

版本 3.5.2 中的新Function。

from typing import List, Coroutine
c = None # type: Coroutine[List[str], str, int]
...
x = c.send('hi') # type: List[str]
async def bar() -> None:
    x = await c # type: int

版本 3.5.3 中的新Function。

版本 3.5.2 中的新Function。

版本 3.5.2 中的新Function。

3.5.4 版中的新Function。

3.6.0 版中的新Function。

3.5.4 版中的新Function。

版本 3.6.2 中的新Function。

此类型可以如下使用:

def count_words(text: str) -> Dict[str, int]:
    ...

版本 3.5.2 中的新Function。

3.7.2 版中的新Function。

3.5.4 版中的新Function。

版本 3.6.1 中的新Function。

3.5.4 版中的新Function。

版本 3.6.1 中的新Function。

def echo_round() -> Generator[int, float, str]:
    sent = yield 0
    while sent >= 0:
        sent = yield round(sent)
    return 'Done'

请注意,与类型模块中的许多其他泛型不同,GeneratorSendType的行为是相反的,而不是协变的或不变的。

如果您的生成器仅产生值,请将SendTypeReturnType设置为None

def infinite_stream(start: int) -> Generator[int, None, None]:
    while True:
        yield start
        start += 1

或者,将生成器 Comments 为返回类型为Iterable[YieldType]Iterator[YieldType]

def infinite_stream(start: int) -> Iterator[int]:
    while True:
        yield start
        start += 1
async def echo_round() -> AsyncGenerator[int, float]:
    sent = yield 0
    while sent >= 0.0:
        rounded = await round(sent)
        sent = yield rounded

与普通生成器不同,异步生成器无法返回值,因此没有ReturnType类型参数。与Generator一样,SendType的行为相反。

如果您的生成器仅产生值,请将SendType设置为None

async def infinite_stream(start: int) -> AsyncGenerator[int, None]:
    while True:
        yield start
        start = await increment(start)

或者,将生成器 Comments 为返回类型为AsyncIterable[YieldType]AsyncIterator[YieldType]

async def infinite_stream(start: int) -> AsyncIterator[int]:
    while True:
        yield start
        start = await increment(start)

版本 3.6.1 中的新Function。

使用Text表示值必须包含与 Python 2 和 Python 3 兼容的 unicode 字符串:

def add_unicode_checkmark(text: Text) -> Text:
    return text + u' \u2713'

版本 3.5.2 中的新Function。

Usage:

class Employee(NamedTuple):
    name: str
    id: int

这等效于:

Employee = collections.namedtuple('Employee', ['name', 'id'])

要为字段提供默认值,您可以在类主体中为其指定:

class Employee(NamedTuple):
    name: str
    id: int = 3

employee = Employee('Guido')
assert employee.id == 3

具有默认值的字段必须位于没有默认值的任何字段之后。

结果类具有一个额外的属性__annotations__,该属性给出将字段名称 Map 到字段类型的字典。 (字段名称在_fields属性中,默认值在_field_defaults属性中,这两者都是 namedtuple API 的一部分.)

NamedTuple子类还可以具有文档字符串和方法:

class Employee(NamedTuple):
    """Represents an employee."""
    name: str
    id: int = 3

    def __repr__(self) -> str:
        return f'<Employee {self.name}, id={self.id}>'

Backward-compatible usage:

Employee = NamedTuple('Employee', [('name', str), ('id', int)])

在版本 3.6 中进行了更改:添加了对 PEP 526变量 Comments 语法的支持。

在版本 3.6.1 中进行了更改:添加了对默认值,方法和文档字符串的支持。

从 3.8 版开始不推荐使用,将在 3.9 版中删除:不推荐使用_field_types属性,而推荐使用具有相同信息的更标准的__annotations__属性。

在 3.8 版中进行了更改:_field_types__annotations__属性现在是常规词典,而不是OrderedDict的实例。

TypedDict创建一个字典类型,该字典类型期望其所有实例都具有一组特定的键,其中每个键都与一个一致类型的值相关联。在运行时不会检查此期望,而是仅由类型检查器强制执行。用法:

class Point2D(TypedDict):
    x: int
    y: int
    label: str

a: Point2D = {'x': 1, 'y': 2, 'label': 'good'}  # OK
b: Point2D = {'z': 3, 'label': 'bad'}           # Fails type check

assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')

可以passPoint2D.__annotations__Point2D.__total__访问用于自省的类型信息。要允许将此Function与不支持 PEP 526的 python 旧版本一起使用,TypedDict支持两种其他等效的语法形式:

Point2D = TypedDict('Point2D', x=int, y=int, label=str)
Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})

默认情况下,所有键都必须存在于 TypedDict 中。pass指定总计可以覆盖此设置。用法:

class point2D(TypedDict, total=False):
    x: int
    y: int

这意味着 point2D TypedDict 可以Ellipsis任何键。类型检查器仅应支持 LiteralsFalse 或 True 作为 total 参数的值。默认是 True,它使在类主体中定义的所有项目都是必需的。

有关使用TypedDict的更多示例和详细规则,请参见 PEP 589

3.8 版的新Function。

UserId = NewType('UserId', int)
first_user = UserId(1)

版本 3.5.2 中的新Function。

这将返回不变的值。对于类型检查器,这表明返回值具有指定的类型,但是在运行时我们有意不进行任何检查(我们希望此检查速度尽可能快)。

这通常与obj.__annotations__相同。此外,pass在globalslocals命名空间中评估它们来处理编码为字符串 Literals 的前向引用。如有必要,如果设置的默认值等于None,则为函数和方法 Comments 添加Optional[t]。对于C类,返回以相反的 Sequences 合并所有__annotations__C.__mro__构成的字典。

对于形式为X[Y, Z, ...]的键入对象,这些函数返回X(Y, Z, ...)。如果X是内置类或collections类的通用别名,则将其标准化为原始类。对于不受支持的对象,分别返回None()。例子:

assert get_origin(Dict[str, int]) is dict
assert get_args(Dict[int, str]) == (int, str)

assert get_origin(Union[int, str]) is Union
assert get_args(Union[int, str]) == (int, str)

3.8 版的新Function。

@overload
def process(response: None) -> None:
    ...
@overload
def process(response: int) -> Tuple[int, str]:
    ...
@overload
def process(response: bytes) -> str:
    ...
def process(response):
    <actual implementation>

有关详细信息以及与其他键入语义的比较,请参见 PEP 484

class Base:
    @final
    def done(self) -> None:
        ...
class Sub(Base):
    def done(self) -> None:  # Error reported by type checker
          ...

@final
class Leaf:
    ...
class Other(Leaf):  # Error reported by type checker
    ...

这些属性没有运行时检查。有关更多详细信息,请参见 PEP 591

3.8 版的新Function。

这可用作类或函数decorator。对于一个类,它递归地应用于该类中定义的所有方法(但不适用于其超类或子类中定义的方法)。

这会使Function变位。

这会将修饰符包装在no_type_check()中,将修饰的函数包装在装饰器中。

该装饰器本身在运行时不可用。如果实现返回私有类的实例,则主要用于标记类型存根文件中定义的类:

@type_check_only
class Response:  # private or not available at runtime
    code: int
    def get_header(self, name: str) -> str: ...

def fetch_response() -> Response: ...

请注意,不建议返回私有类的实例。通常最好公开此类类。

这样的协议可以与isinstance()issubclass()一起使用。当将其应用于非协议类时,它将引发TypeError。这允许进行简单的结构检查,与collections.abc中的“一招小马”(如Iterable)非常相似。例如:

@runtime_checkable
class Closable(Protocol):
    def close(self): ...

assert isinstance(open('/some/file'), Closable)

警告: 这只会检查所需方法的存在,而不检查其类型签名!

3.8 版的新Function。

from typing import NoReturn

def stop() -> NoReturn:
    raise RuntimeError('no way')

3.5.4 版中的新Function。

版本 3.6.2 中的新Function。

要定义并集,请使用例如Union[int, str]。细节:

Union[Union[int, str], float] == Union[int, str, float]
Union[int] == int  # The constructor actually returns int
Union[int, str, int] == Union[int, str]
Union[int, str] == Union[str, int]

在版本 3.7 中进行了更改:在运行时不要从联合中删除显式子类。

Optional[X]等效于Union[X, None]

请注意,这与可选参数的概念不同,后者是默认参数。具有默认值的可选参数仅在其类型 Comments 中不需要Optional限定符,因为它是可选参数。例如:

def foo(arg: int = 0) -> None:
    ...

另一方面,如果允许使用显式值None,则无论参数是否可选,都可以使用Optional。例如:

def foo(arg: Optional[int] = None) -> None:
    ...

示例:Tuple[T1, T2]是对应于类型变量 T1 和 T2 的两个元素的 Tuples。 Tuple[int, float, str]是一个整数,一个浮点数和一个字符串的 Tuples。

要指定同构类型的可变长度 Tuples,请使用 Literals Ellipsis号,例如Tuple[int, ...]。普通的Tuple等效于Tuple[Any, ...],然后等效于tuple

订阅语法必须始终与两个值一起使用:参数列表和返回类型。参数列表必须是类型列表或Ellipsis号。返回类型必须是单个类型。

没有语法指示可选参数或关键字参数。这种函数类型很少用作回调类型。 Callable[..., ReturnType](大写Ellipsis号)可用于使用任何数量的参数并返回ReturnType来键入提示可调用的提示。普通的Callable等效于Callable[..., Any],然后等效于collections.abc.Callable

def validate_simple(data: Any) -> Literal[True]:  # always returns True
    ...

MODE = Literal['r', 'rb', 'w', 'wb']
def open_helper(file: str, mode: MODE) -> str:
    ...

open_helper('/some/path', 'r')  # Passes type check
open_helper('/other/path', 'typo')  # Error in type checker

Literal[...]不能被子类化。在运行时,可以将任意值用作Literal[...]的类型参数,但是类型检查器可能会施加限制。有关 Literals 类型的更多详细信息,请参见 PEP 586

3.8 版的新Function。

正如在 PEP 526中引入的那样,包装在 ClassVar 中的变量 Comments 指示打算将给定属性用作类变量,并且不应在该类的实例上设置该属性。用法:

class Starship:
    stats: ClassVar[Dict[str, int]] = {} # class variable
    damage: int = 10                     # instance variable

ClassVar仅接受类型,无法进一步订阅。

ClassVar本身不是类,因此不应与isinstance()issubclass()一起使用。 ClassVar不会更改 Python 运行时行为,但可以由第三方类型检查器使用。例如,类型检查器可能会将以下代码标记为错误:

enterprise_d = Starship(3000)
enterprise_d.stats = {} # Error, setting class variable on instance
Starship.stats = {}     # This is OK

版本 3.5.3 中的新Function。

MAX_SIZE: Final = 9000
MAX_SIZE += 1  # Error reported by type checker

class Connection:
    TIMEOUT: Final[int] = 10

class FastConnector(Connection):
    TIMEOUT = 1  # Error reported by type checker

这些属性没有运行时检查。有关更多详细信息,请参见 PEP 591

3.8 版的新Function。

它旨在用于可以接受任何类型的字符串而不允许混合不同类型的字符串的函数。例如:

def concat(a: AnyStr, b: AnyStr) -> AnyStr:
    return a + b

concat(u"foo", u"bar")  # Ok, output has type 'unicode'
concat(b"foo", b"bar")  # Ok, output has type 'bytes'
concat(u"foo", b"bar")  # Error, cannot mix unicode and bytes
if TYPE_CHECKING:
    import expensive_mod

def fun(arg: 'expensive_mod.SomeType') -> None:
    local_var: expensive_mod.AnotherType = other_fun()

请注意,第一种类型的 Comments 必须用引号引起来,使其成为“前向引用”,以对解释器运行时隐藏expensive_mod引用。不会评估局部变量的类型 Comments,因此不需要将第二个 Comments 用引号引起来。

版本 3.5.2 中的新Function。

首页