Python: обертывание вызовов метода с пред и методы сообщения

После добавления mavenCentral() и mavenLocal() в build.gradle это сработало.

allprojects {
    repositories {
        google()
        maven{ url 'https://maven.google.com'}
        jcenter()
        mavenCentral()
        mavenLocal()

    }
}
8
задан Ami Tavory 15 July 2017 в 10:46
поделиться

6 ответов

Вот решение I, и мои коллеги придумали:

from types import MethodType

class PrePostCaller:
    def __init__(self, other):
        self.other = other

    def pre(self): print 'pre'
    def post(self): print 'post'

    def __getattr__(self, name):
        if hasattr(self.other, name):
            func = getattr(self.other, name)
            return lambda *args, **kwargs: self._wrap(func, args, kwargs)
        raise AttributeError(name)

    def _wrap(self, func, args, kwargs):
        self.pre()
        if type(func) == MethodType:
            result = func( *args, **kwargs)
        else:
            result = func(self.other, *args, **kwargs)
        self.post()
        return result

#Examples of use
class Foo:
    def stuff(self):
        print 'stuff'

a = PrePostCaller(Foo())
a.stuff()

a = PrePostCaller([1,2,3])
print a.count()

Дает:

pre
stuff
post
pre
post
0

Таким образом, при создании экземпляра объекта, перенесите его с объектом PrePostCaller. После этого Вы продолжаете использовать объект, как будто это был экземпляр перенесенного объекта. С этим решением можно сделать обертывание на на основание экземпляра.

6
ответ дан 5 December 2019 в 17:42
поделиться

no-whistles-or-bells решение состояло бы в том, чтобы записать класс обертки для класса A, который делает просто это.

1
ответ дан 5 December 2019 в 17:42
поделиться

Вы могли просто изменить экземпляр и заменить функцию p1 функцией обертки:

def wrapped(pre, post, f):
    def wrapper(*args, **kwargs):
        pre()
        retval = f(*args, **kwargs)
        post()
        return retval
    return wrapper

class Y:
    def __init__(self):
        self.a=A()
        self.a.p1 = wrapped(self.pre, self.post, self.a.p1)

    def pre(self): print 'X.pre'
    def post(self): print 'X.post'
1
ответ дан 5 December 2019 в 17:42
поделиться

Как другие упомянули, решение для обертки/декоратора, вероятно, быть самым легким. Я не рекомендую изменить сам перенесенный класс по тем же причинам, что Вы указываете.

Если у Вас есть много внешних классов, можно записать генератор кода для генерации классов обертки для Вас. Так как Вы делаете это в Python, можно, вероятно, даже реализовать генератор как часть программы, генерировав обертки при запуске или чем-то.

1
ответ дан 5 December 2019 в 17:42
поделиться

Я только что недавно читал о декораторах в Python, я еще не понимаю их, но мне кажется, что они могут быть решением Вашей проблемы. посмотрите введение Bruce Eckel декораторам в: http://www.artima.com/weblogs/viewpost.jsp?thread=240808

У него есть еще несколько сообщений по той теме там.

Править: Три дня спустя я натыкаюсь на эту статью, которая показывает, как сделать подобную задачу без декораторов, что является проблемами с нею и затем представляет декораторов, и разработайте довольно полное решение: http://wordaligned.org/articles/echo

1
ответ дан 5 December 2019 в 17:42
поделиться

Вот то, что я получил от Steven D'Aprano на comp.lang.python.

# Define two decorator factories.
def precall(pre):
    def decorator(f):
        def newf(*args, **kwargs):
            pre()
            return f(*args, **kwargs)
        return newf
    return decorator

def postcall(post):
    def decorator(f):
        def newf(*args, **kwargs):
            x = f(*args, **kwargs)
            post()
            return x
        return newf
    return decorator

Теперь Вы можете класс A патча обезьяны, если Вы хотите. Это - вероятно, не прекрасная идея сделать это в производственном коде, поскольку это произведет класс A везде. [это хорошо для моего приложения, поскольку это - в основном преобразователь протокола и существует точно один экземпляр каждого обрабатываемого класса.]

class A:
    # in my real application, this is an imported class
    # that I cannot modify
    def p1(self): print 'A.p1'

class X:
    def __init__(self):
        self.a=A()
        A.p1 = precall(self.pre)(postcall(self.post)(A.p1))
    def pre(self): print 'X.pre'
    def post(self): print 'X.post'


x=X()
x.a.p1()

Дает желаемый результат.

X.pre
A.p1
X.post
0
ответ дан 5 December 2019 в 17:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: