Декоратор унаследованного класса [дубликат]

  выберите Name, Value, AnotherColumn из out_pumptable, где Value = (выберите Max (Value) из out_pumptable как f, где f.Name = out_pumptable.Name), по имени, значению, AnotherColumn  

Попробуйте это, он работает.

4
задан Justin 17 September 2013 в 20:54
поделиться

1 ответ

Как было предложено в комментариях, использование подклассов вместо крючка вместо самого run было бы лучше всего:

class Task(object):
    def run(self):
        # before 
        self.do_run()
        # after

class MyTask(Task):
    def do_run(self):
        ...

task = MyTask()
task.run()

Однако это один из способов, которым вы могли сделайте это с помощью декоратора класса:

def decorate_run(cls):
    run = getattr(cls, 'run')
    def new_run(self):
        print('before')
        run(self)
        print('after')
    setattr(cls, 'run', new_run)
    return cls


class Task(object): pass

@decorate_run
class MyTask(Task):
    def run(self):
        pass

task = MyTask()
task.run()

# prints:
# before
# after

Еще один способ - использовать метакласс. Преимущество использования метакласса состояло бы в том, что подклассы не должны были быть украшены. Task можно было бы сделать экземпляром метакласса, а затем все подклассы Task автоматически наследуют метакласс.

class MetaTask(type):
    def __init__(cls, name, bases, clsdict):
        if 'run' in clsdict:
            def new_run(self):
                print('before')
                clsdict['run'](self)
                print('after')
            setattr(cls, 'run', new_run)

class Task(object, metaclass=MetaTask):
    # For Python2: remove metaclass=MetaTask above and uncomment below:
    # __metaclass__ = MetaTask
    pass

class MyTask(Task):
    def run(self):
        #successful override!
        pass

task = MyTask()
task.run()
7
ответ дан unutbu 15 August 2018 в 21:29
поделиться
  • 1
    Спасибо за метаклассический волшебный наконечник, вот о чем я действительно задумывался. Похоже, что у меня, вероятно, другие переопределят крючок, но очень полезно знать, что метаклассы являются опцией. Благодаря! – Justin 17 September 2013 в 21:21
  • 2
    Я всегда видел, что __new__ используется в метаклассах, а не __init__ - это получается намного чище. – Eric 17 September 2013 в 21:45
  • 3
    Причина, по которой __new__ существует в Python, заключается в том, что неизменяемые типы могут сохранять неизменность при разрешении подкласса. (Если бы не было __new__ и неизменяемых __init__, вы могли бы изменить значение неизменяемых, вызвав такие вещи, как math.pi.__init__(3.0)!) Поэтому я считаю, что вы должны зарезервировать __new__ только в тех ситуациях, когда вы хотите, чтобы экземпляры быть неизменным. – unutbu 17 September 2013 в 22:33
  • 4
    Пример метакласса - это именно то, что я ищу, но он не выглядит так, как предполагалось. Я не вижу print before или after. Что мне не хватает? – Jørgen 5 September 2017 в 15:38
  • 5
    @ Jørgen: Синтаксис для объявления метакласса изменился между Python2 и Python3. Если вы используете Python3, добавьте metaclass=MetaTask в объявление базы классов. Я отредактировал сообщение выше, чтобы показать, что я имею в виду. – unutbu 5 September 2017 в 15:46
Другие вопросы по тегам:

Похожие вопросы: