Is there a Python equivalent of the Haskell 'let' - python

Is there a Python equivalent of the Haskell 'let' expression that would allow me to write something like:
list2 = [let (name,size)=lookup(productId) in (barcode(productId),metric(size))
for productId in list]
If not, what would be the most readable alternative?
Added for clarification of the let syntax:
x = let (name,size)=lookup(productId) in (barcode(productId),metric(size))
is equivalent to
(name,size) = lookup(productId)
x = (barcode(productId),metric(size))
The second version doesn't work that well with list comprehensions, though.

You could use a temporary list comprehension
[(barcode(productId), metric(size)) for name, size in [lookup(productId)]][0]
or, equivalently, a generator expression
next((barcode(productId), metric(size)) for name, size in [lookup(productId)])
but both of those are pretty horrible.
Another (horrible) method is via a temporary lambda, which you call immediately
(lambda (name, size): (barcode(productId), metric(size)))(lookup(productId))
I think the recommended "Pythonic" way would just be to define a function, like
def barcode_metric(productId):
name, size = lookup(productId)
return barcode(productId), metric(size)
list2 = [barcode_metric(productId) for productId in list]

Recent python versions allows multiple for clauses in a generator expression, so you can now do something like:
list2 = [ barcode(productID), metric(size)
for productID in list
for (name,size) in (lookup(productID),) ]
which is similar to what Haskell provides too:
list2 = [ (barcode productID, metric size)
| productID <- list
, let (name,size) = lookup productID ]
and denotationally equivalent to
list2 = [ (barcode productID, metric size)
| productID <- list
, (name,size) <- [lookup productID] ]

There is no such thing. You could emulate it the same way let is desugared to lambda calculus (let x = foo in bar <=> (\x -> bar) (foo)).
The most readable alternative depends on the circumstances. For your specific example, I'd choose something like [barcode(productId), metric(size) for productId, (_, size) in zip(productIds, map(lookup, productIds))] (really ugly on second thought, it's easier if you don't need productId too, then you could use map) or an explicit for loop (in a generator):
def barcodes_and_metrics(productIds):
for productId in productIds:
_, size = lookup(productId)
yield barcode(productId), metric(size)

The multiple for clauses in b0fh's answer is the style I have personally been using for a while now, as I believe it provides more clarity and doesn't clutter the namespace with temporary functions. However, if speed is an issue, it is important to remember that temporarily constructing a one element list takes notably longer than constructing a one-tuple.
Comparing the speed of the various solutions in this thread, I found that the ugly lambda hack is slowest, followed by the nested generators and then the solution by b0fh. However, these were all surpassed by the one-tuple winner:
list2 = [ barcode(productID), metric(size)
for productID in list
for (_, size) in (lookup(productID),) ]
This may not be so relevant to the OP's question, but there are other cases where clarity can be greatly enhanced and speed gained in cases where one might wish to use a list comprehension, by using one-tuples instead of lists for dummy iterators.

In Python 3.8, assignment expressions using the := operator were added: PEP 572.
This can be used somewhat like let in Haskell, although iterable unpacking is not supported.
list2 = [
(lookup_result := lookup(productId), # store tuple since iterable unpacking isn't supported
name := lookup_result[0], # manually unpack tuple
size := lookup_result[1],
(barcode(productId), metric(size)))[-1] # put result as the last item in the tuple, then extract on the result using the (...)[-1]
for productId in list1
]
Note that this is scoped like a normal Python assignment, e.g. if used inside a function, the variables bound will be accessible throughout the entire function, not just in the expression.

Only guessing at what Haskell does, here's the alternative. It uses what's known in Python as "list comprehension".
[barcode(productId), metric(size)
for (productId, (name, size)) in [
(productId, lookup(productId)) for productId in list_]
]
You could include the use of lambda:, as others have suggested.

Since you asked for best readability you could consider the lambda-option but with a small twist: initialise the arguments. Here are various options I use myself, starting with the first I tried and ending with the one I use most now.
Suppose we have a function (not shown) which gets data_structure as argument, and you need to get x from it repeatedly.
First try (as per 2012 answer from huon):
(lambda x:
x * x + 42 * x)
(data_structure['a']['b'])
With multiple symbols this becomes less readable, so next I tried:
(lambda x, y:
x * x + 42 * x + y)
(x = data_structure['a']['b'],
y = 16)
That is still not very readable as it repeats the symbolic names. So then I tried:
(lambda x = data_structure['a']['b'],
y = 16:
x * x + 42 * x + y)()
This almost reads as an 'let' expression. The positioning and formatting of the assignments is yours of course.
This idiom is easily recognised by the starting '(' and the ending '()'.
In functional expressions (also in Python), many parenthesis tend to pile up at the end. The odd one out '(' is easily spotted.

