python, класс-обёртка, возвращающий среднее значение обернутых членов - PullRequest
0 голосов
/ 22 марта 2010

Название не очень понятно, но я постараюсь объяснить.

Имея этот класс:

class Wrapped(object):
    def method_a(self):
        # do some operations
        return n

    def method_b(self):
        # also do some operations
        return n

Я хочу иметь класс, который работает так же, как этот:

class Wrapper(object):
    def __init__(self):
        self.ws = [Wrapped(1),Wrapped(2),Wrapped(3)]

    def method_a(self):
        results=[Wrapped.method_a(w) for w in self.ws]
        sum_ = sum(results,0.0)
        average = sum_/len(self.ws)
        return average

    def method_b(self):
        results=[Wrapped.method_b(w) for w in self.ws]
        sum_ = sum(results,0.0)
        average = sum_/len(self.ws)
        return average

Очевидно, что это не настоящая проблемапод рукой (это не только два метода), и этот код также неполон (включен только минимум для объяснения проблемы).

Итак, я ищу способ получить такое поведение.То есть, какой бы метод не вызывался в классе-обертке, вызовите этот метод для всех объектов класса Wrapped и верните среднее значение их результатов.

Можно ли это сделать?Как?

Заранее спасибо.

Редактировать
Спасибо за ответы ... увидев решение, все кажется очевидным :) Я выбрал АлексаОтвет Мартелли, потому что он хорошо объяснил решение.Другие ответы также полезны, поэтому я также проголосовал за них.

Ответы [ 4 ]

3 голосов
/ 22 марта 2010

Хотя это вполне выполнимо, это немного сложнее, потому что получение метода (или другого атрибута) и его вызов - это отдельные операции.Вот решение:

class Wrapper(object):
    def __init__(self):
        self.ws = [Wrapped(1),Wrapped(2),Wrapped(3)]

    def __getattr__(self, n):
        meth = getattr(Wrapped, n)
        def caller():
            results = [meth(w) for w in self.ws]
            sum_ = sum(results,0.0)
            average = sum_/len(self.ws)
            return average
        return caller

Это немного упрощенно (предполагается, что нет никаких изменений в self.ws между получением и вызовом - можно, конечно, «сделать снимок» self.ws в момент получения,если это желаемая семантика; не использует @functools.wraps, поэтому не сохраняет строку документации & c, если те нуждаются в сохранении), но должна быть в основном работоспособной для ваших целей.

1 голос
/ 22 марта 2010

Вы можете сделать это, реализовав метод __getattr__ в вашем Wrapper, который возвращает функцию, которая перенаправляет вызов всем обернутым объектам. Вот пример базовой реализации, просто возвращающей результаты:

import functools

class Wrapper(object):
    def __init__(self, *args):
        self._targets = args

    def _broadcast(self, name, *args, **kwargs):
        return [getattr(t, name)(*args, **kwargs) for t in self._targets]

    def __getattr__(self, name):
        return functools.partial(self._broadcast, name)

Обратите внимание, что __getattr__ будет вызываться только тогда, когда атрибут не найден, поэтому все имена методов, которые вы определили в Wrapper, не будут переадресованы (например, _broadcast в приведенном выше примере).

1 голос
/ 22 марта 2010

Вы можете сделать это (вызвать «произвольный» метод для объекта) с помощью getattr :

Рассмотрим это как пример:

# this fetches you references to the 'method_a' methods for objects in self.ws
funcs = [getattr(wrapped_obj, "method_a") for wrapped_obj in self.ws]
# now execute them to get the results
results = [func() for func in funcs]

Остальная часть вашего кода останется прежней.

0 голосов
/ 22 марта 2010

Вы можете сделать это, используя специальный метод getattr .

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