define_method в Python - PullRequest
       26

define_method в Python

0 голосов
/ 04 июня 2018

Я хотел бы динамически определить некоторые методы для класса Python.Некоторое время я гуглил и нашел это .Я немного изменил код, чтобы выполнить мое требование.

Вот мои коды:

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()).@ Алекс отвечает.

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) 

1 Ответ

0 голосов
/ 04 июня 2018

В результате вы устанавливаете, например, атрибут ' with_red ' в вашем экземпляре MyColor, на локальную функцию, определенную в конструкторе Base - обратите внимание, что это не метод класса, а просто функция, и она занимает 2аргументы: ' self ' и ' value ':

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

ArgSpec (args = ['self', 'value'], varargs = Нет, ключевые слова = Нет, значения по умолчанию = Нет)

Простым решением было бы заставить эту функцию принимать один аргумент:

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

Сэто изменение приведет к тому, что ваш код выдаст ожидаемый результат.

Другой вариант - установить атрибут ' with_red ' для класса - что делает его методом, затем self передаётся неявно, и вы можете сохранить _with_field подпись с двумя аргументами.

...