2016-12-13 6 views
1

У меня есть класс, как это:Это подходящее использование для декораторов?

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 

Но я не хочу, чтобы написать ту же логику для каждой из этих функций (возможно, есть очень многие из них).

Является ли это местом, где я мог бы использовать декоратор? Или есть другой способ добиться желаемого поведения?

+0

Так насколько доступным является 'err_df' вне каждого метода? Декоратор может получить доступ к глобальным переменным, 'self', входящим аргументам и возвращаемому значению, без проблем. Поэтому, если вы * вернули * 'err_df', то уверен, никаких проблем, декоратор может сделать это для вас. В противном случае просто используйте функцию. –

+0

Напишите метод, который принимает другой метод в качестве входных данных, вызывает его и форматирует результат по вашему желанию. – kindall

+0

Есть ли вероятность, что вы хотите получить данные из этих функций по другим причинам? Вы можете написать для этого отдельную функцию форматирования и передать ей результаты. Разделяйте логику программы из презентации. – tdelaney

ответ

2

Я бы не спешил декоратор что-то вроде этого, но, возможно, более общего метода

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) 

EDIT: Просто для удовольствия, версия для декоратора. Я был известен (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 
+0

Спасибо. Вероятно, это способ сделать это, но я просто хотел посмотреть, как это можно сделать с помощью декоратора. – user4601931

+0

Хотя ответ на ваш вопрос, вероятно, просто «нет», см. Мое редактирование для (непроверенной) реализации декоратора для этого варианта использования. Проблема с использованием декоратора, на мой взгляд, на самом деле не связана с функциональностью, а с большей удобочитаемостью и ремонтопригодностью кода. –

+1

Это справедливый вопрос. Я придумал примерно ваш 'print_error_info', но он ничего не делает. Украшение 'def id (df): return df' с' @ print_error_info' возвращает 'df' вместо' ["Ошибка в строке 0: ...", ...] '. – user4601931