# Support for using partial with positional only argument functions

**URL:** <https://discuss.python.org/t/support-for-using-partial-with-positional-only-argument-functions/9821>\
**Category:** Ideas\
**Created:** [July 23, 2021, 11:49am UTC](https://discuss.python.org/t/support-for-using-partial-with-positional-only-argument-functions/9821 "2021-07-23T11:49:51Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![mariocj89](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/mariocj89/32/487_2.png) [@mariocj89](https://discuss.python.org/u/mariocj89)\
**Post date:** [July 23, 2021, 11:49am UTC](https://discuss.python.org/t/support-for-using-partial-with-positional-only-argument-functions/9821/1 "2021-07-23T11:49:52Z")

</div>

I’d like to propose adding a way for functions that take positional only arguments to be used with `functools.partial`.

As an example, say you want to create a function that parses datetimes for a specific format.

Due to positional only arguments, the following will not work:

```auto
>>> functools.partial(datetime.datetime.strptime, format="%d %B, %Y")
>>> p("3 June, 2021")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: strptime() takes no keyword arguments

```

I’d like to add a `PLACEHOLDER` (similar to [c++ bind](https://en.cppreference.com/w/cpp/utility/functional/bind)) sentinel in partial that allows to use the `functools.partial` for positional only argument functions. Example:

```auto
from functools import partial
p = partial(
    datetime.datetime.strptime,
    partial.PLACEHOLDER,
    "%d %B, %Y"
)
p("3 June, 2019") # works as expected

```

With the introduction of PEP570, there are now even more functions that cannot be used with partiality due to the enforcement of positional arguments, making this even more useful IMHO.

I have a PoC [here](https://github.com/python/cpython/commit/c9fce92d98a72efff43b0dd2f21758463160d3c6) if you want to play with it for the Python part. If this is of interest I’ll create a bpo, add this to the extension as well and send a PR.

---

<div class="post-metadata">

**Author:** ![storchaka](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/storchaka/32/217_2.png) [@storchaka](https://discuss.python.org/u/storchaka)\
**Post date:** [July 23, 2021, 7:13pm UTC](https://discuss.python.org/t/support-for-using-partial-with-positional-only-argument-functions/9821/2 "2021-07-23T19:13:27Z")

</div>

You can use lambda:

```auto
p = lambda x: datetime.datetime.strptime(x, "%d %B, %Y")

```

---

<div class="post-metadata">

**Author:** ![mariocj89](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/mariocj89/32/487_2.png) [@mariocj89](https://discuss.python.org/u/mariocj89)\
**Post date:** [July 23, 2021, 8:04pm UTC](https://discuss.python.org/t/support-for-using-partial-with-positional-only-argument-functions/9821/3 "2021-07-23T20:04:30Z")

</div>

That is indeed what I am doing right now 😊, I guess it is also that I generally prefer partials over lambdas for this kind of case as I have seen people fall into cases like:

```python
from functools import partial
import datetime
format_ = "%d %B, %Y"
p = lambda datestr: datetime.datetime.strptime(datestr, format_)
format_ = None
print(p("3 June, 2019")) # Fails

```

Also, 100% subjective, it’s easier for me to read partials, as I know it is just the same functionality just binding arguments.  
If lambdas were a perfect solution for binding arguments there would not be partials at all, right?

---

<div class="post-metadata">

**Author:** ![steven.daprano](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/steven.daprano/32/1083_2.png) [@steven.daprano](https://discuss.python.org/u/steven.daprano)\
**Post date:** [August 9, 2021, 12:45pm UTC](https://discuss.python.org/t/support-for-using-partial-with-positional-only-argument-functions/9821/4 "2021-08-09T12:45:52Z")

</div>

Rather than adding a magical “PLACEHOLDER” sentinel value, another  
common solution is to define a version of partial that binds from the  
right rather than the left.

Here’s an untested implementation:

```auto
def partial_right(func, /, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = { **keywords,** fkeywords}
        return func(*fargs, *args, **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc

```

It is a one line change from the code given in the docs:

[https://docs.python.org/3/library/functools.html#functools.partial](https://docs.python.org/3/library/functools.html#functools.partial)

I don’t think this is a very common need. As far as I can tell, none of  
the major functional-programming languages that support partial  
application provide the functionality. Although that might be because  
their partial application are built on currying?

In any case, you are not the only one to request this sort of feature,  
at least in the Javascript world:

> <https://github.com/jashkenas/underscore/issues/1163>
>
> The current implementation of \`partial\` and \`bind\` allows arguments to be pre-su…pplied only from left to right. This misses the highly practical use case that it is the subject (the first argument) that we want to apply later. In fact, I would argue that supplying initial arguments later is more often the case than providing latter arguments later.
> 
> In my proposal for #1155 makes a good case for partial application where the subject is applied later. It would be useful if \`partial\` made it possible to curry designated arguments, vs. always having to pre-fill from left to right. Sugar.js offers a \`fill\` method that does exactly this. I propose the same feature be extended to underscore. To skip an argument for later application one would pass in a placeholder. Sugar.js uses \`undefined\` for this but we could use the underscore object itself (which makes a good placeholder).
> 
> \`\`\`
> \_.map(comedians, \_.partial(\_.pick, \_, 'name')) //explicit currying
> \_.map(comedians, \_.pick('name')) //implicit currying
> 
> \_.filter(comedians, \_.partial(\_.match, \_, {type: 'stooge'})) //explicit
> \_.filter(comedians, \_.match({type: 'stooge'})) //implicit
> \_.where(comedians, {type: 'stooge'}) //equivalent to the above
> 
> \_.filter(comedians, \_.partial(\_.has, \_, 'type'))
> \`\`\`
> 
> The implicit currying shown above is a carry over of the idea presented in #1155. The focus here is that this idea could be achieved without extending functions to curry themselves if \`partial\` is extended to allow for it.
> 
> Consider this code take from the underscore documentation.
> 
> \`\`\`
> var add = function(a, b) { return a + b; };
> add5 = \_.partial(add, 5);
> add5(10);
> \`\`\`
> 
> This example doesn't make it obvious that we are currying into the leftmost position because a 5 being passed to either \`a\` or \`b\` yields the same effect. For that reason, I would recommend supplying another example. A better example would be
> 
> \`\`\`
> var divide = function(a, b) { return a / b; };
> halve = \_.partial(divide, \_, 2);
> halve(10); // =\> 5
> twoDividedBy = \_.partial(divide, 2)
> twoDividedBy(.5) // =\> 4
> \`\`\`
> 
> because it illustrates that omitting the subject for later is a completely valid scenario. It also makes it clear (without reading any documentation) what got pre-filled and what got applied later.

> **[Selective partial application](https://glebbahmutov.com/blog////selective-partial-application/)**
>
> Sometimes we know values for some arguments to a function. JavaScript allows applying or binding these values to the function. The result is a new function that wraps around old function supplying all

---

<div class="post-metadata">

**Author:** ![elchupanebrej](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/elchupanebrej/32/13396_2.png) [@elchupanebrej](https://discuss.python.org/u/elchupanebrej)\
**Post date:** [July 10, 2023, 3:40pm UTC](https://discuss.python.org/t/support-for-using-partial-with-positional-only-argument-functions/9821/5 "2023-07-10T15:40:24Z")

</div>

[Functions — funcy 2.0 documentation](https://funcy.readthedocs.io/en/stable/funcs.html#rpartial) - is available in third-party tool  
[How to fill specific positional arguments with partial in python? - Stack Overflow](https://stackoverflow.com/questions/7811247/how-to-fill-specific-positional-arguments-with-partial-in-python) - another conversation with workarounds

---

<div class="post-metadata">

**Author:** ![elchupanebrej](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/elchupanebrej/32/13396_2.png) [@elchupanebrej](https://discuss.python.org/u/elchupanebrej)\
**Post date:** [July 10, 2023, 4:15pm UTC](https://discuss.python.org/t/support-for-using-partial-with-positional-only-argument-functions/9821/6 "2023-07-10T16:15:55Z")

</div>

Another approach how to implement such behavior:

Let’s assume partial\_positional:

```python
def partial_positional(func: Callable, *pos_args: Union[Tuple[int, Any], Tuple[slice, Iterable[Any]]])->Callable:
    ...

```

For _POSITIONAL\_ONLY_ or _POSITIONAL\_OR\_KEYWORD_ it applies default values for according parameters  
For _VAR\_POSITIONAL_ values are bound, but can’t be rebounded later

pos\_args: Tuple[int, Any] - index of positional arg and its value  
pos\_args: Tuple[slice, Iterable[Any]] - slice of pos\_args indexes and their values.  
pos\_args indexes must not be overlapped during one call of partial

---

<div class="post-metadata">

**Author:** ![Lancetnik](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/lancetnik/32/13698_2.png) [@Lancetnik](https://discuss.python.org/u/Lancetnik)\
**Post date:** [July 26, 2023, 5:39pm UTC](https://discuss.python.org/t/support-for-using-partial-with-positional-only-argument-functions/9821/7 "2023-07-26T17:39:42Z")

</div>

Looks great! It can be a very helpfull feature for rare cases then u need to use `partial` with unknown function. I have a production example in my [OSS project](https://github.com/Lancetnik/Propan/blob/v2/propan/broker/handler.py#L153)  
Also, `PLACEHOLDER` can be easely added and it costs nothing for the regular `partial` usage

```python
from functools import partial as p

class Placeholder:
    pass

class partial(p):
    def __call__ (self, /, *args, **keywords):
        i = 0
        final_args = []
        for partial_arg in self.args:
            if partial_arg == Placeholder:
                try:
                    final_args.append(args[i])
                except IndexError:
                    raise RuntimeError("not enough positional arguments to unpack")

                i += 1
            else:
                final_args.append(partial_arg)
        final_args.extend(args[i:])

        keywords = { **self.keywords,** keywords}
        return self.func(*final_args, **keywords)

```

It is just an example, I have an implementation, resolving in the ` __init__ ` method, not in runtime, but it still works in these cases:

```python
def func(a, b, c):
    return a + b + c

partial(func, 1, Placeholder, 3)(2) == 6
partial(func, Placeholder, 2)(1, 3) == 6
partial(func, Placeholder, Placeholder, 3)(1, b=2) # raises TypeError

```

---

<div class="post-metadata">

**Author:** ![Lancetnik](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/lancetnik/32/13698_2.png) [@Lancetnik](https://discuss.python.org/u/Lancetnik)\
**Post date:** [July 26, 2023, 5:42pm UTC](https://discuss.python.org/t/support-for-using-partial-with-positional-only-argument-functions/9821/8 "2023-07-26T17:42:41Z")

</div>

Well, ellepsis usage looks great. But why it is not the language feature?

---

<div class="post-metadata">

**Author:** ![chrisgrimm](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/chrisgrimm/32/8998_2.png) [@chrisgrimm](https://discuss.python.org/u/chrisgrimm)\
**Post date:** [July 27, 2023, 7:32pm UTC](https://discuss.python.org/t/support-for-using-partial-with-positional-only-argument-functions/9821/9 "2023-07-27T19:32:36Z")

</div>

> **[GitHub - chrisgrimm/better\_partial](https://github.com/chrisgrimm/better_partial)**
>
> Contribute to chrisgrimm/better\_partial development by creating an account on GitHub.
