how are the 2 implementation of lambda different - python

z = (lambda *a: a, (1,2))
print(z)
k = (lambda *a: a)(1,2)
print(k)
How does the comma (,) and parenthesis work here in lambda implementation?
Output:
(<function <lambda> at 0x000002648500E0D0>, (1, 2))
(1, 2)
If I remove the comma and give parenthesis I get the desired output (1,2).
However, if I give the comma it gives me function ... and (1,2).
Please make me understand.

First case;
z = (lambda *a: a, (1,2))
print(z)
Here z is a tuple which has two elements, lambda *a: a and another tuple (1, 2). When you print it, you will simply get these elements printed, ie, a function and a tuple;
(<function <lambda> at 0x000002648500E0D0>, (1, 2))
Another case;
k = (lambda *a: a)(1,2)
print(k)
Here you are creating a lambda function and to call the function, we add parenthesis at the end of the function and pass the parameters. That is what you are doing here.
By adding (1, 2) at the end of the lambda function calls it with 1 and 2 as parameters.
Also note that * before a in the lambda function (if you don't know). It means that spread the given list or tuple.

If I remove the comma... I get the desired output
So, your desired action is to invoke the lambda function
You don't execute functions using commas, in other words commas never exist between their names/definitions and their parameters, so if you'd expected that to work, it'd be a typo
Now, that all being said, your first line is functionally equivalent to
z=((lambda *a: a), (1,2), )
Which, hopefully makes it a little clearer that you've defined a tuple of two things, a function object and the tuple (1,2)
Regarding the output, as shown before, you're just printing a lambda - understanding the return type of anonymous function lambda

In the lambda ‘z’, because you don’t call the lambda you created (append a pair of parentheses and pass the parameters), so, it is just a lambda that returns a tuple which contains unpacked a and (1, 2).
In the lambda ‘k’, because you called the lambda you created, and you passed the parameter 1 and 2, so, according to the lambda, it returns an unpacked tuple (when 1 and 2 passed to the lambda, however, the parameter becomes (1, 2) ).
Because the lambda returns (1, 2), the variable ‘k’ was assigned with the returned value.

Related

How to apply some operation to each element of a tuple

I have a tuple like (p1, p2) (for example (5,3) or (2,1))
I want to apply the same operation to each element of the tuple. (Incidentally this operation will give for each element another tuple, so I will have a tuple of tuples but this is not a necessary condition)
First I thought something like
for element in (3,2):
res=function(element)
but first, this doesn't seem a elegant solution and two, I would still have to form a tuple from each res to get a (function(3),function(2)) solution
How can I apply a function (with several arguments) to each element of the tuple once and get a tuple of returned values?
If I understand you question correctly, map should to the job as well:
tuple(map(func, tpl))
where func is a one-argument function you defined.
Now, if you have a function with several arguments you would like to apply to each element, like:
def func(x, y, z): return x*y+z
I assume that 2 elements (let's take y and z) are fixed, while x will be determined by the value in the tuple.
There are two approaches in my view:
Either you define a new function with 2 fixed arguments and map:
def func1(x): return func(x, 3, 2)
tuple(map(func1, tpl))
Or map as follows (I think it is less elegant, but it is a matter of tastes, maybe):
tuple(map(lambda x: func(x, 3, 2), tpl))
One approach uses a list comprehension:
def add_one(x):
return x + 1
tpl = (5, 3)
output = tuple([add_one(x) for x in tpl])
print(output) # (6, 4)
You may consider using the generator comprehension then convert it to tuple:
>>> data = (3, 5, 7, 9)
>>> tuple((function(x) for x in data))

Why does max behave differently if I pass a lambda as key compared to applying it directly to a map of the original iterable with the same lambda?

I'm trying to understand how the key argument works in the max function, coming from a problem of finding the closest integer to 0 from a list, and using the positive value in case of having the same positive and negative value in the list.
I have found this to be an efficient solution online, given a list of integers x:
print(max(a, key=lambda x: (-abs(x), x), default=0))
This returns a single integer, where I would expect to return a tuple, given that the lambda will transform every element of x into a tuple, then I did this:
b = list(map(lambda x: (-abs(x), x), a))
max(b)
And this second example returns a tuple. Why does the first one return a single elements when it is comparing tuples generated by the lambda?
You are comparing two different things.
For your first case, if we look at the docs: https://docs.python.org/3/library/functions.html#max
max(arg1, arg2, *args[, key])
Return the largest item in an iterable or the largest of two or more arguments. The key argument specifies a one-argument ordering function like that used for list.sort().
Which means that the key lambda x: (-abs(x), x) is a ordering function, which means that for every x in iterable a, (-abs(x), x) is evaluated and is used to order the items for finding out the maximum element of the iterator, and according to that ordering, 1 is the maximum element
In [24]: a = [1,4,6,-8,-10]
In [40]: print(max(a, key=lambda x: (-abs(x), x), default=0))
1
For the second case, if we look at the docs: https://docs.python.org/3/library/functions.html#map
map(function, iterable, ...)
Return an iterator that applies function to every item of iterable, yielding the results
Which means that the function lambda x: (-abs(x), x) is applied to every element x of a, so we get back (-abs(x), x) for every x, and the max is applied on the updated iterator, which is the largest tuple (-1,1)
In [25]: b = list(map(lambda x: (-abs(x), x), a))
In [26]: b
Out[26]: [(-1, 1), (-4, 4), (-6, 6), (-8, -8), (-10, -10)]
In [27]: max(b)
Out[27]: (-1, 1)

Lambda function syntax in python

I came across the sorted() example below and cannot figure out why lambda student: student[2] can represent a function specifying the integers in the tuple.
Can anyone lay out the mechanics or a clearer example of how python knows the lambda function student should pull data from student_tuples?
student_tuples = [
('john', 'A', 15),
('jane', 'B', 12),
('dave', 'B', 10)]
sorted(student_tuples, key=lambda student: student[2]) # sort by age
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
lambda student: student[2] is equivalent to the following function, aside from not having a name:
def <anonymous function>(student):
return student[2]
The reason why it winds up pulling from student_tuples is because the sorted() function passes each individual element from its first argument (the sequence to sort) to its key argument (a function that takes an element and returns the corresponding sort key). As such, sorted() passes each element of student_tuples to the lambda function in turn, during which the value of the element is temporarily assigned to the student variable.
lambda student: student[2]
clearer:
lambda x: x[2]
A lambda expression returns a function. The arguments for this function are before the ':' and separated by commas.
lambda x,y: x + y
The function does not have a name. But you can imagine as if lambda creates an abstract function. The lambda expression returns a function.
(Lambda is kind of essence of what a function is).
You can give lambda expressions also a name:
f = lambda x: x[2]
And now you can use the name to call the function.
f(["a", "b", "c"]) ## returns "c" because the list element "c" has index 2
list(map(f, student_tuples))
## [15, 12, 10]
or with the lambda expression:
list(map(lambda x: x[2], student_tuples))
## [15, 12, 10]
is actually what happens inside of sort:
the lambda-function is applied to each element of the list (map).
The outer list() around map() is necessary to execute map, because map is lazily evaluated (a promise to execute it but not yet executed).
Lazy evaluation is actually a nesting of lambdas ... well, lambdas are the core of functional programming. Programming languages like Lisp make you clear what lambda actually is. (You can also google for lambda calculus).
In R, a functional language, in such case the order of the iterable object indexes is determined and then applied on the object - for the ordering/sorting - to achieve the final sorted version (function sort)
I guess, sth similar is going on inside Python's sorted function.

Python lambda function underscore-colon syntax explanation?

In the following Python script where "aDict" is a dictionary, what does "_: _[0]" do in the lambda function?
sorted(aDict.items(), key=lambda _: _[0])
Lets pick that apart.
1) Suppose you have a dict, di:
di={'one': 1, 'two': 2, 'three': 3}
2) Now suppose you want each of its key, value pairs:
>>> di.items()
[('three', 3), ('two', 2), ('one', 1)]
3) Now you want to sort them (since dicts are unordered):
>>> sorted(di.items())
[('one', 1), ('three', 3), ('two', 2)]
Notice that the tuples are sorted lexicographically -- by the text in the first element of the tuple. This is a equivalent to the t[0] of a series of tuples.
Suppose you wanted it sorted by the number instead. You would you use a key function:
>>> sorted(di.items(), key=lambda t: t[1])
[('one', 1), ('two', 2), ('three', 3)]
The statement you have sorted(aDict.items(), key=lambda _: _[0]) is just using _ as a variable name. It also does nothing, since aDict.items() produces tuples and if you did not use a key it sorts by the first element of the tuple anyway. The key function in your example is completely useless.
There might be a use case for the form (other than for tuples) to consider. If you had strings instead, then you would be sorting by the first character and ignoring the rest:
>>> li=['car','auto','aardvark', 'arizona']
>>> sorted(li, key=lambda c:c[0])
['auto', 'aardvark', 'arizona', 'car']
Vs:
>>> sorted(li)
['aardvark', 'arizona', 'auto', 'car']
I still would not use _ in the lambda however. The use of _ is for a throway variable that has minimal chance of side-effects. Python has namespaces that mostly makes that worry not a real worry.
Consider:
>>> c=22
>>> sorted(li, key=lambda c:c[0])
['auto', 'aardvark', 'arizona', 'car']
>>> c
22
The value of c is preserved because of the local namespace inside the lambda.
However (under Python 2.x but not Python 3.x) this can be a problem:
>>> c=22
>>> [c for c in '123']
['1', '2', '3']
>>> c
'3'
So the (light) convention became using _ for a variable either in the case of a list comprehension or a tuple expansion, etc where you worry less about trampling on one of your names. The message is: If it is named _, I don't really care about it except right here...
In Python _ (underscore) is a valid identifier and can be used as a variable name, e.g.
>>> _ = 10
>>> print(_)
10
It can therefore also be used as the name of an argument to a lambda expression - which is like an unnamed function.
In your example sorted() passes tuples produced by aDict.items() to its key function. The key function returns the first element of that tuple which sorted() then uses as the key, i.e that value to be compared with other values to determine the order.
Note that, in this case, the same result can be produced without a key function because tuples are naturally sorted according to the first element, then the second element, etc. So
sorted(aDict.items())
will produce the same result. Because dictionaries can not contain duplicate keys, the first element of each tuple is unique, so the second element is never considered when sorting.
In Python, lambda is used to create an anonymous function. The first underscore in your example is simply the argument to the lambda function. After the colon (i.e. function signature), the _[0] retrieves the first element of the variable _.
Admittedly, this can be confusing; the lambda component of your example could be re-written as lambda x: x[0] with the same result. Conventionally, though, underscore variable names in Python are used for "throwaway variables". In this case, it implies that the only thing we care about in each dictionary item is the key. Nuanced to a fault, perhaps.

