plx
plx

Reputation: 427

What is the use of the 'or' keyword in the following code?

I can't understand the use of the or keyword in the following code taken from an answer from this site that showed one way to partition a list using reduce:

 def partition(l, p):
     return reduce(lambda x, y: x[not p(y)].append(y) or x, l, ([], []))

I understand that the code will append to the first list if the condition is true, otherwise it appends to the second. What does the part or x do? I tried leaving that out but I ended up with an error saying TypeError: 'NoneType' object is not subscriptable

Upvotes: 2

Views: 51

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1122382

Someone is code golfing. list.append() always returns None, which is a false value. By using or they can then have the lambda return the result of a second expression; None or ... always returns the result of ....

You could replace the lambda with a full function definition:

def func(x, y): 
    x[not p(y)].append(y)
    return x

Both the lambda and the above re-definition return the x argument, which is the cumulative value reduce() passes in each call. In this case it is a tuple with two lists into which the partitioned values are collected.

Personally, I'd just have used a loop:

def partition(l, p):
    a, b = [], []
    for v in l:
        target = a if not p(v) else b
        target.append(v)
    return a, b

Readability matters, after all. Moreover, because it avoids additional function calls (one extra call per value in the input list), it is also quite a bit faster:

>>> import timeit
>>> import random
>>> testdata = [random.randrange(1000) for _ in range(10 ** 4)]
>>> predicate = lambda v: v % 2 == 0
>>> def partition_lambda(l, p):
...     return reduce(lambda x, y: x[not p(y)].append(y) or x, l, ([], []))
...
>>> def partition_readable(l, p):
...     a, b = [], []
...     for v in l:
...         target = a if not p(v) else b
...         target.append(v)
...     return a, b
...
>>> timeit.timeit('part(l, p)', 'from __main__ import partition_lambda as part, testdata as l, predicate as p', number=10**3)
2.5286515180487186
>>> timeit.timeit('part(l, p)', 'from __main__ import partition_readable as part, testdata as l, predicate as p', number=10**3)
1.6824414430302568

So for partitioning a 10k item list, 1000 times, the readable version takes only 2/3rds of the time that the reduce() version takes.

Upvotes: 5

Related Questions