【问题标题】:TypeError: bar() got multiple values for keyword argument '_old'TypeError: bar() 为关键字参数“_old”获取了多个值
【发布时间】:2016-04-25 22:28:54
【问题描述】:

我知道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'

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

【问题讨论】:

  • 为什么你的函数bar有一个参数self
  • 问题可能出在“自我”那里,也许这里的答案可以帮助stackoverflow.com/questions/18950054/…
  • @jacob 因为wrap 旨在用bar 替换foofoo 有一个参数self,所以bar 应该有一个参数self
  • @trainoasis 无论我是否添加self,代码都不起作用。

标签: python decorator


【解决方案1】:

有几个错误涉及缺少“自我”参数,并且您有关键字参数引导位置参数 - 它必须是相反的方式。试试这个(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':

新的(_old=old, *args, **kwargs)

重新排列成:

新的(自我,数据,_old=old)

(位置引导关键字)但是如果我们查看 bar 的参数:

bar(self, _old, data)

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

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

【讨论】:

  • 谢谢!但是还有一个问题我还没想通。我为什么要把_old作为bar的最后一个参数?
  • @Searene,我已经扩展了我的答案以尝试解决您收到的特定错误消息,这可能会阐明为什么重新排列参数顺序可以解决此问题。
猜你喜欢
  • 2017-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-28
相关资源
最近更新 更多