python中关键字参数
This is a quick post to brief describe a problem I ran into the other day when trying to debug someone’s code – the answer may be entirely obvious to you, but it took me a while to work out, so I thought I’d document it here.
这是一篇简短的文章,简要介绍了我前几天尝试调试某人的代码时遇到的一个问题–答案可能对您完全显而易见,但是花了我一段时间才解决,所以我认为我要记录下来这里。
The problem that I was called over to help with was a line of code like this:
我被要求帮助的问题是这样的代码行:
t.do_something(a=5, b=10)
t.do_something(a=5, b=10)
where t
was an instance of a class. Now, this wasn’t the way that I usually write code – I tend to only use keyword arguments after I’ve already used positional arguments – but it reminded me that in Python the following calls to the function f(a, b)
are equivalent:
其中t
是一个类的实例。 现在,这不是我通常编写代码的方式–我倾向于只在已经使用位置参数之后才使用关键字参数–但它提醒我在Python中,以下对函数f(a, b)
调用是当量:
Anyway, going back to the original code: it gave the following error:
无论如何,回到原始代码:它给出了以下错误:
do_something() got multiple values for argument 'a'
do_something() got multiple values for argument 'a'
which I thought was very strange, as there was definitely only one value of a
given in the call to that method.
我认为是很奇怪的,因为有绝对的只有一个值a
在调用该方法给出。
If you consider yourself to be a reasonably advanced Python programmer than you might want to stop here and see if you can work out what the problem is. Any ideas?
如果您认为自己是一名相当高级的Python程序员,那么您可能想要在这里停下来看看是否可以解决问题所在。 有任何想法吗?
When you’ve had a bit of a think, continue below…
想了一下之后,继续下面的…
I had a look at the definition of t.do_something()
, and it looked like this:
我看了t.do_something()
的定义,它看起来像这样:
You may have noticed the problem now – although at first glance I couldn’t see anything wrong… There was definitely only one parameter called a
, and it definitely wasn’t being passed twice…so what was going on?!
您现在可能已经注意到了这个问题-尽管乍看之下我看不到任何错误……肯定只有一个称为a
参数,而且它肯定没有被传递两次……所以这是怎么回事?
As you’ve probably noticed by now…this method was missing the self
parameter – and should have been defined as do_something(self, a, b)
. Changing it to that made it work fine, but it’s worth thinking about exactly why we were getting that specific error.
您可能已经注意到了……该方法缺少self
参数-应该将其定义为do_something(self, a, b)
。 将其更改为使其正常工作,但值得确切思考为什么我们会遇到该特定错误。
Firstly, let’s have a look at a more ‘standard’ error that you might get when you forget to add self
as the first argument for an instance method. We can see this by just calling the method without using keyword arguments (that is, t.do_something(1, 2)
), which gives:
首先,让我们看看当您忘记将self
作为实例方法的第一个参数添加时可能会遇到的“标准”错误。 我们可以通过不使用关键字参数(即t.do_something(1, 2)
)而仅调用方法来看到这一点,它给出:
TypeError: test_noself() takes 2 positional arguments but 3 were given
TypeError: test_noself() takes 2 positional arguments but 3 were given
Now, once you’ve been programming Python for a while you’ll be fairly familiar with this error from when you’ve forgotten to put self
as the first parameter for an instance method. The reason this specific error is produced is that Python will always pass instance methods the value of self
as well as the arguments you’ve given the method. So, when you run the code:
现在,一旦您已经对Python进行了一段时间的编程,就会从忘记将self
用作实例方法的第一个参数时就非常熟悉此错误。 产生此特定错误的原因是,Python总是将实例方法的self
值以及您赋予该方法的参数传递给实例方法。 因此,当您运行代码时:
Python will change this ‘behind the scenes’, and actually run:
Python会在“幕后”更改它,并实际运行:
t.do_something(t, 1, 2)
t.do_something(t, 1, 2)
and as do_something
is only defined to take two arguments, you’ll get an error. Of course, if your function had been able to take three arguments (for example, if there was an optional third argument), then you would find that t
(which is the value of self
in this case) was being passed as the first argument (a
), 1
as the value of the second argument (b
) and 2
as the value of the third argument (which could have been called c
). This is a good point to remind you that the first argument of methods is only called self
by convention – and that Python itself doesn’t care what you call it (although you should always call it self
!)
并且由于do_something
仅定义为接受两个参数,因此会出现错误。 当然,如果您的函数能够接受三个参数(例如,如果有一个可选的第三个参数),那么您会发现将t
(在这种情况下为self
的值)作为第一个参数传递( a
), 1
作为第二个自变量( b
)的值, 2
作为第三个自变量的值(可能称为c
)。 提醒您一个好点是,方法的第一个参数按照惯例仅被称为self
-Python本身并不关心您所称的名称(尽管您应该始终将其称为self
!)
From this, you should be able to work out why you’re getting an error about getting multiple values for the argument a
… What’s happening is that Python is passing self
to the method, as the first argument (which we have called a
), and is then passing the two other arguments that we specified as keyword arguments. So, the ‘behind the scenes’ code calling the function is:
由此看来,你应该能够明白为什么你得到一个错误有关获取多个值的参数a
...发生了什么事是,Python是通过self
的方法,作为第一个参数(我们称之为a
)然后传递我们指定为关键字参数的其他两个参数。 因此,调用该函数的“幕后”代码为:
But, the first argument is called a
, so this is basically equivalent to writing:
但是,第一个参数称为a
,因此基本上等效于编写:
t.do_something(a=t, a=1, b=2)
t.do_something(a=t, a=1, b=2)
which is obviously ambiguous – and so Python throws an error.
这显然是模棱两可的-因此Python会引发错误。
Interestingly, it is quite difficult to get into a situation in which Python throws this particular error – if you try to run the code above you get a different error:
有趣的是,很难陷入Python抛出此特定错误的情况–如果您尝试运行上面的代码,则会得到另一个错误:
as Python has realised that there is a problem from the syntax, before it even tries to run it. You can manage it by using dictionary unpacking:
因为Python在尝试运行它之前就已经意识到语法存在问题。 您可以使用字典解压缩来管理它:
def f(a, b): pass d = {'a':1, 'b':2} f(1, **d)
def f(a, b): pass d = {'a':1, 'b':2} f(1, **d)
Here we are defining a function that takes two arguments, and then calling it with a single positional argument for a
, and then using the **
method of dictionary unpacking to take the dictionary d
and convert each key-value pair to a keyword argument and value combination.
这里我们定义一个函数,它有两个参数,然后用为单个位置参数调用它a
,然后使用**
字典拆包采取的字典的方法d
和各键值对转换为一个关键字参数和价值组合。
So, congratulations if you’d have solved this problem far quicker than me – but I hope it has made you think a bit more about how Python handles positional and keyword arguments. A few points to remember:
因此,恭喜您,如果您比我更快地解决了这个问题,但我希望它使您对Python如何处理位置和关键字参数有了更多的思考。 需要记住的几点:
self
as the first argument of your methods! (This would have stopped this problem ever happening!)self
is just a convention, and Python will pass the instance of your class to your first argument regardless what it is called, which can cause weird problems.self
作为方法的第一个参数! (这将阻止此问题的发生!) self
只是一个约定,Python会将类的实例传递给您的第一个参数,而不管它的名称是什么,这可能会引起奇怪的问题。 翻译自: https://www.pybloggers.com/2016/08/got-multiple-values-for-argument-error-with-keyword-arguments-in-python-classes/
python中关键字参数