Python函数如何处理传入参数的类型?

466

除非我弄错了,创建Python函数的方式如下:

def my_func(param1, param2):
    # stuff

然而,您实际上没有给出这些参数的类型。此外,如果我没记错的话,Python是一种强类型语言,因此看起来Python不应该允许您传递与函数创建者预期的不同类型的参数。但是,Python如何知道函数的用户是否传递了正确的类型?如果类型不正确,程序会崩溃吗?您必须指定类型吗?

14个回答

1
在Python中,每个东西都有一个类型。如果参数的类型支持它,Python函数将执行任何被要求做的事情。
例如:foo将添加一切可以__add__的内容;)而不必过多担心其类型。因此,为了避免失败,您应该只提供支持加法的那些内容。
def foo(a,b):
    return a + b

class Bar(object):
    pass

class Zoo(object):
    def __add__(self, other):
        return 'zoom'

if __name__=='__main__':
    print foo(1, 2)
    print foo('james', 'bond')
    print foo(Zoo(), Zoo())
    print foo(Bar(), Bar()) # Should fail

1
无论您是否指定类型提示,运行时都会出现错误。
但是,您可以为函数参数及其返回类型提供类型提示。例如,def foo(bar: str) -> List[float] 表示 bar 应该是一个字符串,并且该函数返回一个浮点数列表。如果在方法调用之前(或返回类型之前)类型不匹配,则会导致类型检查错误。我认为这比关于方法调用中缺少字段或方法的错误更有帮助。我建议阅读官方 Python 文档Typing - Support for type hints
此外,如果您使用类型提示,您可以使用静态类型检查器来验证代码正确性。Python 中内置的一个工具是 Mypy (official documentation)。本文中介绍了如何使用 Mypy

1
def foo(bar: str) -> list: 相比于“string”,似乎需要“str”,但是即便如此,list[float]会出现错误“TypeError: 'type' object is not subscriptable ”。因此,使用上述代码就可以了,但是不知道如何处理浮点数的列表。 - Alexander Chervov
1
@AlexanderChervov 感谢您指出那个错别字,我已经修复了它。此外,您可以将返回类型设置为浮点值列表。我在那里还有一个错别字,应该是List[float],L要大写,也已经修复了。再试一次,看看它是否正常工作。 - sprite
1
List 只在 Python 3.9 之前版本中需要,现已被弃用,建议使用 list - chepner

1

我没有在其他答案中看到这个提到,所以我会补充一下。

正如其他人所说,Python不会对函数或方法参数强制执行类型。假定你知道你在做什么,如果你真的需要知道传入的某些东西的类型,你会检查它并决定自己该怎么做。

其中一个主要工具是isinstance()函数。

例如,如果我编写一个期望获取原始二进制文本数据而不是常规的utf-8编码字符串的方法,我可以在输入时检查参数的类型,并根据情况进行适应或引发异常来拒绝。

def process(data):
    if not isinstance(data, bytes) and not isinstance(data, bytearray):
        raise TypeError('Invalid type: data must be a byte string or bytearray, not %r' % type(data))
    # Do more stuff

Python还提供了各种工具来深入对象。如果你勇敢,甚至可以使用importlib在运行时创建任意类别的对象。我曾经用它来从JSON数据中重新创建对象。在像C++这样的静态语言中做这样的事情是一场噩梦。

0
为了有效地使用Python 3.5中的typing模块,请包含所有(*)。
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 等类型名称...

from somewhere import * 不是一个好主意,原因和在C++中使用using namespace std;一样。 这样做会使代码混杂着你并不一定使用的方法和类型,而且可能会在后续的代码中意外调用到你不想调用的内容(尤其是如果你经常滥用这种方式)。捕捉这些错误通常非常困难。最好的做法是只导入你需要的内容(例如from somewhere import a, b, c),或者用一个简短的别名导入库并使用该别名来调用你需要的内容(例如import some.nested.module.very_long_name as vln,然后使用vln.do_something())。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接