我在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实例,因此如果我想通过*args和**kwargs挑战它们(例如自动验证目的),self属性的值是不相关的,举个例子:
@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
这两种解决方案对我来说似乎都不可能... 有人有关于如何解决这个问题的想法吗?有什么建议吗?
test
,而不必用5个装饰器重新装饰它!而且无论如何,那也解决不了我的问题:我从元类中包装方法的方式与使用装饰器完全相同。 - sebpiq