как построить методы динамически? - PullRequest
0 голосов
/ 26 мая 2018

Я разработал класс.Это довольно стандартно, с некоторыми атрибутами метода

class foo:
   def f1(self):
      print 'f1'
   def f2(self):
      print 'f2'
   ....
   def fn(self):
      print 'fn'

Теперь я хотел бы создать класс, который содержит набор экземпляров foo.

class bar:
  self.myfoos=[foo(),foo(),foo()]

Затем я бы хотел классифицироватьf1..fn методы на всех экземплярах foo.Я мог бы сделать:

   class bar:
   ...
   def f1():
     for foo_ in self.myfoos:
        foo_.f1()

Однако мой список f1..fn довольно длинный, так как я могу получить такое поведение лаконичным способом? Может быть, с альтернативным дизайном полностью?

Ответы [ 2 ]

0 голосов
/ 26 мая 2018

Вы можете просто реализовать __getattr__ и передать этот вызов списку foos.Я уверен, что есть более элегантный способ сделать это:

class foo:
    def f1(self):
        print('f1')
    def f2(self):
        print('f2')

class bar:
    def __init__(self):
        self.foos = [foo() for _ in range(3)]
    def __getattr__(self, fn):
        def fns(*args, **kwargs):
            for f in self.foos:
                getattr(f, fn)(*args, **kwargs)
        return fns

In []:
b = bar()
b.f1()

Out[]
f1
f1
f1

In []:
b.f2()

Out[]:
f2
f2
f2
0 голосов
/ 26 мая 2018

Вы ищете способ динамически создавать несколько методов.Это часто не очень хорошая идея, но иногда это так.(Например, рассмотрим библиотеки, такие как 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 и вернув результат.(И если вы не знаете, что это значит, вы не хотите писать эту часть ...)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...