class let:
def __init__(self, var):
self.x = var
def __enter__(self):
return self.x
def __exit__(self, type, value, traceback):
pass
with let(os.path) as p:
print(p)
But this is effectively the same as p = os.path as p's scope is not confined to the with block. To achieve that, you'd need
class let:
def __init__(self, var):
self.value = var
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
del var.value
var.value = None
with let(os.path) as var:
print(var.value) # same as print(os.path)
print(var.value) # same as print(None)
Here var.value will be None outside of the with block, but os.path within it.

To get something vaguely comparable, you'll either need to do two comprehensions or maps, or define a new function. One approach that hasn't been suggested yet is to break it up into two lines like so. I believe this is somewhat readable; though probably defining your own function is the right way to go:
pids_names_sizes = (pid, lookup(pid) for pid in list1)
list2 = [(barcode(pid), metric(size)) for pid, (name, size) in pids_names_sizes]

Although you can simply write this as:
list2 = [(barcode(pid), metric(lookup(pid)[1]))
for pid in list]
You could define LET yourself to get:
list2 = [LET(('size', lookup(pid)[1]),
lambda o: (barcode(pid), metric(o.size)))
for pid in list]
or even:
list2 = map(lambda pid: LET(('name_size', lookup(pid),
'size', lambda o: o.name_size[1]),
lambda o: (barcode(pid), metric(o.size))),
list)
as follows:
import types
def _obj():
return lambda: None
def LET(bindings, body, env=None):
'''Introduce local bindings.
ex: LET(('a', 1,
'b', 2),
lambda o: [o.a, o.b])
gives: [1, 2]
Bindings down the chain can depend on
the ones above them through a lambda.
ex: LET(('a', 1,
'b', lambda o: o.a + 1),
lambda o: o.b)
gives: 2
'''
if len(bindings) == 0:
return body(env)
env = env or _obj()
k, v = bindings[:2]
if isinstance(v, types.FunctionType):
v = v(env)
setattr(env, k, v)
return LET(bindings[2:], body, env)

Related

How do you change a variable in a tkinter command without making it bulky with functions? [duplicate]

