Python __metaclass__继承问题
我的问题是,我正在使用一个元类来包装某些类的方法在一个计时器记录的目的。Python __metaclass__继承问题
例如:
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. '''
我试过一些东西,但到目前为止我没有成功。
用属性保护计时代码。这样,只有对象上最外面的装饰方法才会实际得到时间。
@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
计时只有最外层的方法比“除非他们没有被覆盖不定时继承的方法”略有不同,但我相信它可以解决你的问题。
我不确定这与多继承有什么关系。
麻烦的是,的MyClass0
任何子类必须是相同的元类,这意味着MyClass1
获取与MyMeta.__new__
创建的一个实例,因此它的方法得到处理和包裹在所述定时码。
实际上,你需要的是一个MyClass0.__init__
莫名其妙地返回的东西在下面两种情况下的不同:
- 当直接调用(实例
MyClass0
直接,或当MyClass1
不覆盖它),它需要返回定时方法 - 当一个子类定义中调用,它需要返回原来的不计时方法
这是不可能的,因为MyClass0.__init__
不知道为什么它被称为。
我看到三个选项:
- 让元类更复杂。它可以通过基类来检查它们是否已经是元类的实例;如果是这样,它可以创建它们的新副本,从正在构建的类中存在的方法中移除定时包装器。您不希望直接对基类进行变异,因为这会影响它们的使用(包括直接实例化或其他类覆盖不同方法的子类时)。它的缺点是它真的拧紧instanceof关系;除非你通过创建它们的新子类(ugh!)并缓存所有的变体来构造基类的细微变化,所以你永远不会构造重复项(ugh!),你完全无法自然假设两个类共享一个基类(它们可能只共享两个完全独立的基类生成的模板)。
- 使时间码更复杂。有一个
start_timing
和stop_timing
方法,并且如果start_timing
在方法已被定时时调用,则只需增加一个计数器,而stop_timing
只是递减一个计数器,并且只在计数器达到零时停止计时。注意调用其他定时方法的定时方法;您需要为每个方法名称分配不同的计数器。 - 放弃元类,只是在你想要显式定义的方法上使用装饰器,以某种方式获取undecorated方法,以便覆盖的定义可以调用它。这将涉及几行锅炉板每次使用;那很可能会比其他两个选项中的代码行少加起来。
感谢您的帮助,我将与第2号一起去。我希望尽可能让代码尽可能方便人们阅读,但仍然强制时间/日志记录发生,所以我觉得元类路由是最好的方式。使用装饰器依赖于继承/抽象类来实际装饰他们的方法的人,因为我必须假定只有基本的Python技能,所以尽可能自动化是最好的方式。再次感谢! CB – theceebee
谢谢佩特,这工作完美。我非常接近我能够品尝到的答案。有时你需要另一双眼睛来理解我所猜测的疯狂。再次感谢! CB – theceebee