如何在不重复父类每个方法的情况下,为Python子类中的每个方法添加延迟?
抱歉如果这个问题已经在其他地方被回答过,但我找不到答案。
我想创建一个子类,这个子类是从一个父类派生出来的。我的目标是在每次调用父类的方法之前,先有一个延迟(比如用 time.sleep()
)。我希望这样做,不需要在子类中重复每一个父类的方法。实际上,我想要一个通用的方法,能够适用于几乎任何父类,这样我甚至不需要知道所有父类的方法。
这个延迟的时间会在创建子类实例的时候指定。
举个例子:
class Parent():
....
def method1(self):
....
def method2(self):
....
class Child(Parent):
def __init__(self, delay)
self.delay = delay
....
child = Child(1)
当调用 child.method1()
时,会在调用 Parent.method1()
之前先延迟1秒。
4 个回答
S.Lott的解决方案很好。如果你需要更细致的控制(也就是说,只想延迟某些方法,而不是所有方法),你可以使用装饰器:
from time import sleep
def delayed(func):
'''This is the decorator'''
def wrapped(*args, **kwargs):
sleep(2)
func(*args, **kwargs)
return wrapped
class Example(object):
@delayed
def method(self, str):
print str
e = Example()
print "Brace! I'm delaying!"
e.method("I'm done!")
这个想法是,你在想要延迟的方法定义前面加上@delayed
。
补充:如果你想要更细致的控制:设置一个任意的延迟时间:
from time import sleep
def set_delay(seconds):
def delayed(func):
'''This is the decorator'''
def wrapped(*args, **kwargs):
sleep(seconds)
func(*args, **kwargs)
return wrapped
return delayed
class Example(object):
@set_delay(1)
def method(self, str):
print str
@set_delay(2)
def method_2(self, str):
print str
e = Example()
print "Brace! I'm delaying!"
e.method("I'm done!")
e.method_2("I'm also done!")
我觉得之前的回答没有真正解决你想要的需求,就是要延迟父类的所有方法,而不需要一个个去装饰它们。你提到你不想在子类中复制父类的方法,只是为了能延迟它们。这个答案使用了S.Lott提供的延迟包装器,同时还用到了元类(你可以查看这个链接了解更多:http://www.voidspace.org.uk/python/articles/metaclasses.shtml)
#!/usr/bin/env python
from types import FunctionType
import time
def MetaClassFactory(function):
class MetaClass(type):
def __new__(meta, classname, bases, classDict):
newClassDict = {}
for attributeName, attribute in classDict.items():
if type(attribute) == FunctionType:
attribute = function(attribute)
newClassDict[attributeName] = attribute
return type.__new__(meta, classname, bases, newClassDict)
return MetaClass
def delayed(func):
def wrapped(*args, **kwargs):
time.sleep(2)
func(*args, **kwargs)
return wrapped
Delayed = MetaClassFactory(delayed)
class MyClass(object):
__metaclass__ = Delayed
def a(self):
print 'foo'
def b(self):
print 'bar'
MetaClassFactory会把每个函数都包裹在延迟装饰器里。如果你想确保某些内置函数,比如init函数不被延迟,你只需要在MetaClassFactory中检查这个名字,然后忽略它就可以了。
其实,你这里的设计涉及到一个策略对象。
最好的办法是修改父类,让它包含一个“延迟对象”的调用。默认的延迟对象是不会做任何事情的。
这样做会违反“我甚至不需要知道所有父类的方法”这个理想的功能。
在方法查找中,没有一个方便的__getmethod__
,与__getattribute__
相对应;这个缺口让我们很难利用Python内部的机制来调用方法。
class Parent( object ):
delay= ZeroDelay()
def method1(self):
self.delay()
....
def method2(self):
self.delay()
...
class ZeroDelay( object ):
def __call__( self ):
pass
class ShortDelay( ZeroDelay ):
def __init__( self, duration=1.0 )
self.duration= duration
def __call__( self ):
time.sleep( self.duration )
class Child( Parent ):
delay= ShortDelay( 1 )
编辑:当然,你也可以给每个方法添加装饰器。
def delayed( delayer ):
def wrap( a_method ):
def do_delay( *args, **kw ):
delayer()
return a_method( *args, **kw )
return do_delay
return wrap
class Parent( object ):
delay= ZeroDelay()
@delayed( self.delay )
def method1(self):
self.delay()
....
@delayed( self.delay )
def method2(self):
self.delay()
...