I have a list of objects and I want to remove all objects that are empty except for one, using filter and a lambda expression.
For example if the input is:
[Object(name=""), Object(name="fake_name"), Object(name="")]
...then the output should be:
[Object(name=""), Object(name="fake_name")]
Is there a way to add an assignment to a lambda expression? For example:
flag = True
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = filter(
(lambda o: [flag or bool(o.name), flag = flag and bool(o.name)][0]),
input
)
The assignment expression operator := added in Python 3.8 supports assignment inside of lambda expressions. This operator can only appear within a parenthesized (...), bracketed [...], or braced {...} expression for syntactic reasons. For example, we will be able to write the following:
import sys
say_hello = lambda: (
message := "Hello world",
sys.stdout.write(message + "\n")
)[-1]
say_hello()
In Python 2, it was possible to perform local assignments as a side effect of list comprehensions.
import sys
say_hello = lambda: (
[None for message in ["Hello world"]],
sys.stdout.write(message + "\n")
)[-1]
say_hello()
However, it's not possible to use either of these in your example because your variable flag is in an outer scope, not the lambda's scope. This doesn't have to do with lambda, it's the general behaviour in Python 2. Python 3 lets you get around this with the nonlocal keyword inside of defs, but nonlocal can't be used inside lambdas.
There's a workaround (see below), but while we're on the topic...
In some cases you can use this to do everything inside of a lambda:
(lambda: [
['def'
for sys in [__import__('sys')]
for math in [__import__('math')]
for sub in [lambda *vals: None]
for fun in [lambda *vals: vals[-1]]
for echo in [lambda *vals: sub(
sys.stdout.write(u" ".join(map(unicode, vals)) + u"\n"))]
for Cylinder in [type('Cylinder', (object,), dict(
__init__ = lambda self, radius, height: sub(
setattr(self, 'radius', radius),
setattr(self, 'height', height)),
volume = property(lambda self: fun(
['def' for top_area in [math.pi * self.radius ** 2]],
self.height * top_area))))]
for main in [lambda: sub(
['loop' for factor in [1, 2, 3] if sub(
['def'
for my_radius, my_height in [[10 * factor, 20 * factor]]
for my_cylinder in [Cylinder(my_radius, my_height)]],
echo(u"A cylinder with a radius of %.1fcm and a height "
u"of %.1fcm has a volume of %.1fcm³."
% (my_radius, my_height, my_cylinder.volume)))])]],
main()])()
A cylinder with a radius of 10.0cm and a height of 20.0cm has a volume of 6283.2cm³.
A cylinder with a radius of 20.0cm and a height of 40.0cm has a volume of 50265.5cm³.
A cylinder with a radius of 30.0cm and a height of 60.0cm has a volume of 169646.0cm³.
Please don't.
...back to your original example: though you can't perform assignments to the flag variable in the outer scope, you can use functions to modify the previously-assigned value.
For example, flag could be an object whose .value we set using setattr:
flag = Object(value=True)
input = [Object(name=''), Object(name='fake_name'), Object(name='')]
output = filter(lambda o: [
flag.value or bool(o.name),
setattr(flag, 'value', flag.value and bool(o.name))
][0], input)
[Object(name=''), Object(name='fake_name')]
If we wanted to fit the above theme, we could use a list comprehension instead of setattr:
[None for flag.value in [bool(o.name)]]
But really, in serious code you should always use a regular function definition instead of a lambda if you're going to be doing outer assignment.
flag = Object(value=True)
def not_empty_except_first(o):
result = flag.value or bool(o.name)
flag.value = flag.value and bool(o.name)
return result
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = filter(not_empty_except_first, input)
You cannot really maintain state in a filter/lambda expression (unless abusing the global namespace). You can however achieve something similar using the accumulated result being passed around in a reduce() expression:
>>> f = lambda a, b: (a.append(b) or a) if (b not in a) else a
>>> input = ["foo", u"", "bar", "", "", "x"]
>>> reduce(f, input, [])
['foo', u'', 'bar', 'x']
>>>
You can, of course, tweak the condition a bit. In this case it filters out duplicates, but you can also use a.count(""), for example, to only restrict empty strings.
Needless to say, you can do this but you really shouldn't. :)
Lastly, you can do anything in pure Python lambda: http://vanderwijk.info/blog/pure-lambda-calculus-python/
Normal assignment (=) is not possible inside a lambda expression, although it is possible to perform various tricks with setattr and friends.
Solving your problem, however, is actually quite simple:
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = filter(
lambda o, _seen=set():
not (not o and o in _seen or _seen.add(o)),
input
)
which will give you
[Object(Object(name=''), name='fake_name')]
As you can see, it's keeping the first blank instance instead of the last. If you need the last instead, reverse the list going in to filter, and reverse the list coming out of filter:
output = filter(
lambda o, _seen=set():
not (not o and o in _seen or _seen.add(o)),
input[::-1]
)[::-1]
which will give you
[Object(name='fake_name'), Object(name='')]
One thing to be aware of: in order for this to work with arbitrary objects, those objects must properly implement __eq__ and __hash__ as explained here.
There's no need to use a lambda, when you can remove all the null ones, and put one back if the input size changes:
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = [x for x in input if x.name]
if(len(input) != len(output)):
output.append(Object(name=""))
UPDATE:
[o for d in [{}] for o in lst if o.name != "" or d.setdefault("", o) == o]
or using filter and lambda:
flag = {}
filter(lambda o: bool(o.name) or flag.setdefault("", o) == o, lst)
Previous Answer
OK, are you stuck on using filter and lambda?
It seems like this would be better served with a dictionary comprehension,
{o.name : o for o in input}.values()
I think the reason that Python doesn't allow assignment in a lambda is similar to why it doesn't allow assignment in a comprehension and that's got something to do with the fact that these things are evaluated on the C side and thus can give us an increase in speed. At least that's my impression after reading one of Guido's essays.
My guess is this would also go against the philosophy of having one right way of doing any one thing in Python.
TL;DR: When using functional idioms it's better to write functional code
As many people have pointed out, in Python lambdas assignment is not allowed. In general when using functional idioms your better off thinking in a functional manner which means wherever possible no side effects and no assignments.
Here is functional solution which uses a lambda. I've assigned the lambda to fn for clarity (and because it got a little long-ish).
from operator import add
from itertools import ifilter, ifilterfalse
fn = lambda l, pred: add(list(ifilter(pred, iter(l))), [ifilterfalse(pred, iter(l)).next()])
objs = [Object(name=""), Object(name="fake_name"), Object(name="")]
fn(objs, lambda o: o.name != '')
You can also make this deal with iterators rather than lists by changing things around a little. You also have some different imports.
from itertools import chain, islice, ifilter, ifilterfalse
fn = lambda l, pred: chain(ifilter(pred, iter(l)), islice(ifilterfalse(pred, iter(l)), 1))
You can always reoganize the code to reduce the length of the statements.
The pythonic way to track state during iteration is with generators. The itertools way is quite hard to understand IMHO and trying to hack lambdas to do this is plain silly. I'd try:
def keep_last_empty(input):
last = None
for item in iter(input):
if item.name: yield item
else: last = item
if last is not None: yield last
output = list(keep_last_empty(input))
Overall, readability trumps compactness every time.
If instead of flag = True we can do an import instead, then I think this meets the criteria:
>>> from itertools import count
>>> a = ['hello', '', 'world', '', '', '', 'bob']
>>> filter(lambda L, j=count(): L or not next(j), a)
['hello', '', 'world', 'bob']
Or maybe the filter is better written as:
>>> filter(lambda L, blank_count=count(1): L or next(blank_count) == 1, a)
Or, just for a simple boolean, without any imports:
filter(lambda L, use_blank=iter([True]): L or next(use_blank, False), a)
No, you cannot put an assignment inside a lambda because of its own definition. If you work using functional programming, then you must assume that your values are not mutable.
One solution would be the following code:
output = lambda l, name: [] if l==[] \
else [ l[ 0 ] ] + output( l[1:], name ) if l[ 0 ].name == name \
else output( l[1:], name ) if l[ 0 ].name == "" \
else [ l[ 0 ] ] + output( l[1:], name )
If you need a lambda to remember state between calls, I would recommend either a function declared in the local namespace or a class with an overloaded __call__. Now that all my cautions against what you are trying to do is out of the way, we can get to an actual answer to your query.
If you really need to have your lambda to have some memory between calls, you can define it like:
f = lambda o, ns = {"flag":True}: [ns["flag"] or o.name, ns.__setitem__("flag", ns["flag"] and o.name)][0]
Then you just need to pass f to filter(). If you really need to, you can get back the value of flag with the following:
f.__defaults__[0]["flag"]
Alternatively, you can modify the global namespace by modifying the result of globals(). Unfortunately, you cannot modify the local namespace in the same way as modifying the result of locals() doesn't affect the local namespace.
You can use a bind function to use a pseudo multi-statement lambda. Then you can use a wrapper class for a Flag to enable assignment.
bind = lambda x, f=(lambda y: y): f(x)
class Flag(object):
def __init__(self, value):
self.value = value
def set(self, value):
self.value = value
return value
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
flag = Flag(True)
output = filter(
lambda o: (
bind(flag.value, lambda orig_flag_value:
bind(flag.set(flag.value and bool(o.name)), lambda _:
bind(orig_flag_value or bool(o.name))))),
input)
Kind of a messy workaround, but assignment in lambdas is illegal anyway, so it doesn't really matter. You can use the builtin exec() function to run assignment from inside the lambda, such as this example:
>>> val
Traceback (most recent call last):
File "<pyshell#31>", line 1, in <module>
val
NameError: name 'val' is not defined
>>> d = lambda: exec('val=True', globals())
>>> d()
>>> val
True
first , you dont need to use a local assigment for your job, just check the above answer
second, its simple to use locals() and globals() to got the variables table and then change the value
check this sample code:
print [locals().__setitem__('x', 'Hillo :]'), x][-1]
if you need to change the add a global variable to your environ, try to replace locals() with globals()
python's list comp is cool but most of the triditional project dont accept this(like flask :[)
hope it could help

