def _inner_onchange(method):
        "A decorator that runs a method only when a generic metric changes."
        met_name = "_%s_last_metric" % id(method)
        res_name = "_%s_last_result" % id(method)
        def decorated(self, *args, **kwargs):
            try:
                mresult = metric(*args, **kwargs)
                if getattr(decorated, met_name)  != mresult:
                    setattr(decorated, met_name, mresult)
                    setattr(decorated, res_name, method(self, *args, **kwargs))
            except AttributeError:
                setattr(decorated, met_name, mresult)
                setattr(decorated, res_name, method(self, *args, **kwargs))

            return getattr(decorated, res_name)
        return decorated
A decorator that runs a method only when a generic metric changes.
recipes/Python/426620_only_on_change_decorator/recipe-426620.py