Use def instead.
def d(x):
if x:
return 1
else:
return 2
All python functions are first order objects (they can be assigned to variables and passed around as arguments), lambda is just a convenient way to make short ones. In general, you are better off using a normal function definition if it becomes anything beyond one line of simple code.
Even then, in fact, if you are assigning it to a name, I would always use def over lambda (something PEP 8 explicitly recommends as it improves debugging). lambda is really only a good idea when defining short functions that can be placed inline into the function call, for example key functions for use with sorted().
Note that, in your case, a ternary operator would do the job (lambda x: 1 if x else 2), but I'm presuming this is a simplified case and you are talking about cases where it's not reasonable to use a single expression.
(As a code golf note, this could also be done in less code as lambda x: 2-bool(x) - of course, that's highly unreadable and a bad idea.)
Use def instead.
def d(x):
if x:
return 1
else:
return 2
All python functions are first order objects (they can be assigned to variables and passed around as arguments), lambda is just a convenient way to make short ones. In general, you are better off using a normal function definition if it becomes anything beyond one line of simple code.
Even then, in fact, if you are assigning it to a name, I would always use def over lambda (something PEP 8 explicitly recommends as it improves debugging). lambda is really only a good idea when defining short functions that can be placed inline into the function call, for example key functions for use with sorted().
Note that, in your case, a ternary operator would do the job (lambda x: 1 if x else 2), but I'm presuming this is a simplified case and you are talking about cases where it's not reasonable to use a single expression.
(As a code golf note, this could also be done in less code as lambda x: 2-bool(x) - of course, that's highly unreadable and a bad idea.)
lambda construct in Python is limited to an expression only, no statements are allowed
While keeping the above mentioned constraint, you can write an expression with multiple lines using backslash char, of course:
>>> fn = lambda x: 1 if x \
else 2
>>> fn(True)
>>> 1
>>> fn(False)
>>> 2
Guido van Rossum (the inventor of Python) answers this exact question himself in an old blog post.
Basically, he admits that it's theoretically possible, but that any proposed solution would be un-Pythonic:
"But the complexity of any proposed solution for this puzzle is immense, to me: it requires the parser (or more precisely, the lexer) to be able to switch back and forth between indent-sensitive and indent-insensitive modes, keeping a stack of previous modes and indentation level. Technically that can all be solved (there's already a stack of indentation levels that could be generalized). But none of that takes away my gut feeling that it is all an elaborate Rube Goldberg contraption."
Look at the following:
map(multilambda x:
y=x+1
return y
, [1,2,3])
Is this a lambda returning (y, [1,2,3]) (thus map only gets one parameter, resulting in an error)? Or does it return y? Or is it a syntax error, because the comma on the new line is misplaced? How would Python know what you want?
Within the parens, indentation doesn't matter to python, so you can't unambiguously work with multilines.
This is just a simple one, there's probably more examples.
multi line lambdas, as god intended
Why doesn't Python allow multi-line lambdas? - Software Engineering Stack Exchange
syntax - How can multiline lambdas be designed in indent based languages? - Programming Language Design and Implementation Stack Exchange
c# - Python multiline lambda - Stack Overflow
4 parallel universes ahead of the linter
codec abuse, part 2. https://github.com/dankeyy/superlambda.py
gl hf hope you like it
Guido van van Rossum answered it himself:
But such solutions often lack "Pythonicity" -- that elusive trait of a good Python feature. It's impossible to express Pythonicity as a hard constraint. Even the Zen of Python doesn't translate into a simple test of Pythonicity...
In the example above, it's easy to find the Achilles heel of the proposed solution: the double colon, while indeed syntactically unambiguous (one of the "puzzle constraints"), is completely arbitrary and doesn't resemble anything else in Python...
But I'm rejecting that too, because in the end (and this is where I admit to unintentionally misleading the submitter) I find any solution unacceptable that embeds an indentation-based block in the middle of an expression. Since I find alternative syntax for statement grouping (e.g. braces or begin/end keywords) equally unacceptable, this pretty much makes a multi-line lambda an unsolvable puzzle.
http://www.artima.com/weblogs/viewpost.jsp?thread=147358
Basically, he says that although a solution is possible, it's not congruent with how Python is.
it's perfectly fine to do a multi line lambda in python: see
>>> f = lambda x: (
... x**x)
>>> f
<function <lambda> at 0x7f95d8f85488>
>>> f(3)
27
the real lambda limitation is the fact that lambda must be a single expression; it can't contains keyword (like python2's print or return).
GvR choose to do so to limit the size of the lambda, as they normally are used as parameters.
If you want a real function, use def
In "indent-based languages" such as Python, indentation is needed at the statement level to determine the nesting of blocks. On the other hand, the nesting of expressions is defined without reference to indentation or any other whitespace, so there is no need to enforce any rules about indentation at the expression level, and arbitrary indentation is allowed when splitting expressions across multiple lines, either using backslash \ to ignore a line ending or writing inside brackets.
Both of these can be implemented directly in the lexer:
- Recognise
\\\n\s*(i.e. a literal backslash followed by a newline followed by any whitespace) as a whitespace token. It will then be ignored when parsing the expression, just like any other whitespace, and it won't get processed by the algorithm which tracks indentation at newlines because the newline character is part of the token. - The lexer counts the nesting level of brackets (increment a counter on each
(,[or{token, decrement on),]or}), and the algorithm which tracks indentation and insertsINDENTandDEDENTtokens ignores newlines when the counter is greater than zero. (A simple counter is enough, because if they don't match up correctly the parser will notice and report the error.)
This is all enough for lambda functions to span multiple lines when the body of the lambda is an expression ─ the user just has to ensure that either the lambda or its body is wrapped in parentheses, then it can span multiple lines. (Of course, this applies to every expression, not just lambdas.)
Lambda functions whose body is a block of statements, on the other hand, are considerably more difficult. Python's solution is to just not allow such lambdas; instead, you are supposed to declare a named function and then you can refer to it by name in an expression. There's a lot to be said for this approach ─ it means that expressions never contain statements, making the language grammatically simpler. It also results in more useful stack traces on runtime errors, because the lines have meaningful names instead of just saying <lambda>.
On the other hand, if you do want statements inside expressions, there's probably no way around having some kind of delimiters (like the braces in Rust), otherwise there will be nothing but whitespace separating the end of the last statement from the continuation of the expression that the lambda occurred in. Here's what it looks like without delimiters:
foo(lambda:
print('hello world')
do_something_else()
, 3.5)
Without block delimiters, the comma is required to be in this ugly position at the start of the line, and moreover the indentation of the expression matters on that line ─ it must be less indented than the lambda body ─ when indentation inside expressions doesn't matter anywhere else. These problems both disappear when you require delimiters; if you don't like braces in an indentation-based language, you could use Lua-style do/end keywords instead:
foo(lambda: do
print('hello world')
do_something_else()
end, 3.5)
So I think you have to just bite the bullet and use block delimiters, at least for statements that occur inside expressions. You don't need to require delimiters on every block, and you can still enforce the language's indentation rules between those delimiters; they're not there to define the nesting level of statements, they're there to separate the statements from the expression which contains them.
Implementation-wise, the lexer now needs to maintain a stack of those counters, so that when you see a do token it pushes a 0 to the stack, and when you see end it pops the counter from the stack. (No need to check that it's zero; the parser will ensure correct nesting of brackets.) This way you effectively "reset" the counter so that the lexer can insert the correct INDENT and DEDENT tokens inside the lambda body, while still being able to restore the old counter for the nesting level of the expression that the lambda occurs in.
Koka's trailing lambda syntax
The Koka language has an interesting feature called trailing lambdas: when the last argument of a function is a lambda, it can be written outside of the parentheses.
Let's take a look at this example (based on the example in kaya3's answer):
foo(3.5, fn()
println('hello world')
do_something_else()
)
The final right-parenthesis is ugly. Koka allows us to write this instead:
foo(3.5) fn()
println('hello world')
do_something_else()
Since this lambda doesn't take any arguments, the fn() can be omitted:
foo(3.5)
println('hello world')
do_something_else()
I think this is an elegant syntax sugar. There are some other languages that have similar feature, such as Julia and some early version of Rust, but those languages are not indent based.
You can define your lambda on multiple lines if you put the expression in parentheses. This creates an implied line continuation, causing newlines to be ignored up to the closing parenthesis.
>>> func = lambda a,b: (
... b - a if a <= b else
... a*b
... )
>>>
>>> func(23, 42)
19
You can also explicitly use the line continuation character "\", but this is not the approach preferred by the Python style guide. (Not that binding lambdas to names are a good idea to begin with, in fairness...)
>>> func = lambda a,b: \
... b - a if a <= b else \
... a*b
>>>
>>> func(23, 42)
19
Of course, you can only have expressions inside your lambda, and not statements. So proper if blocks and returns and the like are still impossible.
Additionally, it may not be necessary to use lambdas here at all, because unlike C# (prior to the recent v. 7.0), Python is capable of nesting full functions:
>>> def method(x,y):
... def func(a,b):
... if a <= b:
... return b - a
... return a * b
... return func(x,y)
...
>>> method(23, 42)
19
There is a tricky way of creating not just a multi-line lambda for formatting, but also one that is truly multi-line logically. It involves using the exec command to turn a string into a function. I don't know how efficient this is but it works. I came up with this because sometimes I want to create a custom lambda function for the sorted function and don't want to define a persistent function. So check out the following:
def strToFun(x):
name = x[x.find(' ') + 1:x.find('(')]
exec(x)
ret = eval(name)
return ret
This will create a function and return a pointer to that function. If you run the following test, you will see there is a function called f1 but not one called fun1. The fun1 is a placeholder because we have to have a function name when using def. exec creates a function inside the strToFun function. eval returns a pointer to that function without executing it. The function returns the pointer and the inner function called fun1 falls out of scope.
f1 = strToFun('def fun1(x): return x + 1')
print(f1, type(f1), f1(100))
print(dir())
Instead of storing the newly created function to a variable you could also just use it directly just like you would a lambda expression:
print(strToFun('def fun1(x): return x + 1')(200))
So I use it like this to create complex lambdas when I need to:
countries = ['Uganda', 'Canada', 'USA', 'Albania', 'USA']
print(sorted(countries
, key = strToFun(
'''def _fun1(x):
if x == 'USA':
return (0,)
elif x == 'Canada':
return (1,)
else:
return(2, x)
''')))
I am sure I will get a lot of comments about how unpythonic this is and that if Guido wanted us to have multi-line lambdas he would have put it in the language. Nevertheless, it is an interesting and effective trick when you need it, so what could be wrong with that?