【问题标题】:define_method in PythonPython 中的定义方法
【发布时间】:2018-06-04 07:49:58
【问题描述】:

我想为 Python 类动态定义一些方法。我google了一会儿,发现this。我稍微更改了代码以满足我的要求。

这是我的代码:

class Base(object):

  def add_method(self, field):
    def func(self, value):
      self.colors[field] = value
      return self
    return func

  def define_method(self, *fields):
    for field in fields:
      setattr(self, "with_" + field, self.add_method(field))


class MyColor(Base):

  def __init__(self):
    self.colors = {
      "black": "000",
      "red": "f00",
      "green": "0f0"
    }

    # ========== ==========
    # by doing this, I assume `with_red()` and `with_green()`
    # will be generated, and they're chain-able.
    super(MyColor, self).define_method("red", "green")


s = MyColor()
s.with_red("111").with_green("222")
print(s.colors) 
# should output: {"black": "000", "red": "111", "green": 222}

代码会报错:

Traceback (most recent call last):
  File "main.py", line 26, in <module>
    s.with_red("111").with_green("222")
TypeError: _with_field() missing 1 required positional argument: 'value'

怎么了?

感谢您的宝贵时间!

==========编辑==========

对不起,我在Base 类上更改了我的原始实现,如下所示(有一个错误,总是将最后一个field 更改为define_method())。 @Alex 的回答是正确的。

class Base:

  def define_method(self, *fields):
    for field in fields:
      def _with_field(self, value):
        self.colors[field] = value
        return self
      setattr(self, "with_" + field, _with_field) 

【问题讨论】:

  • setattr(self, "with_" + field, _with_field)更改为setattr(Base, "with_" + field, _with_field)
  • @user1767754,超酷!它有效。
  • 谁能详细解释一下这个selfBasetihing?

标签: python metaprogramming setattr


【解决方案1】:

发生的情况是您设置了例如MyColor 实例上的 'with_red' 属性到 Base 构造函数中定义的本地函数 - 请注意,这不是类方法,只是一个函数,它需要 2 个参数:'self' 和 'value':

import inspect
...
s = MyColor()
print(inspect.getargspec(s.with_red))

ArgSpec(args=['self', 'value'], varargs=None, keywords=None, defaults=None)

这里一个简单的解决方法是让这个函数接受一个参数:

def _with_field(value):
   self.colors[field] = value
   return self

通过此更改,您的代码将产生预期的输出。

另一种选择是在类上设置 'with_red' 属性 - 这使它成为一个方法,然后隐式传递 self 并且您可以使用两个参数保留 _with_field 签名。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-01
    • 2011-08-27
    • 2014-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-07
    • 2022-08-24
    相关资源
    最近更新 更多