Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python functools.partial - How to apply it to a class method with the static decorator

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')
like image 219
Greg Avatar asked Jan 06 '23 04:01

Greg


2 Answers

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')
like image 173
vaultah Avatar answered Jan 08 '23 18:01

vaultah


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.

like image 21
MSeifert Avatar answered Jan 08 '23 18:01

MSeifert