Compressing "n"-time object member call

Is there any non-explicit for way to call a member n times upon an object?
I was thinking about some map/reduce/lambda approach, but I couldn't figure out a way to do this -- if it's possible.
Just to add context, I'm using BeautifulSoup, and I'm extracting some elements from an html table; I extract some elements, and then, the last one.
Since I have:
# First value
print value.text
# Second value
value = value.nextSibling
print value.text
# Ninth value
for i in xrange(1, 7):
value = value.nextSibling
print value.text
I was wondering if there's any lambda approach -- or something else -- that would allow me to do this:
# Ninth value
((value = value.nextSibling) for i in xrange(1, 7))
print value.text
P.S.: No, there's no problem whatsoever with the for approach, except I really enjoy one-liner solutions, and this would fit really nice in my code.
I have a strong preference for the loop, but you could use reduce:
>>> class Foo(object):
... def __init__(self):
... self.count = 0
... def callme(self):
... self.count += 1
... return self
...
>>> a = Foo()
>>> reduce(lambda x,y:x.callme(),range(7),a)
<__main__.Foo object at 0xec390>
>>> a.count
7
You want a one-liner equivalent of this:
for i in xrange(1, 7):
value = value.nextSibling
This is one line:
for i in xrange(1, 7): value = value.nextSibling
If you're looking for something more functional, what you really want is a compose function, so you can compose callme() (or attrgetter('my_prop'), or whatever) 7 times.
In case of BS you can use nextSiblingGenerator() with itertools.islice to get the nth sibling. It would also handle situations where there is no nth element.
from itertools import islice
nth = 7
next(islice(elem.nextSiblingGenerator(), nth, None), None)
Disclaimer: eval is evil.
value = eval('value' + ('.nextSibling' * 7))
Ah! But reduce is not available in Python3, at least not as a built in.
So here is my try, portable to Python2/3 and based on the OP failed attempt:
[globals().update(value=value.nextSibling) for i in range(7)]
That assumes that value is a global variable. If value happens to be a member variable, then write instead:
[self.__dict__.update(value=value.nextSibling) for i in range(7)]
You cannot use locals() because the list comprehension creates a nested local scope, so the real locals() is not directly available. However, you can capture it with a bit of work:
(lambda loc : [loc.update(x=x.nextSibling) for i in range(7)])(locals())
Or easier if you don't mind duplicating the number of lines:
loc = locals()
[loc.update(value=value.nextSibling) for i in range(7)]
Or if you really fancy one-liners:
loc = locals() ; [loc.update(value=value.nextSibling) for i in range(7)]
Yes, Python can use ; too 8-)
UPDATE:
Another fancy variation, now with map instead of the list comprehension:
list(map(lambda d : d.update(value=value.nextSibling), 7 * [locals()]))
Note the clever use of list multiplication to capture the current locals() and create the initial iterable at the same time.
The most direct way to write it would be:
value = reduce(lambda x, _: x.nextSibling, xrange(1,7), value)

