除非我弄错了,在Python中创建一个函数是这样的:
def my_func(param1, param2):
# stuff
但是,实际上并没有给出这些参数的类型。而且,如果我没记错的话,Python是一种强类型语言,因此,Python似乎不应该让你传入与函数创建者期望的不同类型的参数。然而,Python如何知道函数的用户正在传递正确的类型呢?假设函数实际使用了形参,如果它是错误的类型,程序会死吗?必须指定类型吗?
除非我弄错了,在Python中创建一个函数是这样的:
def my_func(param1, param2):
# stuff
但是,实际上并没有给出这些参数的类型。而且,如果我没记错的话,Python是一种强类型语言,因此,Python似乎不应该让你传入与函数创建者期望的不同类型的参数。然而,Python如何知道函数的用户正在传递正确的类型呢?假设函数实际使用了形参,如果它是错误的类型,程序会死吗?必须指定类型吗?
当前回答
如果有人想指定变量类型,我已经实现了一个包装器。
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
其他回答
您不需要指定类型。该方法只有在试图访问未在传入参数上定义的属性时才会失败(在运行时)。
这个简单的函数:
def no_op(param1, param2):
pass
... 无论传入哪两个参数都不会失败。
然而,这个函数:
def call_quack(param1, param2):
param1.quack()
param2.quack()
... 如果param1和param2都没有名为quack的可调用属性,将在运行时失败。
你从不指定类型;Python有鸭子类型的概念;基本上,处理参数的代码将对参数做出某些假设——可能通过调用参数期望实现的某些方法。如果参数类型错误,则会引发异常。
一般来说,这取决于你的代码来确保你传递的对象是正确类型的——没有编译器提前强制这一点。
在这个页面上,有一个臭名昭著的例外值得提及。
当str函数调用__str__类方法时,它会巧妙地检查其类型:
>>> class A(object):
... def __str__(self):
... return 'a','b'
...
>>> a = A()
>>> print a.__str__()
('a', 'b')
>>> print str(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __str__ returned non-string (type tuple)
就好像Guido提示我们,如果程序遇到意外类型,应该引发哪个异常。
许多语言都有特定类型的变量,变量有一个值。Python没有变量;它有对象,你用名字来指代这些对象。
在其他语言中,当你说:
a = 1
然后,变量(通常是整数)将其内容更改为值1。
在Python中,
a = 1
意思是“使用名称a来指代对象1”。你可以在交互式Python会话中执行以下操作:
>>> type(1)
<type 'int'>
函数类型使用对象1调用;因为每个对象都知道它的类型,所以type很容易找到该类型并返回它。
同样,无论何时定义函数
def funcname(param1, param2):
该函数接收两个对象,并将它们命名为param1和param2,而不考虑它们的类型。如果您想要确保接收到的对象是特定类型的,那么就按照它们是所需的类型来编写函数,如果不是,则捕获抛出的异常。抛出的异常通常是TypeError(您使用了无效操作)和AttributeError(您试图访问不存在的成员(方法也是成员))。
Python是强类型的,因为每个对象都有一个类型,每个对象都知道它的类型,不可能意外或故意使用一个类型的对象,“好像”它是一个不同类型的对象,对象上的所有基本操作都委托给它的类型。
这和名字无关。Python中的名称没有“类型”:如果定义了名称,则名称指向对象,并且对象确实具有类型(但这实际上并不强制名称具有类型:名称就是名称)。
A name in Python can perfectly well refer to different objects at different times (as in most programming languages, though not all) -- and there is no constraint on the name such that, if it has once referred to an object of type X, it's then forevermore constrained to refer only to other objects of type X. Constraints on names are not part of the concept of "strong typing", though some enthusiasts of static typing (where names do get constrained, and in a static, AKA compile-time, fashion, too) do misuse the term this way.