Как динамически клонировать методы класса, но уметь различать их в Python

1

Я пытаюсь написать оболочку для внешнего модуля в python. Модуль предоставляет метод сопряжения глагола, который ожидает 2 аргумента. Я хотел бы объединить его в несколько методов, и мне было интересно, есть ли способ сделать это программно.

то есть. вместо:

class X:
  def a(self,arg):
    return module.do(arg,'a')
  def b(self,arg):
    return module.do(arg,'b')
  ...
  def z(self,arg):
    return module.do(arg,'z')

Я пытался:

class X:
  def a(self,arg):
    return module.do(arg,__name__)
    return module.do(arg,__name__)
  def __init__(self):
    setattr(self,'b',self.a)
    ...
    setattr(self,'z',self.a)
x = X()
x.a(y)
x.b(y)
x.z(y)

Проблема заключается в том, что имя возвращает метод верхнего уровня, а не текущий. Я попробовал оба:

from inspect import stack
stack()[0][3]
import sys
sys._getframe().f_code.co_name

Но когда я называю b() или z(), я получаю 'a'. Я делаю что-то неправильно? Есть ли другой способ достижения аналогичного результата?

  • 0
    Почему бы просто не обернуть "do" новой функцией, которая принимает строковый аргумент?
Теги:
class

2 ответа

1
Лучший ответ

Вы просто устанавливаете все атрибуты b to z своего класса, чтобы указать на метод a. Это означает, что всякий раз, когда кто-то обращается к instance.b, он возвращает метод a (поэтому co_name всегда a).

Вы можете выполнить то, что хотите:

import string

class X(object):
  def __getattr__(self, name):
    if name in string.lowercase and len(name) == 1:
      def call_into_module(arg):
        return module.do(arg, name)
      return call_into_module

    return super(X, self).__getattr__(name)
  • 0
    Это именно то, что мне было нужно. Большое спасибо. Я понятия не имел, что могу переписать getattr
  • 0
    @Cameron: name in string.lowercase предназначено для проверки, является ли name одной строчной буквой? Это не так.
Показать ещё 4 комментария
3

Вы можете сделать что-то вроде

class X:
    pass
for name in "abcdefghij":
    setattr(X, name, lambda self, arg, _name=name: module.do(arg, _name))

Достаточно добавить методы в класс один раз - это не обязательно делать для каждого экземпляра в __init__().

Возможно, лучшей альтернативой является перезапись __getattr__():

class X:
    def __getattr__(self, name):
        def foo(arg):
            return module.do(arg, name)
        return foo
  • 0
    Второй вариант - это то, что я искал. Благодарю.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню