代码之家  ›  专栏  ›  技术社区  ›  Philipp_Kats

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

  •  0
  • Philipp_Kats  · 技术社区  · 6 年前

    我有一个带模块的包裹 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
    

    现在,在我的生产代码(包装外)中,我想更改最小样本大小(最小尺寸),这样它将影响所有的装饰功能:在特定情况下,我可以使用最小尺寸=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 回复  |  直到 6 年前
        1
  •  1
  •   zondo L. Scott Johnson    6 年前

    到那时 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 . 当你想改变的时候 最小尺寸 ,只需更改类变量:

    minSample.MIN_SIZE = 0
    

    这样一来,装饰师就不会附在原作上了。 最小尺寸 ,但可以在整个代码中根据需要随时更新。您甚至可以更新单个函数:

    inventory.MIN_SIZE = 5
    
        2
  •  0
  •   Philipp_Kats    6 年前

    虽然上面的答案是绝对合法的,但我最终使用了带有附加参数的decorator,因为它看起来更透明。

    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