Вы ищете способ динамически создавать несколько методов.Это часто не очень хорошая идея, но иногда это так.(Например, рассмотрим библиотеки, такие как PyObjC и pythoncom, которые создают динамические прокси для классов ObjC и COM, о которых вы даже не знаете до времени выполнения. Как еще вы могли бы это сделать?)
Итак, вы должны определенно подуматьчерез то, хотите ли вы этого и нуждаетесь ли вы в этом, но, если вы это сделаете, есть два основных подхода:
Динамическое создание статического класса
Если вы только пытаетесь свернуть коллекциюfoo
объектов, вы можете создавать все методы в цикле.Методы не являются чем-то слишком волшебным;вы просто определяете их так же, как и любую другую функцию, и назначаете их классу.
Единственный сложный момент в том, что вы не можете просто написать bar.f1 = …
, потому что f1
доступен только какстрока.Поэтому мы должны использовать setattr
, чтобы сделать это:
class bar:
# your existing stuff
for name in 'f1 f2 f3 f4 f5 f6 f7 f8'.split():
foometh = getattr(foo, name)
def f(self):
for foo in self.myfoos:
foometh(foo)
f.__name__ = name
setattr(bar, name, f)
Если есть какое-то правило, которое определяет, какие методы вы хотите переслать, вместо списка из множестваимена методов, вы бы сделали что-то вроде:
for name, foometh in inspect.getmembers(foo):
if name.startswith('_') or not isinstance(foometh, types.FunctionType)) or <rest of your rule>:
continue
def f(self):
# from here it's the same as above
Статическое построение динамического класса
Если вы пытаетесь завершить что-нибудь , которое соответствует некоторым базовым требованиямвместо какого-то определенного списка методов какого-то определенного класса вы не будете знать, что вы хотите свернуть, или как вы хотите это делать, пока кто-то не попытается вызвать эти методы.Таким образом, вы должны поймать попытку найти неизвестный метод и создать оболочку на лету.Для этого мы переопределяем __getattr__
:
class bar:
# your existing stuff
def __getattr__(self, attr):
if attr.startswith('_') or <other rules here>:
raise AttributeError
def f():
for foo in self.myfoos:
foometh(foo)
f.__name__ = attr
return f
Эта версия возвращает функции, которые действуют как связанные методы, если вы не смотрите слишком близко, вместо реальных связанных методов, которые могут бытьинтроспекции.Если вы хотите последнее, связывайте метод явно, добавив self
в качестве параметра к f
, а затем вызвав __get__
для f
и вернув результат.(И если вы не знаете, что это значит, вы не хотите писать эту часть ...)