我有一个包含模块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
答案 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_SIZE
和self.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