Метод Python Wrap Class - PullRequest
       10

Метод Python Wrap Class

11 голосов
/ 21 июля 2011

Я пытаюсь создать объект с методом run, который будет заключен в _wrap_run method.Я хотел бы иметь возможность вызывать метод и его оболочку, просто набрав 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
"""

Ответы [ 4 ]

14 голосов
/ 21 июля 2011

Используйте метакласс.

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() методами.

5 голосов
/ 21 июля 2011

Самый простой способ: сделать 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
1 голос
/ 21 июля 2011

Что делают другие люди

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.Мы все здесь взрослые.Все злые социопаты взломают весь ваш код, скопировав его, изменив, а затем разбив.Независимо от того, что вы делаете, они просто скопируют ваш код и изменят его, чтобы сломать умные биты.

Все остальные будут читать ваш комментарий и придерживаться ваших правил.Если они захотят использовать ваш модуль / пакет / инфраструктуру, они будут сотрудничать.

1 голос
/ 21 июля 2011

То, что у вас есть, это в основном декоратор , так почему бы не реализовать _wrap_run в качестве декоратора и применить его при создании подкласса функции?

...