Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can functools.partial be used to bind arbitrary positional arguments?

Tags:

python

Suppose you want to define a partial setting the positional arguments in an arbitrary order, i.e. you want to apply partial to str.split fixing the 2nd and 3th arguments. The desired result is the same as:

lambda s: str.rsplit(s, SEP, 1) # SEP given.

(I use str.rsplit(s... instead of s.rsplit(... to make the point more clear).

Some approximation using functools.partial is:

partial(str.rsplit, sep=SEP, maxsplit=1) # SEP given

But str.rsplit doesn't use keyword arguments, only positional.

How to fix those arguments in partial? Are the only choices lamda and wrappers?

wrappers are ugly if you want to define the function inline, like defining it for an argument wating for a function. Lambda is the defacto here, and partial is the other option, but it seems to lack in this case.

like image 565
jgomo3 Avatar asked Dec 27 '22 06:12

jgomo3


1 Answers

You can't do that with partial. This is because split uses the PyArg_ParseTuple function from the C API which doesn't provide keyword arguments. From the python's point of view it's like if the method was defined as:

def split(self, *args):
    if len(args) > 2:
        raise TypeError(...)
    sep = args[0] if args else None
    maxsplit = args[1] if len(args) > 1 else -1
    ...

Partial can only assign positional arguments in order. This is mentioned in the documentation, where they state that partial is "roughly equivalent to":

def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        return func(*(args + fargs), **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc

Note the return func(*(args + fargs), **newkeywords) which clearly shows that the arguments you pass to partial are prepended to other function arguments.

The conclusion is that lambda are simply more powerful than partial.

On a side note, in python3.3 you can specify maxsplit as keyword argument:

>>> 'some string with spaces'.split(maxsplit=2)
['some', 'string', 'with spaces']

And the same goes for many other methods/functions that had the same issue.

like image 129
Bakuriu Avatar answered Apr 12 '23 23:04

Bakuriu