一些编程语言对变量使用静态类型,例如 C/C++。需要预先声明函数的变量、参数和返回值的类型。预定义类型要求编译器在编译和运行之前检查代码。
Python 使用动态类型,其中函数的变量、参数和返回值可以是任何类型。此外,在程序运行时,变量的类型可能会发生变化。Python 解释器在运行时根据上下文来动态推断变量类型。如下面这个add()函数,输入参数,可以是任意类型。
def add(x,y)
return x+y
print(add(10+20))
print(add(3.14+5.10))
print(add(10+20.33))
print(add("hello","world"))
如果换成C++, 用函数模板来实现,显然不如python 灵活。
template
T add(T x, T y) {
return x + y;
}
// 如果输入参数为整数
int a = 3;
int b = 4;
int result = add(a, b); // result 等于 7
//如果输入参数为浮点数
double c = 3.14;
double d = 2.71;
double result = add(c, d); // result 等于 5.85
//如果x, y 类型不同,必须先转换成同类型,才能调用。
//如果是字符串,必须重写方法
换成 java 的泛型来实现,可读性还不如C++ 。
public class AddFunction {
public static <T extends Number> T add(T x, T y) {
return (T) x.doubleValue() + y.doubleValue();
}
public static void main(String[] args) {
Integer a = 3;
Integer b = 4;
int resultInt = add(a, b); // resultInt 等于 7
Double c = 3.14;
Double d = 2.71;
double resultDouble = add(c, d); // resultDouble 等于 5.85
}
}
通常,动态类型使编程变得容易,但也容易导致程序运行时发生错误。Python 的类型注解为您提供了可选的静态类型,可以同时利用静态和动态类型二者优势。
下面的示例定义了一个简单的函数,该函数接受一个字符串并返回另一个字符串:
def say_hi(name):
return f'Hi {name}'
greeting = say_hi('John')
print(greeting)
下面是向参数添加类型注解和函数返回值的语法:
parameter: type
-> type
例如,下面演示如何对函数的参数和返回值使用类型注解:
def say_hi(name: str) -> str:
return f'Hi {name}'
greeting = say_hi('John')
print((greeting)
输出:
Hi John
在此新语法中,name参数的类型为:str
.
并且 -> str 表示函数的返回值也是str
除了int, str 类型之外,还可以使用其他内置类型,例如str
、int
、float
、bool
、bytes
等。
需要注意的是,Python 解释器完全忽略了类型注解。如果将数字传递给函数,程序将运行,而不会出现任何警告或错误:say_hi()
def say_hi(name: str) -> str:
return f'Hi {name}'
greeting = say_hi(123)
print(greeting)
输出:
Hi 123
若要检查类型注解的语法,需要使用静态类型检查器工具。
Python 没有官方的静态类型检查器工具。目前,最流行的第三方工具是 Mypy。由于 Mypy 是第三方软件包,因此需要使用以下命令进行安装:pip
pip instal mypyCode
安装后,您可以使用它来在运行程序之前使用以下命令检查类型:mypy
mypy app.py
它将显示以下消息:
app.py:5: error: Argument 1 to "say_hi" has incompatible type "int"; expected "str"
Found 1 error in 1 file (checked 1 source file)
该错误指示 的参数是 ,而预期类型是 。say_hi``int``str
如果将参数改回字符串并再次运行,它将显示一条成功消息:mypy
Success: no issues found in 1 source file
定义变量时,可以添加如下类型注解:
name: str = 'John'
变量的类型是。如果将非字符串的值分配给变量,则静态类型检查器将发出错误。例如
name: str = 'Hello'
name = 100
错误:
app.py:2: error: Incompatible types in assignment (expression has type "int", variable has type "str")
Found 1 error in 1 file (checked 1 source file)
向变量添加类型不是必须的,因为静态类型检查器通常可以根据分配给变量的值来推断类型。
在此示例中,name 的值是文本字符串,因此静态类型检查器会将 name 变量的类型推断为 str。例如:
name = 'Hello'
name = 100
mypy将检查出错误:
app.py:2: error: Incompatible types in assignment (expression has type "int", variable has type "str")
Found 1 error in 1 file (checked 1 source file)
前面提到的加法函数,add() 允许输入参数为任意类型
def add(x, y):
return x + y
但你想限制为整数,或浮点数。您可以使用typing模块的 Union 类提供多类型注解。
首先,从typing模块导入:Union
from typing import Union
其次,使用 创建包含int 和 float 的联合类型:Union[int, float]
def add(x: Union[int, float], y: Union[int, float]) -> Union[int, float]:
return x + y
以下是完整的源代码:
from typing import Union
def add(x: Union[int, float], y: Union[int, float]) -> Union[int, float]:
return x + y
从 Python 3.10 开始,您可以使用 X | Y 用于创建联合类型,例如:
def add(x: int | float, y: int | float) -> int | float:
return x + y
Python 允许您为类型分配别名,并将别名用于类型注解。例如:
from typing import Union
number = Union[int, float]
def add(x: number, y: number) -> number:
return x + y
在此示例中,我们为Union[int, float]
分配一个别名number,并在 add()函数中使用该别名。
虽然可将变量直接标注为 list, tuple,set,如果希望进一步指定集合中的元素类型,需要使用Typing 模块的 LIst, Tuple, Set,Dict, Sequence等封装类用于注解。
Typing 类型名 | Python内置类型 |
---|---|
List | list |
Tuple | tuple |
Dict | dict |
Set | set |
Sequence | 用于表示 list, tuple 类型 |
Mapping | 用于表示字典,set 类型 |
ByteString | bytes, bytearray, 以及 memoryview 等二进制类型. |
注意 typing 模块类型首字母为大写。
from typing import List
ratings: List[int] = [1, 2, 3]
data: Sequence = [1,2,3] # 用sequence 来代替 List, Tuple.
如果集合类型的元素也是集合类型,如 [(‘Jack’, 100), (‘Steve’, 300), …] , 列表元素为 tuple,
data_a: List[Tuple[str, int]] = [("Bob", 1), ("Jim", 2), ("Steven", 53)]
再看1个复杂点的类型,
data_b: List[Tuple[Tuple[int, int], str]] = [
((10, 20), "red"),
((40, 30), "green"),
((32, 45), "yellow")
]
显然,不太容易理解, 这类情形下,可通过type alias 类型别名 来注解, 增加可读性
Position = Tuple[int, int]
# type Position = Tuple[int, int] # 在V3.12, 前面加type
Pixel = Tuple[Position, str]
data_b: List[Pixel] = [
((10, 20), "red"),
((40, 30), "green"),
((32, 45), "yellow")
]
如果函数未显式返回值,则可以使用 None 键入 hint 返回值。例如:
def log(message: str) -> None:
print(message)