【问题标题】:changing package variable in order to change decorator behaviour更改包变量以更改装饰器行为
【发布时间】:2018-05-21 21:55:43
【问题描述】:

我有一个带有模块pymetrics.py的包:

from .utils import minSample
MIN_SIZE = 10


@minSample(MIN_SIZE)
def inventory(df):
    '''for quantisation'''
    return len(df)

(以及许多其他具有相同装饰器的指标)

...连同utils.py:

def minSample(sample=None):
    def decorator(method):
        @wraps(method)
        def f(*args, **kwargs):
            if len(args[0]) < sample:
                return None
            return method(*args, **kwargs)
        return f
    return decorator

现在,在我的生产代码(包外)中,我想更改最小样本大小 (MIN_SIZE),以便它影响所有修饰函数:在特定情况下,我可以使用 MIN_SIZE=0;

但是,我不知道该怎么做;

import pandas as pd
from package import pymetrics as mtr
mtr.MIN_SIZE = 0


test = pd.DataFrame({'price': [10, 20, 10], 'name': ['foo', 'bar', 'baz']})

mtr.inventory(test)
>>> None

【问题讨论】:

    标签: python python-3.x decorator


    【解决方案1】:

    import 行完成时,所有函数都已定义。改变MIN_SIZE已经太晚了。但是,您可以做的是改变定义装饰器的方式,以便它可以接受更改。例如,您可以将其设为一个类:

    class minSample:
        MIN_SIZE = 10
        def __init__(self, function):
            self.function = function
    
        def __call__(self, *args, **kwargs):
            ...
    

    在您的__call__ 方法中,您可以使用self.MIN_SIZEself.function 放置所有装饰器代码。当你想更改MIN_SIZE时,只需更改类变量即可:

    minSample.MIN_SIZE = 0
    

    通过这种方式,装饰器不会附加到原始MIN_SIZE,而是可以在整个代码中根据需要多次更新。您甚至可以更新单个函数:

    inventory.MIN_SIZE = 5
    

    【讨论】:

      【解决方案2】:

      虽然上面的答案绝对合法,但我最终还是使用了带有附加参数的装饰器,因为它似乎更透明

      def min_sample(f):
          @wraps(f)
          def new_f(df, *args, min_size=2, **kw):
                 if len(df) < min_size: return None
                 else: return f(df, *args, **kw)
          return new_f
      

      【讨论】:

        猜你喜欢
        • 2019-07-21
        • 2012-08-18
        • 2023-04-04
        • 1970-01-01
        • 2020-10-09
        • 2013-03-01
        • 2015-01-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多