Python函数中的参数太多/太少时为什么会出现TypeError

2024-04-29 12:55:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我很难理解为什么Python在提供不是方法签名一部分的参数时会引发TypeError。在

示例:

>>> def funky():
...    pass
... 
>>> funky(500)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: funky() takes no arguments (1 given)

我想,如果这是因为*args应该是None或{}在无参数函数的作用域内,那就是leaky abstraction,所以我查了一下。在

我的发现

PEP-3102上搜索TypeError时,找到了似乎是某个上下文中{}被提出的理由,但我不明白这种理由。PEP的示例基本上说明了该功能基本上是if args: raise TypeError()的快捷方式。args在这种情况下是一个非空列表,而不是空列表。。。它们都是同一类型的。如果我没搞错的话,确实是正当理由,也许ValueError会更合适。然而,这仍然是一个漏洞百出的抽象,因为这个例子是用Python编写的,使得它更像是某个用例的实现细节,而不是语言特性。类似ArgumentError的东西在这里听起来更合适,这让我相信有一些明显的解释,我忽略了为什么{}有意义。在


Tags: 方法示例most列表参数defargspass
2条回答

函数接受n个参数。您提供了mn != m。这可能是某个人代码中的一个bug,或者是某人对某个API的误解。另外,我认为我们不能就有意义的,有用的语义达成一致。多余的论点应该被忽略吗?这会让这些错误消失,而且“错误永远不会悄悄地过去”,这是不可接受的。类似地,为省略的参数提供一些默认值允许在打字错误等情况下出现无声的错误行为,因此违反了相同的原则,更不用说“显式优于隐式”,即,如果您想传递某些特殊值,则应将其写出来。在

您所指的PEP及其if args: raise TypeError(...)语义仅适用于具有不接受varargs的仅关键字参数的函数,并在参数列表中使用一个普通的*对其进行编码。有些函数可以接受有限数量的位置参数,并且可以从仅限关键字的参数中获益,但varargs对它们没有意义。对于这些,普通的*允许只使用关键字的参数,而不需要样板代码,并且在有人提供太多参数的情况下仍然通知程序员(这是一件好事,因为答案的第一部分列出了原因)。在

至于选择TypeError的原因:“参数数目错误”是静态语言中的编译器类型错误/类型不匹配。我们在Python中没有对这些东西进行compiletime检查,但这仍然是一种“类型错误”。如果(在Python中,非正式的)类型签名显示“我接受两个参数”,而您提供了三个参数,那么这显然违反了该约定。TypeError不仅仅是not isinstance(x, expected),就像其他很多与类型相关的主题一样(想想继承和“gets parent's stuff”与“is-a parent”)它是一个更广泛的概念。在

编辑回应你对静态类型比较的批评:考虑一元函数和二元函数不同,这不仅仅是静态类型系统的一个限制。即使在Python这样的语言中,它也非常有用,因为这两种语言还不够相似,不能“像走路一样嘎嘎嘎嘎地一样”(就像在duck类型中一样)——它们不能以相同的方式使用。(元编程是一个例外,它包装了大量的函数,由***解包运算符来处理。)它们碰巧都有一个事实,即它们是可调用的,但即使Python的内置对象层次结构没有创建许多只在数量和名称上不同的相同类。type(f)可能会说function,但这并不总是故事的结尾。在

你说: def funky(): ... 所以程序“funky”不应该接受任何“参数”。但是当你使用这个程序时,你说funky(参数),而funky不接受参数,所以导致了错误。要修复此问题,请使用;def funky(n):pass。在

相关问题 更多 >