Assignment inside lambda expression in Python

I have a list of objects and I want to remove all objects that are empty except for one, using filter and a lambda expression.
For example if the input is:
[Object(name=""), Object(name="fake_name"), Object(name="")]
...then the output should be:
[Object(name=""), Object(name="fake_name")]
Is there a way to add an assignment to a lambda expression? For example:
flag = True
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = filter(
(lambda o: [flag or bool(o.name), flag = flag and bool(o.name)][0]),
input
)
The assignment expression operator := added in Python 3.8 supports assignment inside of lambda expressions. This operator can only appear within a parenthesized (...), bracketed [...], or braced {...} expression for syntactic reasons. For example, we will be able to write the following:
import sys
say_hello = lambda: (
message := "Hello world",
sys.stdout.write(message + "\n")
)[-1]
say_hello()
In Python 2, it was possible to perform local assignments as a side effect of list comprehensions.
import sys
say_hello = lambda: (
[None for message in ["Hello world"]],
sys.stdout.write(message + "\n")
)[-1]
say_hello()
However, it's not possible to use either of these in your example because your variable flag is in an outer scope, not the lambda's scope. This doesn't have to do with lambda, it's the general behaviour in Python 2. Python 3 lets you get around this with the nonlocal keyword inside of defs, but nonlocal can't be used inside lambdas.
There's a workaround (see below), but while we're on the topic...
In some cases you can use this to do everything inside of a lambda:
(lambda: [
['def'
for sys in [__import__('sys')]
for math in [__import__('math')]
for sub in [lambda *vals: None]
for fun in [lambda *vals: vals[-1]]
for echo in [lambda *vals: sub(
sys.stdout.write(u" ".join(map(unicode, vals)) + u"\n"))]
for Cylinder in [type('Cylinder', (object,), dict(
__init__ = lambda self, radius, height: sub(
setattr(self, 'radius', radius),
setattr(self, 'height', height)),
volume = property(lambda self: fun(
['def' for top_area in [math.pi * self.radius ** 2]],
self.height * top_area))))]
for main in [lambda: sub(
['loop' for factor in [1, 2, 3] if sub(
['def'
for my_radius, my_height in [[10 * factor, 20 * factor]]
for my_cylinder in [Cylinder(my_radius, my_height)]],
echo(u"A cylinder with a radius of %.1fcm and a height "
u"of %.1fcm has a volume of %.1fcm³."
% (my_radius, my_height, my_cylinder.volume)))])]],
main()])()
A cylinder with a radius of 10.0cm and a height of 20.0cm has a volume of 6283.2cm³.
A cylinder with a radius of 20.0cm and a height of 40.0cm has a volume of 50265.5cm³.
A cylinder with a radius of 30.0cm and a height of 60.0cm has a volume of 169646.0cm³.
Please don't.
...back to your original example: though you can't perform assignments to the flag variable in the outer scope, you can use functions to modify the previously-assigned value.
For example, flag could be an object whose .value we set using setattr:
flag = Object(value=True)
input = [Object(name=''), Object(name='fake_name'), Object(name='')]
output = filter(lambda o: [
flag.value or bool(o.name),
setattr(flag, 'value', flag.value and bool(o.name))
][0], input)
[Object(name=''), Object(name='fake_name')]
If we wanted to fit the above theme, we could use a list comprehension instead of setattr:
[None for flag.value in [bool(o.name)]]
But really, in serious code you should always use a regular function definition instead of a lambda if you're going to be doing outer assignment.
flag = Object(value=True)
def not_empty_except_first(o):
result = flag.value or bool(o.name)
flag.value = flag.value and bool(o.name)
return result
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = filter(not_empty_except_first, input)
You cannot really maintain state in a filter/lambda expression (unless abusing the global namespace). You can however achieve something similar using the accumulated result being passed around in a reduce() expression:
>>> f = lambda a, b: (a.append(b) or a) if (b not in a) else a
>>> input = ["foo", u"", "bar", "", "", "x"]
>>> reduce(f, input, [])
['foo', u'', 'bar', 'x']
>>>
You can, of course, tweak the condition a bit. In this case it filters out duplicates, but you can also use a.count(""), for example, to only restrict empty strings.
Needless to say, you can do this but you really shouldn't. :)
Lastly, you can do anything in pure Python lambda: http://vanderwijk.info/blog/pure-lambda-calculus-python/
Normal assignment (=) is not possible inside a lambda expression, although it is possible to perform various tricks with setattr and friends.
Solving your problem, however, is actually quite simple:
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = filter(
lambda o, _seen=set():
not (not o and o in _seen or _seen.add(o)),
input
)
which will give you
[Object(Object(name=''), name='fake_name')]
As you can see, it's keeping the first blank instance instead of the last. If you need the last instead, reverse the list going in to filter, and reverse the list coming out of filter:
output = filter(
lambda o, _seen=set():
not (not o and o in _seen or _seen.add(o)),
input[::-1]
)[::-1]
which will give you
[Object(name='fake_name'), Object(name='')]
One thing to be aware of: in order for this to work with arbitrary objects, those objects must properly implement __eq__ and __hash__ as explained here.
There's no need to use a lambda, when you can remove all the null ones, and put one back if the input size changes:
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = [x for x in input if x.name]
if(len(input) != len(output)):
output.append(Object(name=""))
UPDATE:
[o for d in [{}] for o in lst if o.name != "" or d.setdefault("", o) == o]
or using filter and lambda:
flag = {}
filter(lambda o: bool(o.name) or flag.setdefault("", o) == o, lst)
Previous Answer
OK, are you stuck on using filter and lambda?
It seems like this would be better served with a dictionary comprehension,
{o.name : o for o in input}.values()
I think the reason that Python doesn't allow assignment in a lambda is similar to why it doesn't allow assignment in a comprehension and that's got something to do with the fact that these things are evaluated on the C side and thus can give us an increase in speed. At least that's my impression after reading one of Guido's essays.
My guess is this would also go against the philosophy of having one right way of doing any one thing in Python.
TL;DR: When using functional idioms it's better to write functional code
As many people have pointed out, in Python lambdas assignment is not allowed. In general when using functional idioms your better off thinking in a functional manner which means wherever possible no side effects and no assignments.
Here is functional solution which uses a lambda. I've assigned the lambda to fn for clarity (and because it got a little long-ish).
from operator import add
from itertools import ifilter, ifilterfalse
fn = lambda l, pred: add(list(ifilter(pred, iter(l))), [ifilterfalse(pred, iter(l)).next()])
objs = [Object(name=""), Object(name="fake_name"), Object(name="")]
fn(objs, lambda o: o.name != '')
You can also make this deal with iterators rather than lists by changing things around a little. You also have some different imports.
from itertools import chain, islice, ifilter, ifilterfalse
fn = lambda l, pred: chain(ifilter(pred, iter(l)), islice(ifilterfalse(pred, iter(l)), 1))
You can always reoganize the code to reduce the length of the statements.
The pythonic way to track state during iteration is with generators. The itertools way is quite hard to understand IMHO and trying to hack lambdas to do this is plain silly. I'd try:
def keep_last_empty(input):
last = None
for item in iter(input):
if item.name: yield item
else: last = item
if last is not None: yield last
output = list(keep_last_empty(input))
Overall, readability trumps compactness every time.
If instead of flag = True we can do an import instead, then I think this meets the criteria:
>>> from itertools import count
>>> a = ['hello', '', 'world', '', '', '', 'bob']
>>> filter(lambda L, j=count(): L or not next(j), a)
['hello', '', 'world', 'bob']
Or maybe the filter is better written as:
>>> filter(lambda L, blank_count=count(1): L or next(blank_count) == 1, a)
Or, just for a simple boolean, without any imports:
filter(lambda L, use_blank=iter([True]): L or next(use_blank, False), a)
No, you cannot put an assignment inside a lambda because of its own definition. If you work using functional programming, then you must assume that your values are not mutable.
One solution would be the following code:
output = lambda l, name: [] if l==[] \
else [ l[ 0 ] ] + output( l[1:], name ) if l[ 0 ].name == name \
else output( l[1:], name ) if l[ 0 ].name == "" \
else [ l[ 0 ] ] + output( l[1:], name )
If you need a lambda to remember state between calls, I would recommend either a function declared in the local namespace or a class with an overloaded __call__. Now that all my cautions against what you are trying to do is out of the way, we can get to an actual answer to your query.
If you really need to have your lambda to have some memory between calls, you can define it like:
f = lambda o, ns = {"flag":True}: [ns["flag"] or o.name, ns.__setitem__("flag", ns["flag"] and o.name)][0]
Then you just need to pass f to filter(). If you really need to, you can get back the value of flag with the following:
f.__defaults__[0]["flag"]
Alternatively, you can modify the global namespace by modifying the result of globals(). Unfortunately, you cannot modify the local namespace in the same way as modifying the result of locals() doesn't affect the local namespace.
You can use a bind function to use a pseudo multi-statement lambda. Then you can use a wrapper class for a Flag to enable assignment.
bind = lambda x, f=(lambda y: y): f(x)
class Flag(object):
def __init__(self, value):
self.value = value
def set(self, value):
self.value = value
return value
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
flag = Flag(True)
output = filter(
lambda o: (
bind(flag.value, lambda orig_flag_value:
bind(flag.set(flag.value and bool(o.name)), lambda _:
bind(orig_flag_value or bool(o.name))))),
input)
Kind of a messy workaround, but assignment in lambdas is illegal anyway, so it doesn't really matter. You can use the builtin exec() function to run assignment from inside the lambda, such as this example:
>>> val
Traceback (most recent call last):
File "<pyshell#31>", line 1, in <module>
val
NameError: name 'val' is not defined
>>> d = lambda: exec('val=True', globals())
>>> d()
>>> val
True
first , you dont need to use a local assigment for your job, just check the above answer
second, its simple to use locals() and globals() to got the variables table and then change the value
check this sample code:
print [locals().__setitem__('x', 'Hillo :]'), x][-1]
if you need to change the add a global variable to your environ, try to replace locals() with globals()
python's list comp is cool but most of the triditional project dont accept this(like flask :[)
hope it could help

