Python:使用类来处理方法调用,就像类属性是方法参数一样

时间:2014-03-07 21:58:17

标签: python

我的黑客解决方案如下。我非常欢迎你的评论。


我有一个类,它在指定的时间范围内(称为PerformanceAnalysisMixin)处理给定对象组的性能计算。例如:

class PerformanceAnalysisMixin(object):
    def set_time_frame(self, time_frame):
        sets up time frame and sources related info

    def return_over_time_frame(self, time_frame='past_year', values_only=False):
        return value if values_only else return ('ABC', values)

class Performance(object):
    # a mythical object which returns the values of calls to
    # PerformanceAnalyisMixin() as if they were properties
    # where the calls in are the form: name_for_method.arg0.arg1

>>> pam = PerformanceAnalysisMixin()
>>> pam.set_time_frame((2010, 2013))  # data for the past three years
>>> pam.return_over_time_frame('past_year', values_only=True)
0.13
>>> pam.return_over_time_frame('past_3_years', values_only=True)
0.25

我希望能够以非常惯用的方式调用结果,而不是针对类实例的方法。例如:

>>> perf = Performance(pam)
>>> # 'time_frame_return' is the name for the method 'return_over_time_frame'
>>> perf.time_frame_return.past_year
0.13
>>> perf.time_frame_return.past_3_years
0.25

如果只有几个方法和几个默认时间帧,这将很容易硬编码,但我希望有足够的抽象,所以我不需要编写许多排列。我想使用属性调用为最终方法调用指定适当的参数。

在我开始创建这种类型的解决方案之前,我正在寻找指导。如果我愿意的话,我可以预先填充一个字典,但我宁愿在运行时调用该方法。

我的黑客攻击解决方案:

class F(object):
    def __init__(self, name, fn=None):
        self.name = name
        self.arg_names = [self.name]
        self.fn = fn

    def __getattr__(self, key):
        self.key = F(key)
        self.arg_names.append(self.key.name)

        if key == 'res':
            _res = self.fn(*self.arg_names[:-1])
            self.res = _res
            return _res

        return self

>>> f = F('get', fn=(lambda a, b, c, d: (a, b, c, d)))
>>> r = f.some.more.stuff
>>> r.res
('get', 'some', 'more', 'stuff')
>>> g = F('one', fn=(lambda a, b, c, d: (a, b, c, d)))
>>> g.more.time.ftw.res
('one', 'more', 'time', 'ftw')

2 个答案:

答案 0 :(得分:1)

您可以执行以下操作:

class MapProperty2Argument(object):
    def __init__(self, fn):
        self.fn = fn

    def __getattr__(self, name):
        return self.fn(name)

class Performance(object):
    @property
    def time_frame_return(self):
        return MapProperty2Argument(
            PerformanceAnalysisMixin().return_over_time_frame)

当然,您可能不希望为每个函数调用创建PerformanceAnalysisMixin对象,但需要一些现有的实例。

答案 1 :(得分:1)

我想你想沿着这些方向做点什么:

class PamSugar(object):
    """ Here be dragons """
    def __init__(self, pam):
        self.pam = pam

    def __getattr__(self, key):
        # will be called if the key attribute is not found in usual places
        # http://docs.python.org/2/reference/datamodel.html#object.__getattr__

        # Better make sure key is allowed (you have to define the sanitizer)
        if not is_good_property_name(key):
            raise AttributeError("Can't handle that")

        return self.pam.return_over_time_frame(key, values_only=True)

class Performance(object):
    """ perf.sugar.past_year """
    def __init__(self, pam):
        self.sugar = PamSugar(pam)