我想用相同的包装器在Python中包装许多类方法.
从概念上讲,它在最简单的场景中看起来像这样:
x = 0 # some arbitrary context
class Base(object):
def a(self):
print "a x: %s" % x
def b(self):
print "b x: %s" % x
class MixinWithX(Base):
"""Wrap"""
def a(self):
global x
x = 1
super(MixinWithX, self).a()
x = 0
def b(self):
global x
x = 1
super(MixinWithX, self).a()
x = 0
Run Code Online (Sandbox Code Playgroud)
当然,当有更多的方法a
而且b
,这变得一团糟.似乎应该有更简单的东西.显然x
可以在装饰器中进行修改但是仍然有一个很长的垃圾列表,而不是上面的代码:
from functools import wraps
def withx(f):
@wraps(f) # good practice
def wrapped(*args, **kwargs):
global x
x = 1
f(*args, **kwargs)
x = 0
return wrapped
class MixinWithX(Base):
"""Wrap"""
@withx
def a(self):
super(MixinWithX, self).a()
@withx
def b(self):
super(MixinWithX, self).b()
Run Code Online (Sandbox Code Playgroud)
我想过使用__getattr__
在混合料搅拌,但由于方法比如课程的a
和b
已经被定义,这是永远不会被调用.
我也想过使用__getattribute__
但它返回属性,而不是包装调用.我想__getattribute__
可以返回一个闭包(下面的例子),但我不确定设计是多么合理.这是一个例子:
class MixinWithX(Base):
# a list of the methods of our parent class (Base) that are wrapped
wrapped = ['a', 'b']
# application of the wrapper around the methods specified
def __getattribute__(self, name):
original = object.__getattribute__(self, name)
if name in wrapped:
def wrapped(self, *args, **kwargs):
global x
x = 1 # in this example, a context manager would be handy.
ret = original(*args, **kwargs)
x = 0
return ret
return wrapped
return original
Run Code Online (Sandbox Code Playgroud)
在我看来,Python中可能有一些内容可能会减少手动重现要包装的父类的每个方法的需要.或者关闭__getattribute__
是正确的方法来做到这一点.我很感激你的想法.
这是我的尝试,它允许更简洁的语法......
x = 0 # some arbitrary context
# Define a simple function to return a wrapped class
def wrap_class(base, towrap):
class ClassWrapper(base):
def __getattribute__(self, name):
original = base.__getattribute__(self, name)
if name in towrap:
def func_wrapper(*args, **kwargs):
global x
x = 1
try:
return original(*args, **kwargs)
finally:
x = 0
return func_wrapper
return original
return ClassWrapper
# Our existing base class
class Base(object):
def a(self):
print "a x: %s" % x
def b(self):
print "b x: %s" % x
# Create a wrapped class in one line, without needing to define a new class
# for each class you want to wrap.
Wrapped = wrap_class(Base, ('a',))
# Now use it
m = Wrapped()
m.a()
m.b()
# ...or do it in one line...
m = wrap_class(Base, ('a',))()
Run Code Online (Sandbox Code Playgroud)
...输出...
a x: 1
b x: 0
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2394 次 |
最近记录: |