By reading this article you will understand what functools.Placeholder
is for and how to use it effectively.
The new Placeholder
, added in Python 3.14, only makes sense in the context of functools.partial
, so in order to understand Placeholder
you will need to understand how functools.partial
works and how to use it.
In a nutshell, partial
allows you to perform partial function application, by “freezing” arguments to functions.
functools.partial
Up until Python 3.13, you could use partial
to freeze arguments in two types of ways:
partial
, which would be passed in the same order to the function being used with partial
; orpartial
, which would be passed with the same name to the function being used with partial
.The method 2. is especially useful if you're trying to freeze an argument that is not the first one.
For example, if you use the built-in help
on the built-in int
, you can see this signature:
int(x, base=10) -> integer
If you want to convert a binary string to an integer, you can set base=2
:
print(int("101", 2)) # 5
Now, suppose you want to create a function from_binary
by “freezing” the argument 2
in the built-in int
.
Writing
from_binary = partial(int, 2)
won't work, since in partial(int, 2)
, the value 2
is seen as the argument x
from the signature above.
However, you can pass the base as a keyword argument, skipping the first argument x
from the signature of the built-in int
:
from functools import partial
from_binary = partial(int, base=2)
print(from_binary("101")) # 5
But this doesn't always work.
Consider the following function that uses the string methods maketrans
and translate
to strip punctuation from a string:
import string
_table = str.maketrans("", "", string.punctuation)
def remove_punctuation(string):
return string.translate(_table)
print(remove_punctuation("Hello, world!")) # Hello world
The function remove_punctuation
is a thin wrapper around the string method str.translate
, which is the function doing all the work.
In fact, if you look at str.translate
as a function, you always pass _table
as the second argument; what changes is the first argument:
print(str.translate("Hello, world!", _table)) # Hello world
print(str.translate("What?!", _table)) # What
This may lead you to wanting to use partial
to freeze the value _table
on the function str.translate
, so you use the built-in help
to check the signature of str.translate
:
translate(self, table, /) unbound builtins.str method
You can see that the first argument is self
, the string you are trying to translate, and then table
is the translation table (that str.maketrans
built magically for you).
But you can also see the forward slash /
, which means that self
and table
are positional-only arguments that cannot be passed in as keyword arguments!
As such, you cannot write the following code:
from functools import partial
import string
_table = str.maketrans("", "", string.punctuation)
remove_punctuation = partial(str.translate, table=_table)
print(remove_punctuation("Hello, world!"))
# TypeError: str.translate() takes no keyword arguments
But you also can't pass _table
as a position argument to partial
because the first argument must be the string to translate...
In a way, you want partial
to capture the pattern str.translate(???, _table)
...
And that's what functools.Placeholder
does.
functools.Placeholder
to reserve a place for an argumentThe new Placeholder
can be used exactly for this: to reserve a place for a positional argument that will only be filled later.
Using Python 3.14 (or later), you can write this code:
from functools import partial, Placeholder
import string
_table = str.maketrans("", "", string.punctuation)
remove_punctuation = partial(str.translate, Placeholder, _table) # <--
print(remove_punctuation("Hello, world!")) # Hello world
The key line is
remove_punctuation = partial(str.translate, Placeholder, _table) # <--
When you call remove_punctuation(string)
, partial
sees that you used a Placeholder
earlier and it puts the string in that place, turning it into str.translate(string, _table)
.
Note that Placeholder
is not a class you need to instantiate.
Instead, it's a singleton (like None
, for example) that you use directly whenever you need it.
Placeholder
a bit more ergonomicSince Placeholder
is quite a mouthful – or a “keyboard-ful”, maybe –, you may want to import Placeholder
with a shorter name.
For example, importing Placeholder as _
leads to usages of Placeholder
that look kind of neat:
from functools import partial, Placeholder as _
import string
_table = str.maketrans("", "", string.punctuation)
remove_punctuation = partial(str.translate, _, _table) # <--
print(remove_punctuation("Hello, world!")) # Hello world
Using a single underscore _
as shorthand for Placeholder
is dangerous, though, because _
is typically used as a throwaway variable and you'll shadow Placeholder
.
A more viable alternative is _P
, which is still pretty short.
From Python 3.14, you can use partial
with more functions and in more scenarios, specifically with functions that accept some arguments as positional-only.
In this article you saw an example of using Placeholder
with the string method str.translate
to create a function that removes punctuation from strings.
Get a daily drop of Python knowledge. A short, effective tip to start writing better Python code: more idiomatic, more effective, more efficient, with fewer bugs. Subscribe here.
functools.partial
, https://mathspp.com/blog/functools-partial [last accessed 22-08-2025];