There have been times when I needed to define functions and make them execute on-definition and not by calling later on. They’re called Immediately Invoked Functions or IIFs.
In Python, I satisfy it by doing the following trick and it works perfectly fine.
@lambda _:_()
def func():
...
I thought it would be a great idea to have a functools.invoke decorator that does the exact same thing.
It’s also worth noting that not all languages have built-in support for IIFs, but they can often be emulated with similar constructs. Also, IIFs may not look quite handy in 99% of situations. I know it.
Hey Karl. Thanks for your response. Respectfully, I believe that it’s pretty clean and readable. The reason we don’t call the function is more about the convention. It indicates that the function should be called once it’s defined. So instead of calling the function right after its definition…
def func():
...
func()
You specify its behavior by making it an IIF marked with some decoration keyword like @invoke or any other “more-descriptive” decorator name.
Actually, I always go with lambda as it’s a neat solution. Other than the need to define it in all the projects that you may need such functionality, your implementation is only supported on the functions with input parameters.
@invoke(1, 2, 3) # works fine :)
def func(a, b, c):
return a+b+c
But…
@invoke # not working :(
def func():
return "Hello there"
This case should be considered as well. That’s why the invoke decorator might have a quite complex structure, but handy at the same time.
It takes as many lines as the import would take With extra benefit of no import!
I never liked this behaviour of decorators, where it supports both with and without argument applications. To me it always seemed as unnecessary complexity.
Also, how do you make sure that it is called without arguements?
if len(args) == 1 and callable(args[0]) and not kwds:
What if my function has one argument, which is callable?
BTW, your lambda solution destroys the function. To remain it intact:
It’s possible to check the decorated function’s signature inside the decorator. I’m not talking about inspect or other modules. It’s possible to enforce the decoration process to be keyword-only. That way, we could define a None-default parameter which is responsible for checking if the first positional argument is the function itself or not.
def decorator(func=None, *, foo=..., bar=...):
if func is None: # means -> `@decorator(...)` pattern was used
...
else: # means -> `@decorator` pattern was used
...
The original message’s parameterless call is already satisfied by @operator.call (new in Python 3.11). No need for addition of functools.invoke().
I find this intuitive and use it for constants, e.g.
@operator.call
def fact10() -> int:
f = 1
for i in range(2, 11):
f *= i
return f
assert fact10 == 3_628_800
The situation with keyword parameters could be solved with @functools.partial(operator.call, **kwargs).
However, I find that non-intuitive and wouldn’t do it.
Like when? Why does the code need to be written as a function just to be executed once right away when you can simply execute the same code directly? Can you give a real-world example to illustrate when an IIF actually serves a purpose?
Note that as a decorator the function name isn’t yet assigned so it can’t even be useful for recursion.
I don’t have one (and don’t have time at the moment to dig) but I have definitely worked with code bases where the following pattern allows for encapsulation of an object that needs to be built once:
Another use case would be quickly-generating sentinels or singletons:
@operator.call
class Undefined:
def __repr__(self): return self.__class__.__name__
But as shown, this already exists, so I also don’t feel the need to go dig up real world examples. I do thank OP for prompting @Dutcho to show me something new!
It’s a simple form of namespace. However, when I’ve wanted this, I’ve wanted several different forms of it, including “call this now, but also leave the function for later”, and “replace this with the result of calling it”, which are incompatible. So on the occasions where I want this sort of thing, I generally write the decorator at the top of the program. (When I want it, I usually want it the same way for half a dozen functions in the same file.)
In addition, it’s a pretty useful and common convention in Javascript. I preferably use IIFs in Python to define my web app’s main function. Also as @Rosuav mentioned, there are cases where you need to keep that executed function in the bag for later use.
In Python, the equivalent of the JavaScript function keyword used to define a function inside an expression is lambda. Using lambdas for IIFE can be a quick solution to avoid shadowing any global variable.
JavaScript is my first programming language, so I naturally used IIFE until I learned that this isn’t how Python works. Coincidentally, even in JavaScript, I always use function expressions for simple expressions. I appreciate Python for not allowing yet another way to define functions.