python - 具有默认值但没有类型注释的函数参数的推断类型是什么?初始化为 'None' 的变量怎么样?

标签 python type-hinting mypy

没有类型注释但具有初始值的变量和参数的类型是什么(在类型注释的意义上,不是 type())?例如,

foo = 2
bar = False
baz = MyClass()
bazz = None

Mypy来看docsexample code in the Python docs , foo, bar, baz当前分配int, FalseMyClass。但是,这在任何地方都已标准化吗? bazz 呢?还有呢

def my_func(param1 = 2, param2 = False): 
    ...

?类型检查器会强制传递给 my_func 的参数分别为 intbool 类型吗?

请注意,我对现状不太感兴趣,例如Mypy 等类型检查器的当前实现。相反,我想知道我的问题的答案是否已在任何地方标准化。不幸的是,PEP-484除了:

Type checkers are expected to attempt to infer as much information as necessary.

……但不清楚在上述情况下这到底意味着什么。 (毕竟,param1 = 2 可能只是默认值,实际类型可能更复杂。)

最佳答案

问题一:有默认值但没有类型注解的函数参数的推断类型是什么?

2017年,Guido van Rossum ,Python语言的创造者,建议改PEP 484指定函数参数将从默认值推断出它们的类型。

但是,截至 2020 年 10 月,PEP 484 在 "The Any type 节中说明:

A function parameter without an annotation is assumed to be annotated with Any.

在以下来自 mypy issue #3090 的讨论要点中(从默认值推断参数类型),Jukka 强化了这样一个事实,即默认值不会改变将未注释参数推断为具有类型 Any 的默认行为。

Jukka Lehtosalo写道:

Mypy follows PEP 484. A function parameter without an annotation is the same as having an Any annotation, and there is no exception for default values. Here is some rationale for this:

  • Often the default argument is not enough to infer a type. For example, None doesn't give enough context. With the current rules this doesn't pose a difficulty.
  • The default argument may not be enough to infer the correct type. For example, if the default is '' in Python 2, the correct type could well be Union[str, unicode]. If the default is 0, the correct type might well be float. If the programmer understands the rules for type inference they could override the default type with an annotation as needed, but this would add some extra complexity.
  • The default value could be a complex expression such as a function call, and thus the type may not [be] obvious from just the default value. Having an annotation makes code like this easier to read.
  • If a function has no annotation at all, then the argument type would have to be Any anyway. The current rule makes this consistent across functions with no annotations and functions with partial annotations.

It all boils down to the current rule being simple and obvious, and in practice it doesn't feel much of a burden to add a few extra : int annotations. There is no deep technical reason for the current rule, though it makes type inference easier for mypy.

然后 Guido回复:

OTOH most of those also apply to regular assignments, and there the rule is that

x = 0

infers type int for x. In practice this is very common and useful and only occasionally needs help. So I think we might use the same rule for default values and the complexity of explaining things wouldn't really change. I'm willing to make this a PEP 484 change if enough people care.

问题 2:初始化为 None 的变量的推断类型是什么?

当一个变量被初始化为None时,直接推断该变量允许显式赋值给None。如果该变量随后被赋值,例如:

bazz = None
bazz = 42  # type: Optional[int]

然后类型被推断为Optional[int]。由于 bazz 的推断类型是 Optional[int],因此稍后可以将其重新分配为 None 而不会出错。

bazz = None
bazz = 42
bazz = None  # Okay

但是,如果 bazz 没有被初始化为 None,那么下面将是一个错误:

bazz = 42
bazz = None  # Error: expression has type "None", variable has type "int"

在没有类型注释的情况下初始化变量的推断类型

PEP 484没有明确讨论根据赋值类型推断未注释变量的类型。但是,从 PEP 484 示例中的注释可以推断,未注释变量的类型确实是根据赋值推断的。

来自 PEP 484 部分的示例 "Scoping rules for type variables"

T = TypeVar('T')
S = TypeVar('S')
class Foo(Generic[T]):
    def method(self, x: T, y: S) -> S:
        ...

x = Foo()               # type: Foo[int]
y = x.method(0, "abc")  # inferred type of y is str

来自 PEP 484 部分的示例 "Instantiating generic classes and type erasure"

from typing import TypeVar, Generic

T = TypeVar('T')

class Node(Generic[T]):
    x = None  # type: T # Instance attribute (see below)
    def __init__(self, label: T = None) -> None:
        ...

x = Node('')  # Inferred type is Node[str]
y = Node(0)   # Inferred type is Node[int]
z = Node()    # Inferred type is Node[Any]

关于python - 具有默认值但没有类型注释的函数参数的推断类型是什么?初始化为 'None' 的变量怎么样?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64498806/

相关文章:

python - 我可以同时运行两个单独的 jupyter notebook 文件,而不会在单 CPU 计算机上减速吗?

python - 范围规则的简短描述?

python - def main () -> None 有什么作用?

Python mypy 无法从联合返回类型推断类型

python - 使用 MyPy 验证 `Dict` 与 `TypedDict`

python - 将文件从 Azure 文件加载到 Azure Databricks

python - 如果我没有跟踪所有进入的数据点,则将 y=x 添加到 matplotlib 散点图中

Clojure 给出反射警告而不是类型提示

python 3 typing varadic "apply"样式定义

Python 如何使用 __wrapped__ 键入提示 Callable