What Should I Use Instead Of Assignment-in-an-expression In Python?
Solution 1:
I had this problem years ago, in 2001 -- since I was transliterating to Python from a reference-algorithm in C which used assign-and-test heavily, I was keen to keep a similar structure for the first draft (then refactor later once correctness was well tested). So I wrote a recipe in the Cookbook (see also here), which boils down to...:
class DataHolder(object):
def set(self, value): self.value = value; return value
so the if
/elif
tree can become:
dh = DataHolder()
if dh.set(something()):
# do something with dh.value
elif dh.set(somethingelse()):
# ...
the DataHolder
class can clearly be embellished in various ways (and is so embellished in both the online and book versions), but this is the gist of it, and quite sufficient to answer your question.
Solution 2:
Another alternative which offers some flexibility:
# Functions to be tested (can be expanded):
tests = [something, somethingelse, yetsomethingelse, anotherfunction, another]
for i, f in enumerate(tests):
a = f()
if a:
if i == 0:
# do something with a
elif 1 <= i <= 3:
# do something else with a
else:
# ...
break
Or you can explicitly compare to the function:
tests = [something, somethingelse, yetsomethingelse, anotherfunction, another]
for i, f in enumerate(tests):
a = f()
if a: break
if not a:
# no result
elif f == something:
# ...
elif f == somethingelse:
# ...
If some of the functions take arguments, you can use lambda to keep the function paradigm:
tests = [lambda: something(args), somethingelse, lambda: something(otherargs)]
for i, f in enumerate(tests):
a = f()
if a: break
if not a:
# no result
elif i == 0:
# ...
elif i == 1:
# ...
Solution 3:
You could do this:
a = something()
if a:
#do something with a
else:
a = somethingelse()
if a:
#...
else:
#5 more nested ifs
Or, inside a function you can limit the nesting level with a return
in each matching case:
def f():
a = something()
if a:
#do something with a
return
a = somethingelse()
if a:
#...
return
#5 more ifs
Solution 4:
Make yourself a simple callable object that saves its returned value:
class ConditionValue(object):
def __call__(self, x):
self.value = x
return bool(x)
Now use it like this:
# example code
makelower = lambda c : c.isalpha() and c.lower()
add10 = lambda c : c.isdigit() and int(c) + 10
test = "ABC123.DEF456"
val = ConditionValue()
for t in test:
if val(makelower(t)):
print t, "is now lower case ->", val.value
elif val(add10(t)):
print t, "+10 ->", val.value
else:
print "unknown char", t
Prints:
A is now lower case -> a
B is now lower case -> b
C is now lower case -> c
1 +10 -> 11
2 +10 -> 12
3 +10 -> 13
unknown char .
D is now lower case -> d
E is now lower case -> e
F is now lower case -> f
4 +10 -> 14
5 +10 -> 15
6 +10 -> 16
Solution 5:
I might be missing something, but couldn't you factor each of the branches in your top-level if
statement into separate functions, create a list of test to action tuples and loop over them? You should be able to apply this pattern to mimic if (value=condition()) {} else if (value=other_condition()) {}
style logic.
This is really an extension of redglyph's response and can probably be compressed down to a iterator that raises StopIteration
once it has hit a truth value.
#
# These are the "tests" from your original if statements. No
# changes should be necessary.
#
def something():
print('doing something()')
# expensive stuff here
def something_else():
print('doing something_else()')
# expensive stuff here too... but this returns True for some reason
return True
def something_weird():
print('doing something_weird()')
# other expensive stuff
#
# Factor each branch of your if statement into a separate function.
# Each function will receive the output of the test if the test
# was selected.
#
def something_action(value):
print("doing something's action")
def something_else_action(value):
print("doing something_else's action")
def something_weird_action(value):
print("doing something_weird's action")
#
# A simple iteration function that takes tuples of (test,action). The
# test is called. If it returns a truth value, then the value is passed
# onto the associated action and the iteration is stopped.
#
def do_actions(*action_tuples):
for (test,action) in action_tuples:
value = test()
if value:
return action(value)
#
# ... and here is how you would use it:
#
result = do_actions(
(something, something_action),
(something_else, something_else_action),
(something_weird, something_weird_action)
)
Post a Comment for "What Should I Use Instead Of Assignment-in-an-expression In Python?"