2015-02-09 2 views
4

В моем коде у меня есть класс, где один метод отвечает за фильтрацию некоторых данных. Чтобы разрешить настройку для потомков Я хотел бы определить функцию фильтрации в качестве атрибута класса, как на ниже:Как сохранить функцию в атрибуте класса?

def my_filter_func(x): 
    return x % 2 == 0 

class FilterClass(object): 

    filter_func = my_filter_func 

    def filter_data(self, data): 
     return filter(self.filter_func, data) 

class FilterClassDescendant(FilterClass): 

    filter_func = my_filter_func2 

Однако такой код приводит к TypeError, поскольку filter_func получает «себя» в качестве первого аргумента. Что такое pythonic способ обработки таких прецедентов? Возможно, я должен определить свой фильтр filter_func как обычный метод класса?

+0

Если ему не нужны атрибуты экземпляра/класса, вы можете сделать его '@ staticmethod'. – jonrsharpe

+0

перефразируйте свой вопрос, как перезаписать функции класса в классах потомков? Проверьте эту статью http://lgiordani.com/blog/2014/05/19/method-overriding-in-python/ – AzaFromKaza

ответ

4

Вы могли бы просто добавить его как простой старый атрибут?

def my_filter_func(x): 
    return x % 2 == 0 

class FilterClass(object): 

    def __init__(self): 
     self.filter_func = my_filter_func 

    def filter_data(self, data): 
     return filter(self.filter_func, data) 

С другой стороны, заставить его быть STATICMETHOD:

def my_filter_func(x): 
    return x % 2 == 0 

class FilterClass(object): 

    filter_func = staticmethod(my_filter_func) 

    def filter_data(self, data): 
     return filter(self.filter_func, data) 
2

Python имеет много магии внутри. Одна из этих магий имеет какое-то отношение к преобразованию функций в объекты UnboundMethod (при присвоении классу, а не экземпляру класса).

Когда вы назначаете функцию (И я не уверен, относится ли она к любым вызываемым или справедливым функциям), Python преобразует ее в объект UnboundMethod (т. Е. Объект, который можно вызвать с помощью экземпляра или нет).

В нормальных условиях, вы можете позвонить UnboundMethod как обычно:

def myfunction(a, b): 
    return a + b 

class A(object): 
    a = myfunction 

A.a(1, 2) 
#prints 3 

Это не подведет. Тем не менее, есть отличный случай, когда вы пытаетесь вызвать его из экземпляра:

A().a(1, 2) 

Это потерпит неудачу, поскольку, когда экземпляр получает (скажем, внутренний getattr) атрибут, который является UnboundMethod, он возвращает копию таких метод с im_self членом, населенным (im_self и im_func являются членами UnboundMethod). Функция, которую вы намеревались вызвать, находится в элементе im_func. Когда вы вызываете этот метод, вы на самом деле вызываете im_func с, дополнительно, значением в im_self. Таким образом, функции требуется дополнительный параметр (первый, который будет стоять за себя).

Чтобы избежать этой магии, Python имеет два возможных декоратор:

  • Если вы хотите передать функцию как есть, вы должны использовать @staticmethod. В этом случае у вас будет функция, не преобразованная в UnboundMethod. Однако вы не сможете получить доступ к вызывающему классу, за исключением глобальной ссылки.
  • Если вы хотите иметь то же самое, но иметь доступ к текущему классу (независимо от того, вызвана ли функция из экземпляра или из класса), ваша функция должна иметь другой первый аргумент (INSTEAD of self: cls), который является ссылкой на класс, а декоратор для использования - @classmethod.

Примеры:

class A(object): 
    a = staticmethod(lambda a, b: a + b) 

A.a(1, 2) 
A().a(1, 2) 

Оба будут работать.

Другой пример:

def add_print(cls, a, b): 
    print cls.__name__ 
    return a + b 

class A(object): 
    ap = classmethod(add_print) 

class B(A): 
    pass 

A.ap(1, 2) 
B.ap(1, 2) 
A().ap(1, 2) 
B().ap(1, 2) 

Проверить это, yourseld и пользоваться магией.

Смежные вопросы