Python 包装类方法

15 投票
5 回答
28890 浏览
提问于 2025-04-16 22:01

我想创建一个对象,这个对象里面有一个叫做 run 的方法,并且这个方法会被一个 _wrap_run 方法包裹起来。我希望能够通过简单地输入 instance.run() 来调用这个方法和它的包装器。同时,我还想能够对这个对象进行子类化,这样我就可以重写 run() 方法,但仍然能让它执行包装器的内容。

简单来说,我希望大家可以对 A 这个类进行子类化,并重写 run() 方法,但调用 run() 方法时仍然能执行包装器函数。

我在实现这个功能时遇到了一些困难。有没有人对此有建议?

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
"""

5 个回答

2

其他人是怎么做的

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。我们都是成年人。那些恶意的人会通过复制你的代码、修改它,然后把它搞坏。无论你做什么,他们都会复制你的代码,改动它来破坏那些聪明的部分。

其他人会看你的评论,并遵守你的规则。如果他们想使用你的模块、包或框架,他们会配合的。

5

最简单的方法是:让 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
26

使用元类。

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() 方法也会被自动处理。

撰写回答