为什么Python允许使用错误数量的参数调用函数?

为什么Python允许使用错误数量的参数调用函数?,python,arguments,Python,Arguments,Python是我的第一种动态语言。我最近编写了一个函数调用,错误地提供了错误数量的参数。此操作失败,调用该函数时出现异常。我希望即使在动态语言中,在解析源文件时也可以检测到这种错误 我知道在调用函数之前,实际参数的类型是未知的,因为同一变量可能在不同的时间包含任何类型的值。但是只要解析源文件,就可以知道参数的数量。当程序运行时,它不会改变 所以这不是一个哲学问题 为了将其保持在堆栈溢出的范围内,让我这样表述这个问题。Python是否提供了一些特性,要求它延迟检查函数调用中的参数数量,直到代码实际

Python是我的第一种动态语言。我最近编写了一个函数调用,错误地提供了错误数量的参数。此操作失败,调用该函数时出现异常。我希望即使在动态语言中,在解析源文件时也可以检测到这种错误

我知道在调用函数之前,实际参数的类型是未知的,因为同一变量可能在不同的时间包含任何类型的值。但是只要解析源文件,就可以知道参数的数量。当程序运行时,它不会改变

所以这不是一个哲学问题
为了将其保持在堆栈溢出的范围内,让我这样表述这个问题。Python是否提供了一些特性,要求它延迟检查函数调用中的参数数量,直到代码实际执行为止?

Python无法预先知道最终将调用什么对象,因为它是动态的,所以可以调出函数对象。随时都可以。每个对象都可以有不同数量的参数

下面是一个极端的例子:

import random

def foo(): pass
def bar(arg1): pass
def baz(arg1, arg2): pass

the_function = random.choice([foo, bar, baz])
print(the_function())
上述代码引发异常的几率为2/3。但是Python无法先验地知道情况是否如此

我甚至还没有开始使用动态模块导入、动态函数生成、其他可调用对象(可以调用任何具有
\uuu调用\uuu
方法的对象)或捕获所有参数(
*args
**kwargs

但为了更清楚地说明这一点,您在问题中陈述:

当程序运行时,它不会改变


在Python中并非如此,一旦加载模块,您就可以删除、添加或替换模块命名空间中的任何对象,包括函数对象。

传递的参数数量是已知的,但实际调用的函数是未知的。请参见此示例:

def foo():
打印(“我不接受任何参数”)
def bar():
打印(“我称之为foo”)
foo()
这似乎很明显,但让我们把它们放在一个名为“fubar.py”的文件中。现在,在交互式Python会话中,执行以下操作:

>>导入fubar
>>>fubar.foo()
我不接受任何论据。
>>>fubar.bar()
我叫福
我不接受任何论据。
这是显而易见的。现在来看有趣的部分。我们将定义一个需要非零数量参数的函数:

def notfoo(a): ... 打印(“我接受参数!”) ... 现在我们做一件事,叫做。实际上,我们可以在
fubar
模块中替换函数
foo

fubar.foo=notfoo 现在,当我们调用
bar
时,将引发
TypeError
;名称
foo
现在指的是我们上面定义的函数,而不是以前称为-
foo
的原始函数

>>fubar.bar()
我叫福
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“/home/horazont/tmp/fubar.py”,第6行,在bar中
foo()
TypeError:notfoo()缺少1个必需的位置参数:“a”
因此,即使在这样的情况下,调用的函数
foo
似乎不带参数,Python也只能知道它实际上是执行源代码行时调用的
foo
函数


这是Python的一个特性,它使Python功能强大,但也导致了它的一些缓慢。事实上,在python ideas邮件列表上,它在不久前还没有得到任何真正的支持。

如果名称在运行时完全引用了不同的函数会怎么样?好吧,作为一个反参数,在解析阶段调用
f(*args)
的参数计数是未知的。应该注意的是,在类型理论中,在函数的情况下,值的类型包括参数的数量。在实际尝试调用之前,Python如何知道要调用哪个函数?Python中的函数不是有名字的。(这不是讽刺)@immibis:不,他们有名字。不过,他们并不特别喜欢这些名字。定义为
def foo()的函数:任何
都有
foo.\uuu name\uuu==“foo”
,但这不会阻止您执行
foo=some\u other\u函数
bar=foo
。我以前见过函数表,所以它可能不是那么邪恶。哦,等等,表中的函数不使用
*
参数。。。。这是Python,所以。。。。是的,非常极端。(如果你不知道如何添加归属。如果你想要,告诉我,我可能会知道。)@PyRulez:我的t恤衫上有一个URL。您只需添加
https://stackoverflow.com/a/34567789
就这样吧。@PyRulez:但这只是一份派送名单,真的。重点是要说明,您可以将函数用作对象,而您无法预先知道调用哪个函数。否则它就是一个。也许为了帮助用户解决它的原始问题:在代码运行之前检测错误,可以提到使用静态验证工具。