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

时间:2016-01-02 15:58:13

标签: python arguments

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

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

所以这不是一个哲学问题

为了将其保持在Stack Overflow的范围内,让我说出这样的问题。是否有Python提供的功能,要求它在代码实际执行之前延迟检查函数调用中的参数数量?

2 个答案:

答案 0 :(得分:146)

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())

上面的代码有两到三次提出异常的机会。但是,如果不是这样的话,Python就无法知道先验!

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

但是要明确这一点,请在问题中说明:

  

程序运行时不会改变。

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

答案 1 :(得分:35)

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

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!")
...

现在我们做一些名为 monkey patching 的事情。实际上我们可以替换 foo模块中的函数fubar

>>> fubar.foo = notfoo

现在,当我们致电bar时,会提出TypeError;名称foo现在指的是我们在上面定义的函数,而不是以前称为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的一个属性,它使它强大,但它也导致它的一些缓慢。事实上,making modules read-only to improve performance has been discussed在python-ideas邮件列表前一段时间,但它并没有获得任何真正的支持。