Python, lambda, find minimum

I have foreach function which calls specified function on every element which it contains. I want to get minimum from thise elements but I have no idea how to write lambda or function or even a class that would manage that.
Thanks for every help.
I use my foreach function like this:
o.foreach( lambda i: i.call() )
or
o.foreach( I.call )
I don't like to make a lists or other objects. I want to iterate trough it and find min.
I manage to write a class that do the think but there should be some better solution than that:
class Min:
def __init__(self,i):
self.i = i
def get_min(self):
return self.i
def set_val(self,o):
if o.val < self.i: self.i = o.val
m = Min( xmin )
self.foreach( m.set_val )
xmin = m.get_min()
Ok, so I suppose that my .foreach method is non-python idea. I should do my Class iterable because all your solutions are based on lists and then everything will become easier.
In C# there would be no problem with lambda function like that, so I though that python is also that powerful.
Python has built-in support for finding minimums:
>>> min([1, 2, 3])
1
If you need to process the list with a function first, you can do that with map:
>>> def double(x):
... return x * 2
...
>>> min(map(double, [1, 2, 3]))
2
Or you can get fancy with list comprehensions and generator expressions, for example:
>>> min(double(x) for x in [1, 2, 3])
2
You can't do this with foreach and a lambda. If you want to do this in a functional style without actually using min, you'll find reduce is pretty close to the function you were trying to define.
l = [5,2,6,7,9,8]
reduce(lambda a,b: a if a < b else b, l[1:], l[0])
Writing foreach method is not very pythonic. You should better make it an iterator so that it works with standard python functions like min.
Instead of writing something like this:
def foreach(self, f):
for d in self._data:
f(d)
write this:
def __iter__(self):
for d in self._data:
yield d
Now you can call min as min(myobj).
I have foreach function which calls specified function on every element which it contains
It sounds, from the comment you subsequently posted, that you have re-invented the built-in map function.
It sounds like you're looking for something like this:
min(map(f, seq))
where f is the function that you want to call on every item in the list.
As gnibbler shows, if you want to find the value x in the sequence for which f(x) returns the lowest value, you can use:
min(seq, key=f)
...unless you want to find all of the items in seq for which f returns the lowest value. For instance, if seq is a list of dictionaries,
min(seq, key=len)
will return the first dictionary in the list with the smallest number of items, not all dictionaries that contain that number of items.
To get a list of all items in a sequence for which the function f returns the smallest value, do this:
values = map(f, seq)
result = [seq[i] for (i, v) in enumerate(values) if v == min(values)]
Okay, one thing you need to understand: lambda creates a function object for you. But so does plain, ordinary def. Look at this example:
lst = range(10)
print filter(lambda x: x % 2 == 0, lst)
def is_even(x):
return x % 2 == 0
print filter(is_even, lst)
Both of these work. They produce the same identical result. lambda makes an un-named function object; def makes a named function object. filter() doesn't care whether the function object has a name or not.
So, if your only problem with lambda is that you can't use = in a lambda, you can just make a function using def.
Now, that said, I don't suggest you use your .foreach() method to find a minimum value. Instead, make your main object return a list of values, and simply call the Python min() function.
lst = range(10)
print min(lst)
EDIT: I agree that the answer that was accepted is better. Rather than returning a list of values, it is better to define __iter__() and make the object iterable.
Suppose you have
>>> seq = range(-4,4)
>>> def f(x):
... return x*x-2
for the minimum value of f
>>> min(f(x) for x in seq)
-2
for the value of x at the minimum
>>> min(seq, key=f)
0
of course you can use lambda too
>>> min((lambda x:x*x-2)(x) for x in range(-4,4))
-2
but that is a little ugly, map looks better here
>>> min(map(lambda x:x*x-2, seq))
-2
>>> min(seq,key=lambda x:x*x-2)
0
You can use this:
x = lambda x,y,z: min(x,y,z)
print(x(3,2,1))

