So I have a condition I want to happen only when all items in a list evaluate to true. An example of this might be something like a list of functions which return a boolean (not actually my situation but easier to explain):
def foo():
# do something
def bar():
# do something
def baz():
# do something
fncs = [foo, bar, baz]
if <every element in [fnc() for fnc in fncs] evaluates to true>:
# do something
I know I can definitely do this:
all_true = True
for fnc in fncs:
if not fnc():
all_true = False
if all_true:
# do something
But, I was wondering if this is poor form:
if min([fnc() for fnc in fncs]):
# do something
Alternatively, I could try to select all false elements during list comprehension and check whether the list is occupied (this works because bool(arr) where arr is a list returns False if and only if arr is empty):
if not [None for fnc in fncs if not fnc()]:
# do something
I feel like the "min" is a lot cleaner than the last method, and while the first one is easiest to understand for novices it should be pretty clear what's going on. I could alternately make it clearer through aliasing:
all_true = min
if all_true([fnc() for fnc in fncs]):
# do something
I'm sure I missed other ways to do this as well. I'm wondering what method would be most desirable.
Thanks for the help!
Using min is not "bad", but it is unclear what you are trying to do and will do unnecessary work. You should use all instead.
if all(fnc() for fnc in fncs):
# do something
This will return True if all values are True, and False otherwise. It has the added benefit of quitting early if any value is False, unlike min which must run through the entire sequence at least once.
If you find that you need to evaluate if the are all False, I recommend any (well, not any(...), specifically) which has a similar "quit as soon as possible" behavior.
You're probably looking for all built-in function:
print all(f() for f in [foo, bar, baz])
Related
I have a function I'm using to test in an if/then.
The issue is that I'm executing the function BOTH in the if conditional, and then again after the if statement because the function returns two items.
This just seems wasteful and I'm trying to think of ways to improve this. Here's a really basic version of what I'm trying to avoid: "True" is returned to allow the condition to pass, but then then "coolstuff()" is executed again to get more information from the function.
"coolstuff()" could possibly return false, so I can't use the returned string "stuff" as the test.
def coolstuff():
return True, "stuff"
if coolstuff()[0]:
coolthing = coolstuff()[1]
print coolthing
There's gotta be a better way to do this, no? My brain is melting a little as I try to hash it out.
I basically want to do something like this (invalid) syntax:
def coolstuff():
return True, "stuff"
if a, b == coolstuff() and a:
print b
Just collect both results into variables
a, b = fn()
if a:
# work with b
def coolstuff():
if valid:
return "stuff"
return None
data = coolstuff()
if data:
print(data)
Call the function and capture the entire returned value:
x = coolstuff()
Now you have access to both parts of the returned value, in x[0] and x[1].
Store it:
state, coolvar = coolstuff()
if state:
do_whatever(coolvar)
If in newer Python, you could use the dreaded walrus (but I prefer ti7's approach of just assigning in a separate line):
if (x := coolstuff())[0]:
print(x[1])
I have trouble finding a fitting title for this question, so please forgive me.
Many methods in my class look like this:
def one_of_many():
# code to determine `somethings`
for something in somethings:
if self.try_something(something):
return
# code to determine `something_else`
if self.try_something(something_else):
return
…
where self.try_something returns True or False.
Is there a way to express this with something like:
def one_of_many():
# code to determine `somethings`
for something in somethings:
self.try_something_and_return(something) # this will return from `one_of_many` on success
# code to determine `something_else`
self.try_something_and_return(something_else) # this will return from `one_of_many` on success
…
I was fiddling with decorators and context managers to make this happen with no success but I still believe that "There must be a better way!".
It looks like itertools to the rescue:
When you say method, I assume this is a method of a class so the code could look like this:
import itertools
class Thing:
def one_of_many(self):
# code to determine `somethings`
for something in itertools.chain(somethings,[something_else]):
if self.try_something(something):
return
Hopefully something_else is not too difficult to compute.
Hopefully this mcve mimics your problem:
a = [1,2,3]
b = 3
def f(thing):
print(thing)
return False
class F:
pass
self = F()
self.trysomething = f
Map the method to all the things and take action if any return True
if any(map(self.trysomething, a + [b])):
print('yeay')
else:
print('nay')
Depending on what a and b actually are you may have to play around with ways to concatenate or flatten/add or chain as #quamrana mentioned.
if self.try_something(a_thing) or self.try_something(another_thing):
return
But you'll either need to know your thing's beforehand.. or calculate them with an expression within the function call.
Let's say I have several functions that basically do the same thing but on a set of different variables. I think about something like that:
def changex():
if x:
# do procedure1 with x as variable
else:
# do procedure2 with x as variable
def changey():
if y:
# do procedure1 with y as variable
else:
# do procedure2 with y as variable
def changez():
...
How can I simplify that set of functions, such that I only have to write the function once but it does the job for all variables? I already looked into decorators which I think can do the job, but I can't make out how to make it work for my purpose.
Functions can accept variables as parameters.
Something like this:
def change(p):
if p:
# do procedure1 with p as variable
else:
# do procedure2 with p as variable
Then changex() becomes change(x); changey() becomes change(y) etc.
Decorators are way too complex for what you are trying to do. Functions can take arguments, so you can pass in the variable you want to do stuff with:
def change(var):
if var:
procedure1(var)
else:
procedure2(var)
Notice that I used if/else instead of checking both conditions with an if. I also recommend not testing explicitly against True/False. If you must do so, however, it is considered better practice to use is instead of == since True and False are singleton objects in Python: if x is True is better than if x == True.
Python is a language in which the following is possible:
>>> class A(object):
... def __eq__(self, _):
... return True
...
>>> a = A()
>>> a == "slfjghsjdfhgklsfghksjd"
True
>>> a == -87346957234576293847658734659834628572384657346573465
True
>>> a == None
True
>>> a is None
False
Other things, like gt and lt are also "overloadable"1 in this way, and this is a great feature, in my opinion.
I'm curious if the = assignment operator is also "overloadable"1 in a similar kind of fashion, or if I'd have to recompile Python into NotPython to do this.
(As far as I know, classes and objects don't implement some __assign__ method; that's implemented with the C bytecode runner/compiler.)
Specifically, I want to implement an LL(k) parser by iterating on a token list, without using an iterator such that I can change the iterator's index arbitrarily to jump to a given token.
The catch is that on a given cycle of the loop, if I've already arbitrarily modified the index in preparation for the next cycle (something I'll surely do a lot) the last thing I want to do is mess up that variable by adding one to it as if it hadn't been changed.
Probably the easiest, simplest solution to this is to have a flag that gets set on jumps and which is reset to False every cycle, but this can and will introduce tiny hiding bugs I'd like to avoid ahead of time. (See here for what I mean -- this is the pathetic iterative LL(1) parser I'm rewriting, and I want its reincarnation to be somewhat maintainable and/or readable.)
The flag solution:
idx = 0
while True:
jmpd = False
# maybe we jumped, maybe we didn't; how am I to know!?!?
if jmpd == False:
idx += 1
Great! One big drawback: at each possible branch resulting in an arbitrary change in the index, I have to set that flag. Trivial, perhaps (obviously in this example), but to me it seems like a harbinger of unreadable, bug-friendly code.
What's the best way, without using a second variable, to test if a value's changed over time?
If your answer is, "there isn't one, just be quiet and use a flag variable", then I congratulate you for promoting bad code design. /s
1Yeah, I know it's not technically operator overloading; have you a better, more quickly understandable term?
You can use another magic method to intercept assignment of the attribute. It's called __setattr__(). Here is an example of how to use it:
In [2]: class Test(object):
def __setattr__(self, name, value):
print(name, "changed to", value)
super().__setattr__(name, value)
...:
In [3]: t = Test()
In [4]: t.name = 4
name changed to 4
In [5]: t.name = 5
name changed to 5
I mean, if I have a function like this:
def example(foo, bar)
...
return False, True
How can I compare the 2 returns?
if example(foo, bar):
I know that I can do this:
bool1, bool2 = example(foo,bar)
if bool1 and bool2:
...
But, can I compare the 2 of them without seting them in a variable?
Use all.
if all(example(foo, bar)):
# do something
If you need just one positive result you can use any.
It depends on what you want to check. If you can send them to another function to do the checks, it will work without variables. Say if you want to check they're both True:
if all(example()):
...
or any() for one of them.
But if you say want to compare them with each other, you'd call the function twice:
if example()[0] == example()[1]:
and that's usually not desirable. So there I'd simply use the variable.
simply use
if (True, True) == example(foo, bar):
use all command:
if all(example(foo,bar)):
# All returned values are True