Python是我的第一个动态语言。我最近编写了一个函数调用错误地提供了错误数量的参数。这在调用函数时发生异常失败。我希望即使在动态语言中,也可以在解析源文件时检测到这种错误。
我知道在调用函数之前,实际参数的类型是未知的,因为同一个变量可能包含不同时间的任何类型的值。但是,只要解析了源文件,就会知道数量的参数。程序运行时不会改变。
为了将其保持在Stack Overflow的范围内,让我说出这样的问题。是否有Python提供的功能,要求它在代码实际执行之前延迟检查函数调用中的参数数量?
答案 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邮件列表前一段时间,但它并没有获得任何真正的支持。