OP:print_line()缺少3个必需的位置参数:“line”、“encoding”和“errors”
错误很明显,因为它是函数print_line()的定义方式。在
此外:def print_line(line, encoding, errors):
print(line, encoding, errors)
line = 1
encoding = 2
errors = 3
print_line(errors, encoding, line)
输出:
^{pr2}$
Note: It is positional, not naming arguments
编辑:1def abc(a,b,c=2):
return a+b+c
abc(1,2) #both positional argument and c is default
5
abc(2, b=3) # positional, named and again c is default
7
abc(a=2,b=4) # both named argument and c is default
8
编辑2:
位置论元的目的是什么?
嗯。。在
简而言之:位置参数是没有作为key=value对提供的任何参数。在
不幸的是,要理解这意味着什么,多少有些牵扯。在
术语“参数”在整个编程社区中的使用有点不精确,尤其是在Python文档中。在
从技术上讲,参数是传递给函数的内容,而参数是定义为这些参数的名称/占位符的内容。在
所以,当我定义一个函数时:def foo(a,b):
return a+b
。。。这样称呼:foo(1,3)
。。。然后a和b是我的参数,而1和3是对该函数的给定调用的参数。在
现在这是一个诡辩。当a和b实际上是函数执行时包含参数的名称(参数),人们通常将a和b称为函数的“参数”。在
现在,有了这一点,请理解Python支持四类参数:“required positional”(您在其他任何编程语言中都见过的类型)、“optional”。。。或者“违约”。。。位置参数具有指定的默认值,“星ARG”(类似于其他语言如VC++和java的VARARGS支持)和“KWARG.\”/P>
后者几乎是Python所独有的(尽管Ruby也有非常类似的支持)。在
因此,您可以使用如下参数列表定义函数:def bar(a, b, c=None, d=[], *e, **opts):
'''bar takes all sorts of arguments
'''
results = dict()
results['positional 1'] = a
results['positional 2'] = b
results['sum']=a+b
results['optional'] = list()
for each in e:
results['optional'].append(each)
if c is not None:
results['default over-ridden']=c
else:
results['default']='no arg supplied for parameter c'
d.append(results)
if 'verbose' in opts and opts['verbose']:
for k,v in results:
print '%s:%s' % (k, v)
return (results, d)
。。。这个相当做作的例子有两个正常的、传统的位置参数(a和b),以及可选的第三个和第四个参数(其中一个参数将默认为特殊的Python singleton值None,如果bar()只使用两个参数调用,另一个参数将默认为列表)以及可选变量数目的附加参数(通过名为“e”的参数传递到我们的函数中),最后,bar()可以接受任意数量的“keyword”参数(作为键值对传递给它并通过参数“opts”引用)(在我的示例中)。在
那里有很多东西要消化。首先有a和b,就像你在大多数编程语言中看到的一样。如果只使用一个参数调用此函数,则会出现错误,因为该函数需要两个参数。还有c和d。。。这些参数可以与参数一起提供。。。但是如果只使用两个必需的参数调用函数,那么参数c将引用“None”,而d将引用列表。。。它是在我们定义函数时实例化的!在
哇!请重新阅读最后一点,因为这是一个常见的混淆源,因为对于那些错误地定义了带有默认可变类型(列表、字典、集合或自定义类的大多数实例)的函数的人来说。在
在Python中定义函数时,解释器正在执行代码。它执行def语句并计算参数(这些参数将成为函数的参数)。因此,Python虚拟机在定义函数时实例化一个list([]---empty list literal)。参数(在我的示例中是e)现在绑定到该列表,就像任何Python“variable”(名称)绑定到任何其他对象一样。它所引用的对象在调用bar()时只要使用三个或更少的参数就可以访问。在
这里有一个棘手的地方:任何时候你用超过三个参数调用bar,那么参数e将被绑定到第四个参数(在特定调用的持续时间内)乌门特。在调用期间,基础列表将被隐藏。这样的默认列表对象包含在一个闭包中,通常在函数之外是完全不可访问的。(在本例中,我在return语句中包含了对它的引用,展示了如果选择的话,如何导出对该封闭对象的引用)。在
因此,如果我传递bar()四个参数,那么它将尝试使用对象的“append”方法修改通过其“e”参数引用的对象。(显然,这将失败,并对任何不支持append方法的对象引发异常)。每次我只使用三个参数调用bar()时,我都会在其闭包中修改封闭的list对象。在
这可能很有用,但这很少是新程序员在学习Python时所期望的。因此,通常情况下,不要将可变对象的函数定义为参数的默认值。当你很好地理解了语义,你就知道什么时候该打破这个规则了。在
我使用“None”作为另一个参数的默认值是有原因的。通常,使用“None”作为任何参数的默认值,然后显式测试“is None”并在函数体中提供自己的默认值,这通常很有用。通过这种方式,您可以区分默认参数值和显式传递给您的任何参数(碰巧与默认值匹配)。(这也可以防止您无意中创建了前面描述的可变闭包的情况。函数体中发生的赋值/绑定将为达到该条件的每个调用生成一个新的实例化)。在
因此,我们讨论了所需的位置参数,以及提供默认值的参数(因此,它们是可选的位置参数)。在
使用参数'e'我们可以看到Python支持可变数量的参数。在第四个参数之后指定的任何参数都将被收集到一个元组中,并通过参数“e”传递给我们。。。除了任何形式的参数:this=that。在
最后,这给了我们。{programmers{programmers{optional)将“{ts>”称为“^参数”。我把它命名为“opts”来强调这一点,“kwargs”只是一个传统的术语,从技术上讲,有点令人困惑,因为我在本文中已经详细讨论过了,它是一个参数,它指的是通过某个函数调用作为参数传递的任何关键字参数。在
可以编写所有函数,使它们不带位置参数,只使用“key/words arguments”参数定义。然后,您可以确保函数的调用方每次调用时都必须说明哪个参数绑定到了哪个名称。如果您的函数在使用错误顺序的参数调用时可能会产生灾难性的后果,那么这将非常方便。在
我知道这很令人困惑。。。我绝对建议您使用不同的函数定义和各种各样的调用,看看它们是如何相互作用的。在
我还要指出一个额外的“gotchya”会咬你。调用者不能传递kwargs(opts)值,其键的名称与参数名冲突。尝试使用参数列表调用bar(),例如:bar(1,2,3,4,a=99),您将得到如下异常:"TypeError: bar() got multiple values for keyword argument 'a'"
Python通过管理名称空间(如字典)将参数解析为参数。试图提供一个关键字/单词参数,任何与参数名匹配的键都会产生歧义。。。因此引发了一个例外。在
对于这个已经很麻烦的答案,我还将添加两个额外的注释。在
在Python中调用函数时,可以传递如下参数:myargs=(1,2,3)
bar(*myargs)
。。。这将被视为你用^{}---或者就像您进行以下函数调用一样:apply(bar, myargs)。在
事实上,为了完成这一层的间接寻址,您必须使用apply()函数(以前可以用*foo参数定义函数,但不能用*foo参数调用它们)。在
(在函数调用时添加了*args语法,这在很大程度上取代了Python的apply()内置函数的使用)。在
。。。最后,可以使用以下语法传递kwargs的字典:mykwargs={'z':99, 'whatever':'yikes'}
bar(1,2,3, **mykwargs)
。。。或者结合我之前的例子:bar(*myargs, **mykwargs)
因此,理解*和**在定义函数时的含义以及它们在调用函数时的含义是非常重要的。如果你理解了参数和参数之间的区别,那么这些含义是相互补充和直观的(尽管术语“arguments”更常用)。在