2011-07-21 59 views
8

我想用一个_wrap_run方法包装的run方法创建一个对象。我希望能够通过简单地输入instance.run()来调用方法和包装器,并且我希望能够对该对象进行子类化,以便我可以重写run()方法并让它仍然执行包装器。更简单地说,我希望人们能够继承A并重写run(),但仍然调用run()方法来执行包装函数。Python包装类方法

我对这个机制有一些困难。有没有人有关于这种方法的任何建议?谢谢阅读。

class A: 

    def run(self): 
     print "Run A" 
     return True 

    def _wrap_run(self): 
     print "PRE" 
     return_value = self.run() 
     print "POST" 
     return return_value 

    run = property(_wrap_run) 


a = A() 
a.run() 
""" 
Should Print: 
PRE 
Run A 
POST 
""" 


class B(A): 

    def run(self): 
     print "Run B" 
     return True 

b = B() 
b.run() 
""" 
Should Print: 
PRE 
Run B 
POST 
""" 
+1

'_wrap_run'有什么意义?这应该是某种装饰者?为此使用装饰器有什么问题? –

+1

他不想修饰所有的派生类。 – agf

回答

12

使用Metaclass。

class MetaClass(type): 
    @staticmethod 
    def wrap(run): 
     """Return a wrapped instance method""" 
     def outer(self): 
      print "PRE", 
      return_value = run(self) 
      print "POST" 
      return return_value 
     return outer 
    def __new__(cls, name, bases, attrs): 
     """If the class has a 'run' method, wrap it""" 
     if 'run' in attrs: 
      attrs['run'] = cls.wrap(attrs['run']) 
     return super(MetaClass, cls).__new__(cls, name, bases, attrs) 

class MyClass(object): 
    """Use MetaClass to make this class""" 
    __metaclass__ = MetaClass 
    def run(self): print 'RUN', 

myinstance = MyClass() 

# Prints PRE RUN POST 
myinstance.run() 

现在,如果其他人继承MyClass,他们仍然会得到他们的run()方法包裹。

+0

这是一个非常酷的方法,似乎很好地工作。 –

3

最简单的方法:使run包装,私人方法是可覆盖的方法。

class A(object): 
    def run(self): 
     print "PRE" 
     return_value = self._inner_run() 
     print "POST" 
     return return_value 

    def _inner_run(self): 
     print "Run A" 
     return True 

class B(A): 
    def _inner_run(self): 
     print "Run B" 
     return True 
+0

感谢您的评论。我想让它在子类中实现run()的人不必担心进行额外的调用,并依赖它们来正确添加函数调用。此外,下划线包装功能正在做一些维护工作,我想保持对子类的“隐藏”。虽然我不知道我的问题是否会起作用...... –

+0

@JoeJ:正确记录界面,如果子类必须重写'run'或别的东西,这并不重要。 –

+0

@Joe:让用户覆盖'_run'非常常见,例如[FormEncode'_to_python'](http://formencode.org/Validator.html?highlight=_to_python),而不是'run' – neurino

1

你有什么存在基本上是一个decorator,所以继承的功能时,为什么不继续前进,实现_wrap_run作为装饰,并运用它?

+0

我是考虑将装饰器制作出来,但有没有办法在父类中进行装饰,以便实现任何子类的人员不必每次都添加装饰器? –

+0

不,这是对什么python代表 –

+0

我认为这是__exactly__ Python代表什么。它与鸭子打字或上下文管理者有什么不同?我可以直接写'run()',元类负责处理细节。 – agf

1

什么其他人做

class A: 
    def do_run(self): 
     """Must be overridden.""" 
     raise NotImplementedError 
    def run(self, *args, **kw): 
     """Must not be overridden. 
     You were warned. 
     """ 
     print "PRE" 
     return_value = self.do_run(*args, **kw) 
     print "POST" 
     return return_value 

class B(A): 
    def do_run(self): 
     print "Run B" 
     return True 

这通常是足够的。

如果你想担心有人“打破”这一点,现在停下来。不要浪费时间担心。

这是Python。我们都是大人。所有恶意的反社会人员都会通过复制它,改变它,然后破坏它来破坏你的所有代码。无论你做什么,他们只会复制你的代码并修改它来打破聪明点。

其他人都会阅读你的评论,并坚持你的规则。如果他们想使用你的模块/包/框架,他们会合作。

+0

'run()'需要调用需要接受参数的'do_run()'。 – agf

+0

谢谢S.Lott。这看起来像是一种两极分化的做法。雅,我想一些好的评论就足够了。 –

+0

@Joe J:他们**都足够了。没有什么可以做的,真的。任何更复杂的事情都只是维修头痛。不管你写多少额外的代码,总有人总是会惹恼它。所以,写下你可以逃脱的最少代码。 –