Python: Understanding reduce()'s 'initializer' argument

I'm relatively new to Python and am having trouble
with Folds or more specifically, reduce()'s 'initializer' argument
e.g. reduce(function, iterable[, initializer])
Here is the function...
>>> def x100y(x,y):
... return x*100+y
Could someone explain why reduce() produces 44...
>>> reduce(x100y, (), 44)
44
or why it produces 30102 here...
>>> reduce(x100y, [1,2], 3)
30102
From the docs:
reduce(function, iterable[, initializer])
Apply function of two
arguments cumulatively to the items of iterable, from left to right,
so as to reduce the iterable to a single value. For example,
reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
((((1+2)+3)+4)+5). The left argument, x, is the accumulated value and
the right argument, y, is the update value from the iterable. If the
optional initializer is present, it is placed before the items of the
iterable in the calculation, and serves as a default when the iterable
is empty. If initializer is not given and iterable contains only one
item, the first item is returned.
The initializer is placed as element 0 in your iterable and if there are no elements in your iterable it is returned. (So this is why you get 44)
Also, x100y is not a valid python function. If you want to make it into a valid python function you would have to do
reduce(lambda x,y: x*100*y,[1,2],3)
which is equivalent to
(3*100*1)*100*2 which should give 60000 (why you got the value you had is probably because of an error)
Documentation on lambda is here

Categories