What you're doing is about as idiomatic as it can be. Some languages have a binary prefix operator named do
that invokes its argument:
generator = do <generator expression>
Python syntax just doesn't allow you to write multiline functions as expressions. You have to use def
statements. That's why you can't pass a multiline function or generator to a decorator using a regular invocation in Python either:
generator = decorator(def generator(): yield) # syntax error
You have to define the function or generator up front:
def generator(): yield
generator = decorator(generator)
It's mainly that syntactic limitation that forced Python to adopt the @
syntax for decorating functions that are defined with a def
statement. The following code is equivalent to the last example (aside from a subtle difference in when the names are assigned):
@decorator
def generator(): yield
As Greg mentioned, there are generator comprehensions, which work really nicely where you can use them, but if you need more logic in the body, then what you're doing seems like it would be the most Pythonic way. It's just that Python syntax always made functional programming quite clunky.
You asked in the comments about languages that have the do
operator. CoffeeScript and Haskell both have it. To be honest, I don't really understand anything the Haskell docs say, but in CoffeeScript, do
is useful for creating values within closures.
Take a look at this code (there's an explanation below).
updateElementText = do ->
element = jQuery "#someElement"
return (newText) -> element.text newText
Which would look like this in JS:
let updateElementText = function() {
let element = jQuery("#someElement");
return function(newText) { element.text(newText) };
}(); // Immediately-Invoked Function Expression (IIFE)
The code assigns updateElementText
to the function that's returned on Line 3, which references element
by closure. The element is only selected by jQuery once (on Line 2), no matter how many times updateElementText
is invoked to update the element. Also note that element
is hidden, so it can only be referenced by the function that updates it.