更改包变量以更改装饰器行为

时间:2018-05-21 21:55:44

标签: python python-3.x decorator

我有一个包含模块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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

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

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