Which is more preferable to use: lambda functions or nested functions ('def')?
If you need to assign the lambda
to a name, use a def
instead. def
s are just syntactic sugar for an assignment, so the result is the same, and they are a lot more flexible and readable.
lambda
s can be used for use once, throw away functions which won't have a name.
However, this use case is very rare. You rarely need to pass around unnamed function objects.
The builtins map()
and filter()
need function objects, but list comprehensions and generator expressions are generally more readable than those functions and can cover all use cases, without the need of lambdas.
For the cases you really need a small function object, you should use the operator
module functions, like operator.add
instead of lambda x, y: x + y
If you still need some lambda
not covered, you might consider writing a def
, just to be more readable. If the function is more complex than the ones at operator
module, a def
is probably better.
So, real world good lambda
use cases are very rare.
Why would you use lambda instead of def?
lambda
is nice for small, unnamed functions but in this case it would serve no purpose other than make functionalists happy.
python lambda map over nested list
While I'm not certain of this, it sounds like the input might have the length included in the beginning and it needs to be passed through untouched. If that's the case, here's a single lambda function that will take the input and produce the desired output:
lambda i: [n**2 for n in i if n > 0] if isinstance(i, list) else i
This portion does the squaring on the non-negatives: [n**2 for n in i if n > 0]
But only if the value is a list: if isinstance(i, list)
Otherwise pass the value through: else i
That means this input [2, [1, 2, 3, -1, 2], [2, 4, -3]]
returns this output [2, [1, 4, 9, 4], [4, 16]]
Nested lambda statements when sorting lists
In almost all cases I would simply go with your second attempt. It's readable and concise (I would prefer three simple lines over one complicated line every time!) - even though the function name could be more descriptive. But if you use it as local function that's not going to matter much.
You also have to remember that Python uses a key
function, not a cmp
(compare) function. So to sort an iterable of length n
the key
function is called exactly n
times, but sorting generally does O(n * log(n))
comparisons. So whenever your key-function has an algorithmic complexity of O(1)
the key-function call overhead isn't going to matter (much). That's because:
O(n*log(n)) + O(n) == O(n*log(n))
There's one exception and that's the best case for Pythons sort
: In the best case the sort
only does O(n)
comparisons but that only happens if the iterable is already sorted (or almost sorted). If Python had a compare function (and in Python 2 there really was one) then the constant factors of the function would be much more significant because it would be called O(n * log(n))
times (called once for each comparison).
So don't bother about being more concise or making it much faster (except when you can reduce the big-O without introducing too big constant factors - then you should go for it!), the first concern should be readability. So you should really not do any nested lambda
s or any other fancy constructs (except maybe as exercise).
Long story short, simply use your #2:
def sorter_func(x):
text, num = x.split('-')
return int(num), text
res = sorted(lst, key=sorter_func)
By the way, it's also the fastest of all proposed approaches (although the difference isn't much):
Summary: It's readable and fast!
Code to reproduce the benchmark. It requires simple_benchmark
to be installed for this to work (Disclaimer: It's my own library) but there are probably equivalent frameworks to do this kind of task, but I'm just familiar with it:
# My specs: Windows 10, Python 3.6.6 (conda)
import toolz
import iteration_utilities as it
def approach_jpp_1(lst):
return sorted(lst, key=lambda x: (int(x.split('-')[1]), x.split('-')[0]))
def approach_jpp_2(lst):
def sorter_func(x):
text, num = x.split('-')
return int(num), text
return sorted(lst, key=sorter_func)
def jpp_nested_lambda(lst):
return sorted(lst, key=lambda x: (lambda y: (int(y[1]), y[0]))(x.split('-')))
def toolz_compose(lst):
return sorted(lst, key=toolz.compose(lambda x: (int(x[1]), x[0]), lambda x: x.split('-')))
def AshwiniChaudhary_list_comprehension(lst):
return sorted(lst, key=lambda x: [(int(num), text) for text, num in [x.split('-')]])
def AshwiniChaudhary_next(lst):
return sorted(lst, key=lambda x: next((int(num), text) for text, num in [x.split('-')]))
def PaulCornelius(lst):
return sorted(lst, key=lambda x: tuple(f(a) for f, a in zip((int, str), reversed(x.split('-')))))
def JeanFrançoisFabre(lst):
return sorted(lst, key=lambda s : [x if i else int(x) for i,x in enumerate(reversed(s.split("-")))])
def iteration_utilities_chained(lst):
return sorted(lst, key=it.chained(lambda x: x.split('-'), lambda x: (int(x[1]), x[0])))
from simple_benchmark import benchmark
import random
import string
funcs = [
approach_jpp_1, approach_jpp_2, jpp_nested_lambda, toolz_compose, AshwiniChaudhary_list_comprehension,
AshwiniChaudhary_next, PaulCornelius, JeanFrançoisFabre, iteration_utilities_chained
]
arguments = {2**i: ['-'.join([random.choice(string.ascii_lowercase),
str(random.randint(0, 2**(i-1)))])
for _ in range(2**i)]
for i in range(3, 15)}
b = benchmark(funcs, arguments, 'list size')
%matplotlib notebook
b.plot_difference_percentage(relative_to=approach_jpp_2)
I took the liberty to include a function composition approach of one of my own libraries iteration_utilities.chained
:
from iteration_utilities import chained
sorted(lst, key=chained(lambda x: x.split('-'), lambda x: (int(x[1]), x[0])))
It's quite fast (2nd or 3rd place) but still slower than using your own function.
Note that the key
overhead would be more significant if you used a function that had O(n)
(or better) algorithmic complexity, for example min
or max
. Then the constant factors of the key-function would be more significant!
How can i exception handle through a lambda function? [tkinter]
The simplest solution is to not use lambda. Create a proper function, and it will be easier to write, easier to understand, and easier to debug. In this specific case, lambda
is doing nothing but making your code more complicated than it needs to be.
In this specific case, just move the calls to get
inside of the submit_details
function.
def second_win():
...
Button(window, text='Submit', command= submit_details).grid()
...
def submit_details():
username = UserName.get()
firstname = User_FirstName.get()
surname = User_Surname.get()
age = User_Age.get()
height = User_Height.get()
weight = User_weight.get()
...
If you prefer to leave submit_details
the way that it is, create an intermediate function to get the data from the UI before passing it to submit_details
:
def second_win():
...
Button(window, text='Submit', command=submit).grid()
...
def submit():
username = UserName.get()
firstname = User_FirstName.get()
surname = User_Surname.get()
age = User_Age.get()
height = User_Height.get()
weight = User_weight.get()
data = [username, firstname, surname, age, height, weight]
submit_details(data)
Decorator factory returning lambda
It's just returning an anonymous function instead of using a def
statement. The following is entirely equivalent:
def decorator_factory(arg1):
def decorator(arg2):
def _(func):
return real_decorator(arg1, arg2, func)
return _
return decorator
decorator_factory("r")
returns a function bound to the name my_decorator_instance
; my_decorator_instance('decorator_args')
returns a function that gets applied to method_1
.
Just to get a better feel for how decorators work (they are just functions applied to other things), you could also have written
class MyClass():
def __init__(self, *args, **kwargs):
pass
@decorator_factory("r")('decorator args')
def method_1(self):
print("method_1")
or even
class MyClass():
def __init__(self, *args, **kwargs):
pass
method_1 = decorator_factory("r")('decorator args')(lambda self: print("method_1"))
Replacements for switch statement in Python?
The original answer below was written in 2008. Since then, Python 3.10 (2021) introduced the match
-case
statement which provides a first-class implementation of a "switch" for Python. For example:
def f(x):
match x:
case 'a':
return 1
case 'b':
return 2
case _:
return 0 # 0 is the default case if x is not found
The match
-case
statement is considerably more powerful than this simple example.
You could use a dictionary:
def f(x):
return {
'a': 1,
'b': 2,
}[x]
what is the difference for python between lambda and regular function?
They are the same type so they are treated the same way:
>>> type(a)
<type 'function'>
>>> type(b)
<type 'function'>
Python also knows that b
was defined as a lambda function and it sets that as function name:
>>> a.func_name
'a'
>>> b.func_name
'<lambda>'
In other words, it influences the name that the function will get but as far as Python is concerned, both are functions which means they can be mostly used in the same way. See mgilson's comment below for an important difference between functions and lambda functions regarding pickling.
Related Topics
How to Merge 200 CSV Files in Python
A Fast Way to Find the Largest N Elements in an Numpy Array
Getting Only Element from a Single-Element List in Python
Why Is Tensorflow 2 Much Slower Than Tensorflow 1
Combining Conda Environment.Yml with Pip Requirements.Txt
How to Update JSON File with Python
What Is the Pythonic Way to Unpack Tuples
Pipelinedrdd' Object Has No Attribute 'Todf' in Pyspark
Pyspark: Split Multiple Array Columns into Rows
Selenium Element Not Visible Exception
Pytz Localize VS Datetime Replace
How to Upgrade to Python 3.6 with Conda
Convert Image from Pil to Opencv Format
Failed to Get Convolution Algorithm. This Is Probably Because Cudnn Failed to Initialize,