【问题标题】:Is this an appropriate use for decorators?这是装饰器的适当用途吗?
【发布时间】:2016-12-13 18:05:24
【问题描述】:

我有这样的课:

class MyClass(object):
    def __init__(self, name):
        self.name = name
        self.df = pd.read_table(name)

还有一堆这样的方法:

def valid_cond1(self):
    # check if cond1 is satisfied with respect to self.df and return
    # a DataFrame of rows not satisfying cond1   

def valid_cond2(self):
    # same deal

等等。最后,我想获取这些方法中的每一个的输出,然后将坏行的格式化列表返回给客户端。我可以通过像这样调整实现来为valid_cond1 做到这一点:

def valid_cond1(self):
    # err_df = rows of self.df not meeting cond1
    bad_lines = []
    for ix, val in err_df.iterrows():
        bad_lines.append("Error in line %s: %s.  Cond1 not met.." % (ix,val))
    return bad_lines

但我不想为这些函数中的每一个编写相同的逻辑(也许它们有很多)。

这是我可以使用装饰器的地方吗?还是有其他方法可以实现所需的行为?

【问题讨论】:

  • 那么err_df 在每种方法之外的可访问性如何?装饰器可以访问全局变量self、传入的参数和返回值,没问题。因此,如果您返回 err_df,那么当然,没问题,装饰者可以为您做到这一点。否则,只需使用一个函数。
  • 编写一个方法,将另一个方法作为输入,调用它,并根据需要格式化结果。
  • 您是否有可能出于其他原因想要这些函数的输出?您可以为此编写一个单独的格式化函数并将结果传递给它。将程序逻辑与表示分离。
  • @MartijnPieters 是的,每个方法都返回不同的err_df。那么装饰器理论上应该可以工作吗?我在实现一个时遇到了麻烦,因为valid_condn 方法采用可变数量的参数(也许我应该在问题中说明这一点)。还有可能吗?并不是说它比下面的答案更可取,我只是想看看它是如何完成的。
  • @tdelaney 这可能是解决问题的最佳方法。只是想看看装饰器的方法,如果可能的话。

标签: python decorator python-decorators


【解决方案1】:

我不会为这样的事情跳到装饰器,但也许是更通用的方法

def check_condition(self, condition):
    # check the condition
    return bad_lines  # etc.

def valid_cond1(self):
    # define condition_1
    return self.check_condition(condition_1)

def valid_cond2(self):
    return self.check_condition(condition_2)

如果你不能把条件变成简单的可以通过的东西,你可以这样做至少避免重复错误打印代码:

@staticmethod
def invalid_condition(err_df):
    # bad lines stuff here

def valid_cond1(self):
    # calculate err_df
    if err_df:
        return self.invalid_condition(err_df)

编辑:只是为了好玩,一个装饰器版本。我知道(ab)使用装饰器,所以我可以理解这种愿望:

from functools import wraps

def print_error_info(func):
    @wraps(func)
    def wrapped(*args, **kwargs):
        err_df = func(*args, **kwargs)
        bad_lines = []
        for ix, val in err_df.iterrows():
            bad_lines.append("Error in line %s: %s.  Cond1 not met.." % (ix,val))
        return bad_lines
    return wrapped

# use
class MyClass:
    # *snip*

    @print_error_info
    def valid_cond1(self):
        # whatever you need
        return err_df

【讨论】:

  • 谢谢。这可能是这样做的方法,但我只是想看看如何使用装饰器来完成。
  • 虽然您的问题的答案可能只是“否”,但请参阅我对这个用例的(未经测试的)装饰器实现的编辑。在我看来,这里使用装饰器的问题与功能无关,而更多地与代码的可读性和可维护性有关。
  • 这是一个公平的观点。我大致想出了你的print_error_info,但它似乎没有做任何事情。用@print_error_info 装饰def id(df): return df 会返回df 而不是["Error in line 0: ...", ...]
  • 我复制/粘贴了您的函数只是为了确保它不是那样的,并且结果相同。
  • 发现错误!它必须是@wraps(func)
猜你喜欢
  • 2011-10-23
  • 2016-09-04
  • 1970-01-01
  • 1970-01-01
  • 2016-11-25
  • 2011-09-08
  • 2011-07-20
  • 1970-01-01
  • 2011-02-17
相关资源
最近更新 更多