Most pythonic form for mapping a series of statements?

This is something that has bugged me for some time. I learnt Haskell before I learnt Python, so I've always been fond of thinking of many computations as a mapping onto a list. This is beautifully expressed by a list comprehension (I'm giving the pythonic version here):
result = [ f(x) for x in list ]
In many cases though, we want to execute more than a single statement on x, say:
result = [ f(g(h(x))) for x in list ]
This very quickly gets clunky, and difficult to read.
My normal solution to this is to expand this back into a for loop:
result = []
for x in list:
x0 = h(x)
x1 = g(x0)
x2 = f(x1)
result.append(x2)
One thing about this that bothers me no end is having to initialize the empty list 'result'. It's a triviality, but it makes me unhappy. I was wondering if there were any alternative equivalent forms. One way may be to use a local function(is that what they're called in Python?)
def operation(x):
x0 = h(x)
x1 = g(x0)
x2 = f(x1)
return x2
result = [ operation(x) for x in list ]
Are there any particular advantages/disadvantages to either of the two forms above? Or is there perhaps a more elegant way?
You can easily do function composition in Python.
Here's a demonstrates of a way to create a new function which is a composition of existing functions.
>>> def comp( a, b ):
def compose( args ):
return a( b( args ) )
return compose
>>> def times2(x): return x*2
>>> def plus1(x): return x+1
>>> comp( times2, plus1 )(32)
66
Here's a more complete recipe for function composition. This should make it look less clunky.
Follow the style that most matches your tastes.
I would not worry about performance; only in case you really see some issue you can try to move to a different style.
Here some other possible suggestions, in addition to your proposals:
result = [f(
g(
h(x)
)
)
for x in list]
Use progressive list comprehensions:
result = [h(x) for x in list]
result = [g(x) for x in result]
result = [f(x) for x in result]
Again, that's only a matter of style and taste. Pick the one you prefer most, and stick with it :-)
If this is something you're doing often and with several different statements you could write something like
def seriesoffncs(fncs,x):
for f in fncs[::-1]:
x=f(x)
return x
where fncs is a list of functions. so seriesoffncs((f,g,h),x) would return
f(g(h(x))).
This way if you later in your code need to workout h(q(g(f(x)))) you would simply do seriesoffncs((h,q,g,f),x) rather than make a new operations function for each combination of functions.
If your only concerned with the last result, your last answer is the best. It's clear for anyone looking at it what your doing.
I often take any code that starts to get complex and move it to a function. This basically serves as a comment for that block of code. (any complex code probably needs a re-write anyway, and putting it in a function I can go back and work on it later)
def operation(x):
x0 = h(x)
x1 = g(x0)
x2 = f(x1)
return x2
result = [ operation(x) for x in list]
A variation of dagw.myopenid.com's function:
def chained_apply(*args):
val = args[-1]
for f in fncs[:-1:-1]:
val=f(val)
return val
Instead of seriesoffncs((h,q,g,f),x) now you can call:
result = chained_apply(foo, bar, baz, x)
As far as I know there's no built-in/native syntax for composition in Python, but you can write your own function to compose stuff without too much trouble.
def compose(*f):
return f[0] if len(f) == 1 else lambda *args: f[0](compose(*f[1:])(*args))
def f(x):
return 'o ' + str(x)
def g(x):
return 'hai ' + str(x)
def h(x, y):
return 'there ' + str(x) + str(y) + '\n'
action = compose(f, g, h)
print [action("Test ", item) for item in [1, 2, 3]]
Composing outside the comprehension isn't required, of course.
print [compose(f, g, h)("Test ", item) for item in [1, 2, 3]]
This way of composing will work for any number of functions (well, up to the recursion limit) with any number of parameters for the inner function.
There are cases where it's best to go back to the for-loop, yes, but more often I prefer one of these approaches:
Use appropriate line breaks and indentation to keep it readable:
result = [blah(blah(blah(x)))
for x in list]
Or extract (enough of) the logic into another function, as you mention. But not necessarily local; Python programmers prefer flat to nested structure, if you can see a reasonable way of factoring the functionality out.
I came to Python from the functional-programming world, too, and share your prejudice.

Categories

Resources