#python #class
#python #класс
Вопрос:
Я пытаюсь написать оболочку для внешнего модуля на 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)
Проблема в том, что name возвращает метод верхнего уровня, а не текущий.
Я пробовал оба:
from inspect import stack
stack()[0][3]
import sys
sys._getframe().f_code.co_name
Но когда я вызываю b () или z () Я получаю ‘a’.
Я делаю что-то не так? Есть ли какой-либо другой способ добиться аналогичного результата?
Комментарии:
1. Почему бы просто не обернуть «do» новой функцией, которая принимает строковый аргумент?
Ответ №1:
Вы можете сделать что-то вроде
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
Комментарии:
1. Второй вариант — это то, что я искал. Спасибо.
Ответ №2:
Вы просто устанавливаете все атрибуты вашего класса 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)
Комментарии:
1. Это именно то, что мне было нужно. Большое вам спасибо. Я понятия не имел, что смогу перезаписать getattr
2. @Cameron:
name in string.lowercase
Предназначен для проверки,name
есть ли одна строчная буква? Это не так.3. @Sven: Лучше? Спасибо, что обратили на меня внимание по этому поводу 🙂
4. @Cameron: Я бы использовал
name.islower() and len(name) == 1
илиname in list(string.lowercase)
.a
,b
c
Именование методов в исходном сообщении в любом случае приведено только для примера, так что на самом деле это не имеет значения. SO предназначен для придирок, поэтому я не смог удержаться. 🙂5. @Cameron: ты делаешь
super
неправильно. Так и должно бытьsuper(X, self)
. Это важное различие, потому что смыслsuper
в том, что вам не нужно жестко кодировать суперклассы в коде при вызове их методов.