У меня есть проблема в Python, для которой я не могу найти никакого чистого решения ...
При вызове некоторых методов я хочу выполнить некоторый код до выполнения метода и после.Для того, чтобы (помимо всего прочего) автоматически установить и очистить переменную context
.
Для этого я объявил следующий метакласс:
class MyType(type):
def __new__(cls, name, bases, attrs):
#wraps the 'test' method to automate context management and other stuff
attrs['test'] = cls.other_wrapper(attrs['test'])
attrs['test'] = cls.context_wrapper(attrs['test'])
return super(MyType, cls).__new__(cls, name, bases, attrs)
@classmethod
def context_wrapper(cls, operation):
def _manage_context(self, *args, **kwargs):
#Sets the context to 'blabla' before the execution
self.context = 'blabla'
returned = operation(self, *args, **kwargs)
#Cleans the context after execution
self.context = None
return returned
return _manage_context
@classmethod
def other_wrapper(cls, operation):
def _wrapped(self, *args, **kwargs):
#DO something with self and *args and **kwargs
return operation(self, *args, **kwargs)
return _wrapped
Это работает следующим образомОчарование:
class Parent(object):
__metaclass__ = MyType
def test(self):
#Here the context is set:
print self.context #prints blabla
Но как только я хочу создать подкласс Parent
, возникают проблемы, когда я вызываю родительский метод с помощью super
:
class Child(Parent):
def test(self):
#Here the context is set too
print self.context #prints blabla
super(Child, self).test()
#But now the context is unset, because Parent.test is also wrapped by _manage_context
#so this prints 'None', which is not what was expected
print self.context
Я подумалсохранения контекста перед установкой его нового значения, но это только частично решает проблему ...
Действительно, (подождите, это трудно объяснить), вызывается родительский метод, оберткивыполняется, но они получают *args
и **kwargs
, адресованные Parent.test
, в то время как self
является экземпляром Child
, поэтому атрибуты self
имеют нерелевантные значения, если я хочу проверить их с помощью *args
и **kwargs
(например, для целей автоматической проверки), пример:
@classmethod
def validation_wrapper(cls, operation):
def _wrapped(self, *args, **kwargs):
#Validate the value of a kwarg
#But if this is executed because we called super(Child, self).test(...
#`self.some_minimum` will be `Child.some_minimum`, which is irrelevant
#considering that we called `Parent.test`
if not kwarg['some_arg'] > self.some_minimum:
raise ValueError('Validation failed')
return operation(self, *args, **kwargs)
return _wrapped
Таким образом, в основном, чтобы решить эту проблему, я вижу два решения:
, предотвращающих использование оболочеквыполняется, когда метод вызывается с super(Child, self)
с self
, который всегда имеет «правильный» тип
Оба решения кажутся мне невозможными ...у кого-нибудь есть идеи как это решить?Предложение?