TypeError:bar()获得了关键字参数' _old'的多个值。

时间:2016-01-20 07:27:34

标签: python decorator

我知道在python中有一个名为decorator的东西,它可以比下面的代码更整洁地完成工作。但我很好奇为什么下面的代码不起作用。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def wrap(old, new):
    "Override an existing function."
    def repl(*args, **kwargs):
        return new(_old=old, *args, **kwargs)
    return repl

class MyClass(object):

    def foo(self, data):
        print data
        return data

def bar(self, _old, data):
    print 'running foo'
    _old(data)
    print 'foo completed'

MyClass.foo = wrap(MyClass.foo, bar)

mc = MyClass()
mc.foo('Test Data')

当我运行代码时,出现错误:

Traceback (most recent call last):
  File "./test.py", line 24, in <module>
    mc.foo('Test Data')
  File "./test.py", line 7, in repl
    return new(_old=old, *args, **kwargs)
TypeError: bar() got multiple values for keyword argument '_old'

这里有什么问题?我该如何解决?

1 个答案:

答案 0 :(得分:1)

有一些错误涉及缺少'self'参数,并且你有关键字参数引导位置参数 - 它必须是另一种方式。试试这个(Python 3,根据需要恢复。):

def wrap(old, new):
    "Override an existing function." 
    return lambda *args, **kwargs: new(*args, _old=old, **kwargs)

class MyClass(object):

    def foo(self, data):
        print(data)
        return data

def bar(self, data, _old):
    print('running foo')
    _old(self, data)
    print('foo completed')

MyClass.foo = wrap(MyClass.foo, bar)

mc = MyClass()
mc.foo('Test Data')

通过将_old移动到位置参数的末尾并重新排列调用,我们希望能够让事情发挥作用:

> python3  myclass.py
running foo
Test Data
foo completed
>

我认为具体错误“为关键字参数'_old'获取了多个值是由以下原因引起的。你以这种方式调用'bar':

new(_old = old,* args,** kwargs)

重新排列为:

new(self,data,_old = old)

(位置引导关键字)但是如果我们看一下bar的论点:

bar(self,_old,data)

我们可以看到_old传递了两次,一次作为第二个位置参数,一次作为关键字参数。

部分混淆可能是Python有两个略有不同但相互作用的'关键字参数'概念:通过关键字传递的位置参数;未指定的附加参数作为关键字传递。两者都在这里发挥。