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

Python是我的第一个dynamic语言。 我最近编写了一个函数调用错误地提供了错误数量的参数。 这在函数被调用的时候失败了。 我期望即使是在dynamic语言中,当parsing源文件时,也可以检测到这种错误。

我知道实际参数的types在函数被调用之前是不知道的,因为同一个variables在不同时间可能包含任何types的值。 但是一旦源文件被parsing,参数的数量就已经知道了。 程序运行时不会改变。

所以这不是一个哲学问题

为了保持这个在堆栈溢出的范围,让我来说这样的问题。 有没有Python提供的一些function,需要延迟检查函数调用中参数的数量,直到代码实际执行?

Python不能预先知道你最终会调用什么对象,因为dynamic的,你可以换出函数对象 。 随时。 而每个这些对象可以有不同数量的参数。

这是一个极端的例子:

 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提出exception的机会。 但是,如果情况是这样的话,Python不能先验知道!

我甚至还没有开始dynamic模块导入,dynamic函数生成,其他可调用对象(可以调用具有__call__方法的任何对象)或全部**kwargs参数( *args**kwargs )。

但为了使这个更清楚,你在你的问题中陈述:

程序运行时不会改变。

这不是这种情况,不是在Python中,一旦模块被加载,您可以删除,添加或replace模块名称空间中的任何对象,包括函数对象。

传递的参数个数是已知的,但不是实际调用的函数。 看到这个例子:

 def foo(): print("I take no arguments.") def bar(): print("I call foo") foo() 

这可能看起来很明显,但让我们把它们放到一个名为“fubar.py”的文件中。 现在,在交互式Python会话中,执行以下操作:

 >>> import fubar >>> fubar.foo() I take no arguments. >>> fubar.bar() I call foo I take no arguments. 

这是显而易见的。 现在是有趣的部分。 我们将定义一个需要非零数量参数的函数:

 >>> def notfoo(a): ... print("I take arguments!") ... 

现在我们做一些叫做猴子补丁的东西。 我们实际上可以replace fubar模块中的函数foo

 >>> fubar.foo = notfoo 

现在,当我们调用bar ,将会引发TypeError ; foo这个名字现在指的是我们上面定义的函数,而不是原来的函数former-known-as- foo

 >>> fubar.bar() I call foo Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/horazont/tmp/fubar.py", line 6, in bar foo() TypeError: notfoo() missing 1 required positional argument: 'a' 

所以即使在这样的情况下,被调用的函数foo可能看起来非常明显,但是Python只能知道它实际上是执行该源代码行时被调用的foo函数。

这是Python的一个属性,它使得它强大,但是它也导致了它的一些缓慢。 实际上,前段时间在python-ideas邮件列表上已经讨论了使模块只读来提高性能 ,但是没有得到任何实际的支持。