Currently, this is how I resolve a "and" function using lambda with two arguments:
custom_function = lambda a, b: a and b
But how can I resolve an unknown number of arguments, like:
custom_function = lambda a, b, c, d, ...: what now?
Anybody had this issue before?
Thanks and Greetings!
You can use "*args":
>>> custom_function = lambda *args: all(args)
>>> custom_function(1, 2, 3)
True
>>> custom_function(1, 2, 3, 0)
False
Which indeed is the same as just using "all":
>>> all(1, 2, 3)
True
>>> all(1, 2, 3, 0)
False
To be general, you can use "functools.reduce" to use any "2-parameters" function with any number of parameters (if their order doesn't matter):
import operator
import functools
c = lambda *args: functools.reduce(operator.and_, args)
(same results as before)
You can use argument unpacking via the * operator to process any number of arguments. You would have to resort to reduce (Python2) or functools.reduce (Python3) in order to combine them all with and in a single expression (as needed by the lambda):
from functools import reduce # only Py3
custom_function = lambda *args: reduce(lambda x, y: x and y, args, True)
Note: this is not the same as all, like many here suggest:
>>> all([1,2,3])
True
>>> 1 and 2 and 3
3
>>> custom_function(1,2,3)
3
First, use *args to store an unknown number of arguments as a tuple.
Second, all(args) only return Ture or False but and operation may return value (Here is why). So we need to use reduce.
Here is the solution:
custom_function = lambda *args: reduce(lambda x,y: x and y, args)
Test 1: arguments are Ture or False
>>> custom_function(True,False,True,False)
False
>>> custom_function(True,True,True)
True
Test 2: arguments are values
>>> custom_function(1,2,3,4,3,2)
2
>>> custom_function('a','b','d','s')
's'
Test 3: arguments are a combination of bool and values
>>> custom_function(1,2,True,4,3,2)
2
>>> custom_function(1,2,False,4,3,2)
False
Note the three tests are correct according to the definition of Logical AND (and):
Return the first Falsey value if there are any, else return the last
value in the expression.
Why not just using the all function?
a = 1
b = 2
c = None
args = [a, b, c]
print (all(args))
# False
Related
Suppose I have a function like:
def myfun(a, b, c):
return (a * 2, b + c, c + b)
Given a tuple some_tuple = (1, "foo", "bar"), how can I use some_tuple to call myfun, to get the result (2, "foobar", "barfoo")
I know could define myfun so that it accepts the tuple directly, but I want to call the existing myfun.
See also: What do the * (star) and ** (double star) operators mean in a function call?.
myfun(*some_tuple) does exactly what you request. The * operator simply unpacks the tuple (or any iterable) and passes them as the positional arguments to the function. Read more about unpacking arguments.
Note that you can also expand part of argument list:
myfun(1, *("foo", "bar"))
Take a look at the Python tutorial section 4.7.3 and 4.7.4.
It talks about passing tuples as arguments.
I would also consider using named parameters (and passing a dictionary) instead of using a tuple and passing a sequence. I find the use of positional arguments to be a bad practice when the positions are not intuitive or there are multiple parameters.
This is the functional programming method. It lifts the tuple expansion feature out of syntax sugar:
apply_tuple = lambda f, t: f(*t)
Redefine apply_tuple via curry to save a lot of partial calls in the long run:
from toolz import curry
apply_tuple = curry(apply_tuple)
Example usage:
from operator import add, eq
from toolz import thread_last
thread_last(
[(1,2), (3,4)],
(map, apply_tuple(add)),
list,
(eq, [3, 7])
)
# Prints 'True'
Similar to #Dominykas's answer, this is a decorator that converts multiargument-accepting functions into tuple-accepting functions:
apply_tuple = lambda f: lambda args: f(*args)
Example 1:
def add(a, b):
return a + b
three = apply_tuple(add)((1, 2))
Example 2:
#apply_tuple
def add(a, b):
return a + b
three = add((1, 2))
I am trying to get a single Handler of a specific custom type MemoryListHandler in the logger.handlers collection.
With .NET I would simply use the following LINQ extension, which filters element and returns only those of type MemoryListHandler:
logger.handlers.OfType<MemoryListHandler>().SingleOrDefault()
What would be the most elegant equivalent in Python?
My current (not very neat) attempt is:
next((handler for handler in logger.handlers if handler is MemoryListHandler), None)
You might try the index method.
try:
lh = logger.handlers
x = lh[lh.index(MemoryListHandler)]
except ValueError:
x = some_default_value
Python is dynamically typed, therefore you might not need to convert anything.
However, in some cases you still might need to convert, say, int to string :
map(lambda x: str(x), [1, 2, 3])
Or, given your function accepts only one argument, just pass the function alone :
map(str, [1, 2, 3])
Update
filter(lambda x: type(x) == YourClass, [your_array])
For Python the is operator tests identity NOT type like it does in c#. You want isinstance for your test -- which will also work with subtypes of the target_type you're looking for.
Using the Python REPL to illustrate the difference between is and isinstance:
>>> s = ""
>>> s is str
False
>>> isinstance(s, str)
True
>>> class Foo:
... def __init__(self):
... pass
...
>>> f = Foo()
>>> g = Foo()
>>> f is g
False
>>> f is Foo
False
>>> g is Foo
False
>>> x = f
>>> f is x
True
>>> g is x
False
Your own expression is pretty close to what you want. You can hide it behind a method:
def first_of_type(xs, target_type):
return next((x for x in xs if isinstance(x, target_type)), None)
Usage becomes short and sweet:
first_of_type(logger.handlers, MemoryListHandler)
Note: addition of type hints and doc comments would help usability.
In Python 2 this code is OK:
f = lambda (m, k): m + k
m = [1,2,3,4]
k = [5,6,7,8]
print(map(f, zip(m, k)))
but in Python 3 the following error occurred:
f = lambda (m, k): m + k
^
SyntaxError: invalid syntax
If I remove parentheses in lambda expression then another error occurred:
TypeError: <lambda>() missing 1 required positional argument: 'k'
Also approach with tuple as single lambda argument works in Python 3, but it's not clear (hard for reading):
f = lambda args: args[0] + args[1]
How can I unpack values in the right way in Python 3?
The removal of tuple unpacking is discussed in PEP 3113. Basically, you can't do this in Python 3. Under the headline Transition plan, you see that the "suggested" way of doing this is as your final code block:
lambda x_y: x_y[0] + x_y[1]
You can use the same syntax in both Python 2 and Python 3 if you use itertools.starmap instead of map which unpacks the tuple items for us:
>>> from itertools import starmap
>>> f = lambda m, k: m + k
>>> list(starmap(f, zip(m, k)))
[6, 8, 10, 12]
You may find this solution easier to read:
lambda mk: (lambda m,k: m + k)(*mk)
Additionally, I'd argue that the unpacking makes this more (1) Pythonic and (2) consistent with the manual unpacking of tuple arguments for named functions, required in Python 3 by PEP 3113.
You cannot use parentheses in Python3 to unpack arguments in lambda functions (PEP 3113), Try:
f = lambda m, k: m + k
To make it work with your code, you should use:
lambda mk: mk[0] + mk[1]
Or you can just sum() to add numbers without unpack:
f = lambda args: sum(args)
Just use
map(f, m, k)
Note that f can be
from operator import add
map(add, m, k)
I have a chain of operations which needs to occur one after the other and each depends on the previous function's output.
Like this:
out1 = function1(initial_input)
out2 = function2(out1)
out3 = function3(out2)
out4 = function4(out3)
and so on about 10 times. It looks a little ugly in the code.
What is the best way to write it? Is there someway to handle it using some functional programming magic? Is there a better way to call and execute this function chain?
You can use functools.reduce:
out = functools.reduce(lambda x, y : y(x), [f1, f2, f3, f4], initial_value)
Quoting functools.reduce documentation:
Apply a function of two arguments cumulatively to the items of a sequence,
from left to right, so as to reduce the sequence to a single value.
For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
((((1+2)+3)+4)+5). If initial is present, it is placed before the items
of the sequence in the calculation, and serves as a default when the
sequence is empty.
Here, we use the fact that functions can be treated as any variable in Python, and an anonymous functions which simply does "apply x to function y".
This "reduce" operation is part of a very general pattern which have been applied successfully to parallelize tasks (see http://en.wikipedia.org/wiki/MapReduce).
Use a loop:
out = initial_input
for func in [function1, function2, function3, function4]:
out = func(out)
To propagate functional programming a bit:
In [1]: compose = lambda f, g: lambda arg: f(g(arg))
In [2]: from functools import reduce
In [3]: funcs = [lambda x:x+1, lambda x:x*2]
In [4]: f = reduce(compose, funcs)
In [5]: f(1)
Out[5]: 3
In [6]: f(3)
Out[6]: 7
You can pass the return values directly to the next function:
out4 = function4(function3(function2(function1(initial_input))))
But this isn't necessarily better, and is perhaps less readable.
Suppose a = [[1,2,3],[1,2,3]]
reduce(lambda x,y: x==y, a) returns True
But if a = [[1,2,3],[1,2,3],[1,2,3]]
reduce(lambda x,y: x==y, a) returns False
Why in the second case, the outcome is False?
please help
thanks
Try this instead, it works for lists of any size:
all(e == a[0] for e in a)
Notice that your proposed solution using reduce doesn't work for more than two items, as the accumulated value after the first comparison is True, and you'd be comparing True against each of the elements from that point on, and obviously that's not going to work.
You are not reducing the lists. The return value of your lambda is True or False, which is then used as input parameters to further calls to the same lambda function. So you end up comparing a boolean with a list. Therefore, the reducing function should return the same type as it input parameters.
You were probably looking for what other answers proposed instead: use all().
You can still use reduce! Check out this magic:
bool(reduce(lambda x,y: (x==y)*x, a))
Since the return value of the lambda for x==y is True or False, that can be multiplied by the input and then used in the next comparison because True*[1,2,3] is [1,2,3]. It also works for strings, True*"MyString" is "MyString".
Try it. However, this method will not work for a list of zeros.
Because first time reduce compare [1,2,3] == [1, 2, 3] and it's true
next time it compare True and [1,2,3] and it's false.
help(reduce)
Help on built-in function reduce in module __builtin__:
reduce(...)
reduce(function, sequence[, initial]) -> value
Apply a function of two arguments cumulatively to the items of a sequence,
from left to right, so as to reduce the sequence to a single value.
For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
((((1+2)+3)+4)+5).
a = [range(1, 4), range(1, 4), range(1, 4)]
To evaluate reduce(operator.eq, a) the reduce function will first evaluate the function operator.eq on the first two elements of a to obtain True. Then it will call operator.eq again with True and range(1, 4) as the two arguments, and obtain False which is the final result of reduce.
Perhaps you are wanting:
from functools import partial
import operator
allequal = reduce(partial(operator.eq, a[0]), a[1:])
Why in the second case, the outcome is False
Because reduce(lambda x, y: x == y, (a, b, c, d)) does not mean (a == b) and (b == c) and (c == d); it means (((a == b) == c) == d). a == b will produce either True or False, which then gets compared to c.