Шаблон прокси в Python

У меня много классов, реализованных в моем коде. Теперь я понимаю, что для каждого метода, вызываемого для всех этих классов, мне нужно добавить строку:

with service as object:

Итак, я пытаюсь использовать шаблон Proxy для автоматического выполнения работы, это мой пример кода

class A(object):
    def __init__(self, name):
        self.name = name
    def hello(self):
        print 'hello %s!' % (self.name)
    def __enter__(self):
        print 'Enter the function'
        return self
    def __exit__(self, exc_type, exc_value, traceback):
        print 'Exit the function'
class Proxy(object):
    def __init__(self, object_a):
#        object.__setattr__(self, '_object_a', object_a)
        self._object_a = object_a

    def __getattribute__(self, name):
        service = object.__getattribute__(self, '_object_a')
        with service as service:
            result = getattr(service, name)
        return result    

if __name__=='__main__':
    a1 = A('A1')
    b = Proxy(a1)
    b.hello()
    a2 = A('A2')
    b = Proxy(a2)
    b.hello()

Все работает найти, у меня есть вывод:

Enter the function A1
Exit the function A1
hello A1!
Enter the function A2
Exit the function A2
hello A2!

Но это не совсем мне нужно, потому что мне нужен эквивалент:

with a1 as a1:
    a1.hello()

И я должен иметь вывод:

Enter the function A1
hello A1!
Exit the function A1
Enter the function A2
hello A2!
Exit the function A2

Что мне нужно для такого результата? Спасибо


person nam    schedule 07.03.2013    source источник
comment
Этот пример у меня не работает: 'NoneType' object has no attribute 'hello'.   -  person poke    schedule 07.03.2013
comment
Я не знаю, что, по вашему мнению, должно означать with a1 as a1, но здесь это определенно не имеет никакого смысла.   -  person danodonovan    schedule 07.03.2013
comment
Я думаю, что ваш __enter__ должен вернуть self  -  person poke    schedule 07.03.2013
comment
Да, моя ошибка, я добавил возврат в код, спасибо   -  person nam    schedule 07.03.2013


Ответы (2)


Я бы использовал декоратор:

class Proxy(object):
    def __init__(self, object_a):
        self._object_a = object_a

    def decorateEnterExit(self, obj, f):
        def inner(*args, **kwargs):
            with obj as _:
                return f(*args, **kwargs)
        return inner

    def __getattribute__(self, name):
        obj = object.__getattribute__(self, '_object_a')
        dee = object.__getattribute__(self, 'decorateEnterExit')
        return dee(obj, getattr(obj, name))

Таким образом, with будет оцениваться только при выполнении функции. То, как вы это сделали, сначала оценивало with (включая выход из него), а затем возвращалась функция для вызова. Теперь мы возвращаем функцию, которая сама войдет в with и вызовет функцию внутри.

>>> Proxy(A('Ax')).hello()
Enter the function
hello Ax!
Exit the function

Обратите внимание, что вам нужно вернуть self в методе __enter__ A:

def __enter__(self):
    print 'Enter the function'
    return self
person poke    schedule 07.03.2013

В вашем методе __enter__ отсутствует оператор return, который должен возвращать экземпляр вашего класса (self).

Что касается вопроса, в вашем Proxy, вероятно, результат оценивается после закрытия контекста. Попробуйте это, чтобы увидеть, что вы на самом деле возвращаете - это связанный метод:

def __getattribute__(self, name):
    service = object.__getattribute__(self, '_object_a')
    with service as service:
        result = getattr(service, name)
        print result
    return result

это покажет

Enter the function
<bound method A.hello of <__main__.A object at 0x022A2950>>
Exit the function

И только потом вызывается метод, после того как __getattribute__ вернул его.

person stachern    schedule 07.03.2013