我的问题是我使用元类将某些类方法包装在计时器中以进行日志记录。
例如:
class MyMeta(type):
@staticmethod
def time_method(method):
def __wrapper(self, *args, **kwargs):
start = time.time()
result = method(self, *args, **kwargs)
finish = time.time()
sys.stdout.write('instancemethod %s took %0.3f s.\n' %(
method.__name__, (finish - start)))
return result
return __wrapper
def __new__(cls, name, bases, attrs):
for attr in ['__init__', 'run']:
if not attr in attrs:
continue
attrs[attr] = cls.time_method(attrs[attr])
return super(MetaBuilderModule, cls).__new__(cls, name, bases, attrs)
我遇到的问题是我的包装器为每个'__init__'运行,即使我真的只想要它用于我实例化的当前模块。任何想要时间的方法都是如此。我不希望时间在任何继承的方法上运行,除非它们没有被覆盖。
class MyClass0(object):
__metaclass__ = MyMeta
def __init__(self):
pass
def run(self):
sys.stdout.write('running')
return True
class MyClass1(MyClass0):
def __init__(self): # I want this timed
MyClass0.__init__(self) # But not this.
pass
''' I need the inherited 'run' to be timed. '''
我尝试过一些事情,但到目前为止我还没有成功。
答案 0 :(得分:4)
使用属性保护计时代码。这样,只有对象上最外面的装饰方法才能实际获得定时。
@staticmethod
def time_method(method):
def __wrapper(self, *args, **kwargs):
if hasattr(self, '_being_timed'):
# We're being timed already; just run the method
return method(self, *args, **kwargs)
else:
# Not timed yet; run the timing code
self._being_timed = True # remember we're being timed
try:
start = time.time()
result = method(self, *args, **kwargs)
finish = time.time()
sys.stdout.write('instancemethod %s took %0.3f s.\n' %(
method.__name__, (finish - start)))
return result
finally:
# Done timing, reset to original state
del self._being_timed
return __wrapper
定时只有最外层的方法与“不定时继承的方法,除非它们没有被覆盖”略有不同,但我相信它可以解决你的问题。
答案 1 :(得分:1)
我不确定这与多重继承有什么关系。
麻烦的是MyClass0
的任何子类都必须是同一元类的实例,这意味着MyClass1
是用MyMeta.__new__
创建的,所以它的方法被处理并包装在时间码。
实际上,你需要的是MyClass0.__init__
在以下两种情况下以某种方式返回不同的东西:
MyClass0
,或MyClass1
不覆盖它时),需要返回定时方法这是不可能的,因为MyClass0.__init__
不知道为什么被调用。
我看到三个选项:
start_timing
和stop_timing
方法,如果在方法已经定时时调用start_timing
,你只需增加一个计数器,stop_timing
只减少一个计数器并且只停止计数器达到零时的计时。注意调用其他定时方法的定时方法;你需要为每个方法名称设置单独的计数器。