让我们假设我有一个A类,它有一堆方法,但是我希望它在调用每个方法之前和之后运行某些行。 例如:我希望我的类Dog在每次调用bark()或run()之前运行before()和after()。
class Dog():
def __init__(self, sound, speed):
self.sound = sound
self.speed = speed
def before(self):
check_some_things(self)
def after(self):
do_some_things(self)
def bark(self):
sound(self.sound)
def run(self):
move(self.speed)
答案 0 :(得分:4)
您可以将其封装在装饰器中;以下装饰者会调用before
和after
,如果self
上有这些内容:
import inspect
from functools import wraps
def before_and_after(f):
@wraps(f)
def wrapper(self, *args, **kw):
if hasattr(self, 'before') and inspect.ismethod(self.before):
self.before()
result = f(self, *args, **kw)
if hasattr(self, 'after') and inspect.ismethod(self.after):
self.after()
return result
return wrapper
然后简单地应用于应该包装的方法:
class Dog():
def __init__(self, sound, speed):
self.sound = sound
self.speed = speed
def before(self):
check_some_things(self)
def after(self):
do_some_things(self)
@before_and_after
def bark(self):
sound(self.sound)
@before_and_after
def run(self):
move(self.speed)
装饰者假定它用于方法,例如生成的包装器期望self
作为第一个参数。
如果这需要适用于非before
或after
的所有方法,则可能会按顺序使用元类:
class BeforeAfterMeta(type):
def __new__(mcs, classname, bases, body):
for name, value in body.items():
if not inspect.isfunction(value):
continue
if name in ('before', 'after') or name[:2] + name[-2:] == '_' * 4:
# before or after hook, or a special method name like __init__.
continue
body[name] = before_and_after(value)
return super(BeforeAfterMeta, mcs).__new__(mcs, classname, bases, body)
然后你可以申请你的班级:
class Dog(metaclass=BeforeAfterMeta):
def __init__(self, sound, speed):
self.sound = sound
self.speed = speed
def before(self):
check_some_things(self)
def after(self):
do_some_things(self)
def bark(self):
sound(self.sound)
def run(self):
move(self.speed)
答案 1 :(得分:2)
如果pre和post方法存在,您还可以使用装饰器功能检查class Dog
并覆盖run
方法:
def PrePostMethod(inputClass):
mainRun = inputClass.run
beforeFunc = inputClass.before if "before" in inputClass.__dict__ else None
afterFunc = inputClass.after if "after" in inputClass.__dict__ else None
def new_run(self, *args, **kwargs):
# you could inspect the given arguments if you need
# to parse arguments into before and the after methods
if beforeFunc:
self.before()
mainRun(self)
if afterFunc:
self.after()
inputClass.run = new_run
return inputClass
@PrePostMethod
class Dog(object):
def __init__(self, sound, speed):
self.sound = sound
self.speed = speed
def before(self):
print "Do stuff before"
def after(self):
print "Do stuff after"
def run(self):
print "Do main process"
Dog(1,2).run()
要将run
中的参数和关键字参数解析为before
和after
,请使用类inspect
并循环遍历args和kwargs来解析正确的参数。
from inspect import getargspec
def argHandler(method, *args, **kwargs):
method = getargspec(method)
mArgs = method.args
mKwargs = method.keywords
rArgs = args[:len(mArgs)-1]
rKwargs = { k:v for k,v in kwargs.iteritems() if k in mKwargs }
leftArgs = len(mArgs)-len(rArgs)
if len(rKwargs):
rKwargs = [ rKwargs[k] for k in mArgs[:leftArgs-1]]
rArgs += rKwargs
return rArgs
def PrePostMethod(inputClass):
mainRun = inputClass.run
beforeFunc = inputClass.before if "before" in inputClass.__dict__ else None
afterFunc = inputClass.after if "after" in inputClass.__dict__ else None
def new_run(self, *args, **kwargs):
if beforeFunc:
nargs = argHandler(self.before, *args, **kwargs)
if nargs: self.before( *nargs)
else: self.before()
nargs = argHandler(mainRun, *args, **kwargs)
if nargs: mainRun(self, *nargs)
else: mainRun(self)
if afterFunc:
nargs = argHandler(self.after, *args, **kwargs)
if nargs: self.after( *nargs)
else: self.after()
inputClass.run = new_run
return inputClass
答案 2 :(得分:0)
您可以使用许多不同的方法来执行此操作。但我认为最好的方法是,使用前后方法定义一个类,并重新定义它的对象隐藏方法:__enter__
和__exit__
。要使用它们,只需使用复合语句with
调用该类。
class pre_post(object):
def __enter__(self):
print "Enter check method.."
def __exit__(self, type, value, tb):
print "Exit check method.."
class dog(object):
def run(self, checkups=True):
if checkups:
with pre_post() as pp:
print "My stuff.."
else:
print "My stuff.."
dog().run(True)
这会给你以下结果:
Enter check method..
My stuff..
Exit check method..
我希望这会对你有帮助。