После добавления mavenCentral()
и mavenLocal()
в build.gradle
это сработало.
allprojects {
repositories {
google()
maven{ url 'https://maven.google.com'}
jcenter()
mavenCentral()
mavenLocal()
}
}
Вот решение 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. После этого Вы продолжаете использовать объект, как будто это был экземпляр перенесенного объекта. С этим решением можно сделать обертывание на на основание экземпляра.
no-whistles-or-bells решение состояло бы в том, чтобы записать класс обертки для класса A, который делает просто это.
Вы могли просто изменить экземпляр и заменить функцию 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'
Как другие упомянули, решение для обертки/декоратора, вероятно, быть самым легким. Я не рекомендую изменить сам перенесенный класс по тем же причинам, что Вы указываете.
Если у Вас есть много внешних классов, можно записать генератор кода для генерации классов обертки для Вас. Так как Вы делаете это в Python, можно, вероятно, даже реализовать генератор как часть программы, генерировав обертки при запуске или чем-то.
Я только что недавно читал о декораторах в Python, я еще не понимаю их, но мне кажется, что они могут быть решением Вашей проблемы. посмотрите введение Bruce Eckel декораторам в: http://www.artima.com/weblogs/viewpost.jsp?thread=240808
У него есть еще несколько сообщений по той теме там.
Править: Три дня спустя я натыкаюсь на эту статью, которая показывает, как сделать подобную задачу без декораторов, что является проблемами с нею и затем представляет декораторов, и разработайте довольно полное решение: http://wordaligned.org/articles/echo
Вот то, что я получил от 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