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

Python函数如何处理传入的参数类型?,python,function,parameters,Python,Function,Parameters,除非我弄错了,否则在Python中创建函数的工作原理如下: def my_func(param1, param2): # stuff def pick(l: list, index: int) -> int: return l[index] def pick(l: list, index: int = 0) -> int: if not isinstance(l, list): raise TypeError return l[in

除非我弄错了,否则在Python中创建函数的工作原理如下:

def my_func(param1, param2):
    # stuff
def pick(l: list, index: int) -> int:
    return l[index]
def pick(l: list, index: int = 0) -> int:
    if not isinstance(l, list):
        raise TypeError
    return l[index]
def pick(l, index):
    """
    :param l: list of integers
    :type l: list
    :param index: index at which to pick an integer from *l*
    :type index: int
    :returns: integer at *index* in *l*
    :rtype: int
    """
    return l[index]

但是,实际上并没有给出这些参数的类型。另外,如果我记得的话,Python是一种强类型语言,因此,Python似乎不应该让您传入与函数创建者期望的不同类型的参数。但是,Python如何知道函数的用户正在传递正确的类型?假设函数实际使用了该参数,那么如果程序的类型错误,它会死掉吗?您必须指定类型吗?

Python不是静态或编译时类型检查意义上的强类型


大多数Python代码都属于所谓的类型——例如,在对象上查找方法
read
——不管对象是磁盘上的文件还是套接字,只要从中读取N个字节即可;Python的概念是:;基本上,处理参数的代码将对它们做出某些假设——可能是通过调用某个参数预期实现的某些方法。如果参数的类型错误,则将引发异常


通常,由您的代码来确保传递的对象类型正确-没有编译器提前强制执行此操作。

您不指定类型。该方法只有在尝试访问传入的参数上未定义的属性时才会失败(在运行时)

所以这个简单的函数:

def no_op(param1, param2):
    pass
def call_quack(param1, param2):
    param1.quack()
    param2.quack()
。。。无论传入哪两个参数,都不会失败

但是,该功能:

def no_op(param1, param2):
    pass
def call_quack(param1, param2):
    param1.quack()
    param2.quack()

。。。如果
param1
param2
都没有名为
quack

的可调用属性,则在运行时将失败。Python不关心传递给它的函数的内容。调用
my_func(a,b)
时,param1和param2变量将保存a和b的值。Python不知道您正在使用正确的类型调用函数,并且希望程序员能够处理这个问题。如果将使用不同类型的参数调用函数,则可以使用try/except块包装访问它们的代码,并以任何方式计算参数。

As

正常的、python式的、首选的解决方案几乎总是“duck typing”:尝试使用参数,就好像它是某个所需的类型一样,在try/except语句中执行该操作,该语句捕获可能出现的所有异常,如果该参数实际上不是该类型(或任何其他类型很好地模仿它;-),并且在except子句中,尝试其他方法(使用参数“仿佛”它属于其他类型)


阅读他的文章的其余部分以获得有用的信息。

Python是强类型的,因为每个对象都有一个类型,每个对象都知道它的类型,不可能偶然或故意使用一个类型为“仿佛”的对象,它是一个不同类型的对象,并且对象上的所有基本操作都委托给它的类型

这与名称无关。Python中的名称没有“类型”:定义名称时,名称引用对象,对象确实有类型(但实际上并不强制名称上有类型:名称就是名称)


Python中的名称完全可以在不同的时间引用不同的对象(就像在大多数编程语言中一样,尽管不是全部)——并且名称上没有约束,因此,如果它曾经引用过X类型的对象,然后,它永远只能引用X类型的其他对象。名称上的约束不属于“强类型”概念的一部分,尽管一些静态类型的爱好者(名称确实受到约束,并且是静态的,也就是编译时的方式)不要这样误用这个术语。

在Python中,任何东西都有一个类型。如果参数类型支持Python函数,则Python函数将执行要求它执行的任何操作

示例:
foo
将添加所有可以添加的内容不用担心它的类型。这意味着,为了避免失败,您应该只提供那些支持加法的东西

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

许多语言都有变量,这些变量属于特定类型并具有值。Python没有变量;它有对象,您可以使用名称来引用这些对象

在其他语言中,当你说:

a = 1
然后(通常为整数)变量将其内容更改为值1

在Python中

a = 1
表示“使用名称a引用对象1”。您可以在交互式Python会话中执行以下操作:

>>> type(1)
<type 'int'>

该函数接收两个对象,并将它们命名为
param1
param2
,而不考虑它们的类型。如果要确保接收到的对象属于特定类型,请将函数编码为所需类型,并捕获抛出的异常(如果不是所需类型)。引发的异常通常是
TypeError
(您使用了无效的操作)和
AttributeError
(您试图访问不存在的成员(方法也是成员))。

其他答案在解释duck键入和:


Python没有变量,就像其他语言一样,变量有类型和值;它的名称指向对象,对象知道它们的类型

然而,自2010年(当第一次提出这个问题时)以来,一件有趣的事情发生了变化,即的实现(在Python 3中实现)。您现在可以实际指定参数的类型和函数的返回类型,如下所示:

def my_func(param1, param2):
    # stuff
def pick(l: list, index: int) -> int:
    return l[index]
def pick(l: list, index: int = 0) -> int:
    if not isinstance(l, list):
        raise TypeError
    return l[index]
def pick(l, index):
    """
    :param l: list of integers
    :type l: list
    :param index: index at which to pick an integer from *l*
    :type index: int
    :returns: integer at *index* in *l*
    :rtype: int
    """
    return l[index]
我们可以在这里看到,
pick
包含两个参数,一个是list
l
,一个是integer
index
。它还应该返回一个整数

因此这里暗示,
l
是一个整数列表,我们可以不费吹灰之力地看到它,但是对于mor
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.