1
def f(x):
    return x <5
[x for x in filter(lambda x: f(x), ls)]  #[0,1,2,3,4]
def g(x):
    return lambda: x<5
[x for x in filter(lambda x: g(x), ls)]  # [0,1,2,3,4,5,6,7,8,9]
def h(x):
    return lambda x=x: x<5
[x for x in filter(lambda x: h(x), ls)]  # [0,1,2,3,4,5,6,7,8,9]

Can anyone explain why g and h are not equivalent to f? I think they should be equivalent because x in g and h should bind to the x in the environment that they are defined in (see this question on closures)

Jean
  • 1,480
  • 15
  • 27

2 Answers2

0

Here g and h return function object, but filter waits an function which returns a boolean or object wich will convert as boolean . With f it is correct for your expected output, but for g and h, the condition is always true because bool(function object) is always true see here, a python function is a callable object.

Take:

def f(x):
    return x < 5

def g(x):
    return lambda: x < 5

def h(x):
    return lambda x=x: x < 5

I advise to do:

ls = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print([x for x in ls if f(x)]) # list comprehension
# is equivalent to filter(lambda x: x < 5, ls) iterator
# To get list :
# [x for x in filter(lambda x: x < 5, ls)]
# is equivalent to list(filter(lambda x: x < 5, ls))

Output:

[0,1,2,3,4]

To call g to do:

g(1)() # True

Do:

 print([x for x in ls if g(x)()])

Output:

[0,1,2,3,4]

To call h to do:

h(1)() # True

or

h(1)(5) # False the second argument overrides the first one

Do:

print([x for x in ls if h(x)(x)])
# or print([x for x in ls if h(x)()])

Output:

[0,1,2,3,4]

See documentation to use filter:

Construct a list from those elements of iterable for which function returns true. iterable may be either a sequence, a container which supports iteration, or an iterator. If iterable is a string or a tuple, the result also has that type; otherwise it is always a list. If function is None, the identity function is assumed, that is, all elements of iterable that are false are removed.

Note that filter(function, iterable) is equivalent to [item for item in iterable if function(item)] if function is not None and [item for item in iterable if item] if function is None.

See documentation to use lambda expression:

lambda arguments: expression with :

def <lambda>(arguments):
    return expression
Community
  • 1
  • 1
glegoux
  • 3,505
  • 15
  • 32
0

g(x) and h(x) are returning the lambda function itself (<function __main__.<lambda>>), but not executing it.

Try for example: g(3)() that will return the desired value.

Therefore running g(x)() or h(x)() will work:

[x for x in filter(lambda x: g(x)(), ls)]  # [0,1,2,3,4]
[x for x in filter(lambda x: h(x)(), ls)]  # [0,1,2,3,4]

While running only g(x) or h(x) will return the lambda function itself per each value, which is equivalent to True statement in filter function, and therefore no value is filtered.


and of course, in this case you can just run:

filter(lambda x: x<5, ls)

or even a better list comprehension approach:

[x for x in ls if x<5]
Dimgold
  • 2,748
  • 5
  • 26
  • 49