One liner to "assign if not None" - python

Is there a way to do an assignment only if the assigned value is not None, and otherwise do nothing?
Of course we can do:
x = get_value() if get_value() is not None
but this will read the value twice. We can cache it to a local variable:
v = get_value()
x = v if v is not None
but now we have made two statements for a simple thing.
We could write a function:
def return_if_not_none(v, default):
if v is not None:
return v
else:
return default
And then do x = return_if_not_none(get_value(), x). But surely there is already a Python idiom to accomplish this, without accessing x or get_value() twice and without creating variables?
Put in another way, let's say =?? is a Python operator similar to the C# null coalesce operator. Unlike the C# ??=, our fictional operator checks if the right hand side is None:
x = 1
y = 2
z = None
x =?? y
print(x) # Prints "2"
x =?? z
print(x) # Still prints "2"
Such a =?? operator would do exactly what my question is asking.

In python 3.8 you can do something like this
if (v := get_value()) is not None:
x = v
Updated based on Ryan Haining solution, see in comments

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

Python how to reduce this two-liner to one line?

x = f1(x)
x = f2(x, x)
How do I write this in a single line? Obviously I don't want to write x = f2(f1(x), f1(x)) since it performs the same operation twice, but do I really have to do a two-liner here?
You should probably just keep it as two lines, it is perfectly clear that way. But if you must you can use an assignment expression:
>>> def f1(a): return a + 42
...
>>> def f2(b, c): return b + c
...
>>> f2(x:=f1(1), x)
86
>>>
But again, don't try to cram your code into one line. Rarely is a code improved by trying to make a "one-liner". Write clear, readable, and maintainable code. Don't try to write the shortest code possible. That is maybe fun if you are playing code-golf, but it isn't what you should do if you are trying to write software that is actually going to be used.
This is horrendous, and 2 clear lines is better than 1 obfuscated line, but...
x = f2(*itertools.repeat(f1(x), 2))
Example of use:
import itertools
def f1(x):
return 2*x
def f2(x1, x2):
return x1+x2
x = 1
x = f2(*itertools.repeat(f1(x), 2))
print(x)
Prints 4.
This really doesn't seem like a good place to condense things down to one line, but if you must, here's the way I would go about it.
Let's take the function f2. Normally, you'd pass in parameters like this:
x = f2("foo", "bar")
But you can also use a tuple containing "foo" and "bar" and extract the values as arguments for your function using this syntax:
t = ("foo", "bar")
x = f2(*t)
So if you construct a tuple with two of the same element, you can use that syntax to pass the same value to both arguments:
t = (f1(x),) * 2
x = f2(*t)
Now just eliminate the temporary variable t to make it a one-liner:
x = f2(*(f1(x),) * 2)
Obviously this isn't very intuitive or readable though, so I'd recommend against it.
One other option you have if you're using Python 3.8 or higher is to use the "walrus operator", which assigns a value and acts as an expression that evaluates to that value. For example, the below expression is equal to 5, but also sets x to 2 in the process of its evaluation:
(x := 2) + 3
Here's your solution for a one-liner using the walrus operator:
x = f2(x := f1(x), x)
Basically, x is set to f1(x), then reused for the second parameter of f2. This one might be a little more readable but it still isn't perfect.

Making a variable conditionally global

Suppose that I'm required to run a function with a loop in it until I meet a condition. For the function to work right, I'm only allowed to return one value in the function, but once the condition clears, I want to bring some of the calculations I performed into the global scope. I'm not allowed to use the return command to do this, so I decided to globalize the variables in post. This raises a warning, but seems to work alright. Is this the best way to do things?
Here's an example:
def check_cond(x,cond):
return (x - cond,3)
def loop(x,func):
relevant_value = 0
while x > 0:
local_expensive_calculation = 1 #use your imagination
x = func(x,local_expensive_calculation)[0]
relevant_value += func(x,local_expensive_calculation)[1]
if x == 0:
global local_expensive_calculation
return relevant_value
x = 4
loop(x,check_cond)
#then do stuff with local_expensive_calculation, which is now global
This may be slightly abusing the system but you can set your variable as an attribute of the function, and then access it later through that namespace:
def check_cond(x,cond):
return (x - cond,3)
def loop(x,func):
relevant_value = 0
while x > 0:
local_expensive_calculation = 1 #use your imagination
x = func(x,local_expensive_calculation)[0]
relevant_value += func(x,local_expensive_calculation)[1]
if x == 0:
loop.local_expensive_calculation = local_expensive_calculation
return relevant_value
x = 4
loop(x,check_cond)
print loop.local_expensive_calculation
If you absolutely insist on having it as a global, one way you can do that is by changing the line:
global local_expensive_calculation
to:
globals()['local_expensive_calculation'] = local_expensive_calculation
It makes your SyntaxWarning disappear.
I don't know much about the context and it appears you want a Python 2.7 answer (Python 3.?) has nonlocal.
Bear in mind that the while statement can also have a else clause
You can write:
while x>0:
# do calculation and stuff
else:
# make calculation result global
PS: There's a typo in your assignment to x: (calcuation --> calculation)

Best way to do conditional assignment in python

I tend to use this a lot, but it's ugly:
a = (lambda x: x if x else y)(get_something())
So I wrote this function:
def either(val, alt):
if val:
return val
else:
return alt
So you can do:
a = either(get_something(), y)
Is there a built-in function for this (similar to ISNULL in T-SQL)?
The or operator does what you want:
get_something() or y
In fact, it's chainable, like COALESCE (and unlike ISNULL). The following expression evaluates to the left-most argument that converts to True.
A or B or C
Easy!
For more conditional code:
a = b if b else val
For your code:
a = get_something() if get_something() else val
With that you can do complex conditions like this:
a = get_something() if get_something()/2!=0 else val
You may use:
a = get_something() or y
If get_something is True in boolean context, its value will be assigned to a. Otherwise - y will be assigned to a.
You can use a simple or, like so:
>>> a = None
>>> b = 1
>>> c = (a or b) # parentheses are optional
>>> c
1
I have provided an answer to this question to another user. Check it out here:
Answer to similar question
To respond quickly here, do:
x = true_value if condition else false_value
I'm also using the (a,b)[condition based on the value of a] form, saving the result of the get_something() call into a, in the rare cases that are best presented here: http://mail.python.org/pipermail/python-list/2002-September/785515.html
...
a=0 b=None a or b => None (a,b)[a is None] => 0
a=() b=None a or b => None (a,b)[a is None] => ()
...

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

Categories

Resources