2016-04-28 9 views
4

Я знаю, что должен быть способ сделать это. Но я получаю сообщение об ошибке «TypeError: первый аргумент должен быть вызван».Python functools.partial - Как применить его к методу класса со статическим декоратором

Что я могу сделать по-другому, чтобы сделать эту работу?

class FaxMachine(object): 
    MODEL_NO = '100' 

    @staticmethod 
    def load_fax(fax, error=''): 
     # send fax here 

    fail_fax = functools.partial(load_fax, error='PC LOAD LETTER') 

ответ

2

staticmethod объекты не подлежат вызову. Это descriptors, которые содержат ссылки на оригинальные функции в своих атрибутах __func__.

Так следующие работы:

# Note: apply staticmethod again 
fail_fax = staticmethod(partial(load_fax.__func__, error='PC LOAD LETTER')) 

Вы также можете определить вспомогательную функцию в пространстве имен класса, чтобы избежать ненужной Lookups атрибутов:

def _load_fax(fax, error=''): 
    # ... 

# _load_fax is an ordinary function 
load_fax = staticmethod(_load_fax) 
fail_fax = staticmethod(partial(_load_fax, error='PC LOAD LETTER')) 

Хотя правильный Python 3.4+ решением является используйте partialmethod, который был разработан для работы с дескрипторами:

fail_fax = partialmethod(load_fax, error='PC LOAD LETTER') 
2

методы и функции ведут себя по-разному, когда «вызывается»: функции вызываются непосредственно с помощью __call__, тогда как методы (не как правило, методы, я думаю, только дескрипторы) вызываются __get__.

Поэтому functools модуль содержит другой partial для методов: functools.partialmethod:

functools.partialmethod(load_fax, error='PC LOAD LETTER') 

Официальная документация содержит очень хорошее объяснение, особенно в отношении staticmethod.

+0

Это только в Python 3? – Greg

+0

Похоже, что ['functools.partialmethod''] (https://docs.python.org/3.5/library/functools.html#functools.partialmethod) был введен в python 3.4. – MSeifert

2

Возможно, существует более разумный способ сделать это, но это, похоже, работает нормально.

import functools 

class FaxMachine(object): 
    MODEL_NO = '100' 

    @staticmethod 
    def load_fax(fax, error=''): 
     print error or fax 

FaxMachine.fail_fax = functools.partial(FaxMachine.load_fax, error='PC LOAD LETTER') 

f = FaxMachine() 
f.load_fax('hi') 
f.fail_fax('hi')