Метод Python украшения подкласс


Это подходящие для Python код?

def emit_decorator(method, signal_name):
    def decorated(self, *args, **kwargs):
        retval = method(self, *args, **kwargs)
        getattr(self, signal_name).emit()
        return retval
    return decorated

class Model(base.Transformer, Node):
    """
    Transformer subclass that implements the Model of the Model-View-Controller
    paradigm.
    """
    def __init__(self, *args, **kwargs):
        super(Model, self).__init__(*args, **kwargs)

    modelChanged = pyqtSignal()

    def create_view(self, parent=None):
        return View(self, parent)

for x in ('importance_changed',
          'evidence_changed',
          ):
    setattr(Model, x,
            emit_decorator(getattr(Model, x), 'modelChanged'))

Окончательный код декоратора:

from functools import update_wrapper

def method_emit_decorator(signal_name):
    def method_decorator(method):
        def decorated(self, *args, **kwargs):
            retval = method(self, *args, **kwargs)
            getattr(self, signal_name).emit()
            return retval
        return update_wrapper(decorated, method)
    return method_decorator

def class_emit_decorator(signal_name_to_method_names_dict):
    def class_decorator(cls):
        retval = cls
        for signal_name, method_names in (
            signal_name_to_method_names_dict.items()):
            for method_name in method_names:
                method = method_emit_decorator(signal_name)(
                    getattr(cls, method_name))
                setattr(retval, method_name, method)
        return retval
    return class_decorator


1147
5
задан 9 июня 2011 в 08:06 Источник Поделиться
Комментарии
1 ответ

Изменение класса после определения его запахи. То есть его не обязательно плохая идея, но нужно изучить возможные варианты, прежде чем прибегать к нему.

При "оформлении" функция следует использовать functools.обертывания оформителя. Это сделает декорированная функция больше похожа на оригинал.

Код, который вы заменяете выглядит так:

def importance_changed(self):
return_value = super(Model, self).importance_changed()
self.modelChanged.emit()
return return_value

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

Ваша функция emit_decorator не декоратор. Dectorators нужно взять ровно один аргумент (функции их упаковки) для использования с @синтаксис.

3
ответ дан 9 июня 2011 в 10:06 Источник Поделиться