除非我弄错了,在Python中创建一个函数是这样的:
def my_func(param1, param2):
# stuff
但是,实际上并没有给出这些参数的类型。而且,如果我没记错的话,Python是一种强类型语言,因此,Python似乎不应该让你传入与函数创建者期望的不同类型的参数。然而,Python如何知道函数的用户正在传递正确的类型呢?假设函数实际使用了形参,如果它是错误的类型,程序会死吗?必须指定类型吗?
除非我弄错了,在Python中创建一个函数是这样的:
def my_func(param1, param2):
# stuff
但是,实际上并没有给出这些参数的类型。而且,如果我没记错的话,Python是一种强类型语言,因此,Python似乎不应该让你传入与函数创建者期望的不同类型的参数。然而,Python如何知道函数的用户正在传递正确的类型呢?假设函数实际使用了形参,如果它是错误的类型,程序会死吗?必须指定类型吗?
当前回答
要有效地使用typing模块(Python 3.5新增),请包含all(*)。
from typing import *
你将准备使用:
List, Tuple, Set, Map - for list, tuple, set and map respectively.
Iterable - useful for generators.
Any - when it could be anything.
Union - when it could be anything within a specified set of types, as opposed to Any.
Optional - when it might be None. Shorthand for Union[T, None].
TypeVar - used with generics.
Callable - used primarily for functions, but could be used for other callables.
然而,你仍然可以使用类型名称,如int, list, dict,…
其他回答
从静态或编译时类型检查的意义上讲,Python不是强类型的。
大多数Python代码都属于所谓的“Duck Typing”——例如,你寻找一个对象上读取的方法——你不关心对象是磁盘上的文件还是套接字,你只想从中读取N个字节。
您不需要指定类型。该方法只有在试图访问未在传入参数上定义的属性时才会失败(在运行时)。
这个简单的函数:
def no_op(param1, param2):
pass
... 无论传入哪两个参数都不会失败。
然而,这个函数:
def call_quack(param1, param2):
param1.quack()
param2.quack()
... 如果param1和param2都没有名为quack的可调用属性,将在运行时失败。
如果有人想指定变量类型,我已经实现了一个包装器。
import functools
def type_check(func):
@functools.wraps(func)
def check(*args, **kwargs):
for i in range(len(args)):
v = args[i]
v_name = list(func.__annotations__.keys())[i]
v_type = list(func.__annotations__.values())[i]
error_msg = 'Variable `' + str(v_name) + '` should be type ('
error_msg += str(v_type) + ') but instead is type (' + str(type(v)) + ')'
if not isinstance(v, v_type):
raise TypeError(error_msg)
result = func(*args, **kwargs)
v = result
v_name = 'return'
v_type = func.__annotations__['return']
error_msg = 'Variable `' + str(v_name) + '` should be type ('
error_msg += str(v_type) + ') but instead is type (' + str(type(v)) + ')'
if not isinstance(v, v_type):
raise TypeError(error_msg)
return result
return check
使用它作为:
@type_check
def test(name : str) -> float:
return 3.0
@type_check
def test2(name : str) -> str:
return 3.0
>> test('asd')
>> 3.0
>> test(42)
>> TypeError: Variable `name` should be type (<class 'str'>) but instead is type (<class 'int'>)
>> test2('asd')
>> TypeError: Variable `return` should be type (<class 'str'>) but instead is type (<class 'float'>)
EDIT
如果没有声明任何参数的(或返回值的)类型,上面的代码就不能工作。下面的编辑可以提供帮助,另一方面,它只对kwarg有效,不检查args。
def type_check(func):
@functools.wraps(func)
def check(*args, **kwargs):
for name, value in kwargs.items():
v = value
v_name = name
if name not in func.__annotations__:
continue
v_type = func.__annotations__[name]
error_msg = 'Variable `' + str(v_name) + '` should be type ('
error_msg += str(v_type) + ') but instead is type (' + str(type(v)) + ') '
if not isinstance(v, v_type):
raise TypeError(error_msg)
result = func(*args, **kwargs)
if 'return' in func.__annotations__:
v = result
v_name = 'return'
v_type = func.__annotations__['return']
error_msg = 'Variable `' + str(v_name) + '` should be type ('
error_msg += str(v_type) + ') but instead is type (' + str(type(v)) + ')'
if not isinstance(v, v_type):
raise TypeError(error_msg)
return result
return check
Alex Martelli解释道,
正常的、Pythonic的、首选的解决方案几乎总是“duck typing”:尝试使用参数,好像它是某种所需的类型,在try/except语句中执行它,捕捉如果参数实际上不是该类型(或任何其他类型,很好地模仿它;-)可能出现的所有异常,并在except子句中尝试其他内容(使用参数“as if”它是其他类型)。
阅读他的文章以获得有用的信息。
要有效地使用typing模块(Python 3.5新增),请包含all(*)。
from typing import *
你将准备使用:
List, Tuple, Set, Map - for list, tuple, set and map respectively.
Iterable - useful for generators.
Any - when it could be anything.
Union - when it could be anything within a specified set of types, as opposed to Any.
Optional - when it might be None. Shorthand for Union[T, None].
TypeVar - used with generics.
Callable - used primarily for functions, but could be used for other callables.
然而,你仍然可以使用类型名称,如int, list, dict,…