6

I know there must be a way to do this. But I'm getting the error "TypeError: the first argument must be callable".

What could I do differently to make this work?

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')
Greg
  • 45,306
  • 89
  • 231
  • 297

3 Answers3

7

staticmethod objects are not callable. They're descriptors that keep references to original functions in their __func__ attributes.

So the following works:

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

You could also define a helper function in the class namespace, to avoid unnecessary attribute 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'))

Though the correct Python 3.4+ solution is to use the partialmethod, which was designed to work with descriptors:

fail_fax = partialmethod(load_fax, error='PC LOAD LETTER')
vaultah
  • 44,105
  • 12
  • 114
  • 143
3

methods and functions behave differently when "called": functions are called directly by using __call__ while methods (not generally methods, I think only descriptors) are called by __get__.

Therefore the functools-module contains another partial for methods: functools.partialmethod:

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

The official documentation contains a very good explanation especially in regard to staticmethod.

MSeifert
  • 145,886
  • 38
  • 333
  • 352
2

There's probably a smarter way to do it but this seems to work fine.

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')
Greg
  • 45,306
  • 89
  • 231
  • 297