Is there any way to optimise my if else condition in python?
if not is_text or not is_archive or not is_hidden or \
not is_system_file or not is_xhtml or not is_audio or not is_video:
is_unrecognised = True
else:
#get the value which is True out of
#is_text, is_archive, is_hidden, is_system_file,
#is_xhtml, is_audio, is_video
I'm feeling that this could be bad idea to write the if condition in this way. So I divided them in to the function and written the code. But Can we optimise my this code to feel it readable and efficient?
8 Answers 8
Read De Morgan's laws:
"not (A and B)" is the same as "(not A) or (not B)"
all(iterable): Return True if all elements of the iterable are true (or if the iterable is empty).
any(iterable): Return True if any element of the iterable is true. If the iterable is empty, return Falseconditions = ( # make a tuple: an iterable is_text, is_archive, is_hidden, is_system_file, is_xhtml, is_audio, is_video ) if not all(conditions): # apply De Morgans is_unrecognised = True else: # other code
Btw, if it meets to your requirement, it can be further simplified without if as
is_unrecognised = not all(conditions)
# may be you can write
# if not is_unrecognised:
# you code in else
3 Comments
any(), all() supports short-circuiting and stops evaluating as soon as result evaluated.First of all, I would try to use try: except: than if: else:. It is faster, for a reason that I do not completely understand. The only thing is that your statement have to rise exception.
Another way is to do it like that:
if False in [is_text, is_archive, is_hidden, is_system_file, is_xhtml, is_audio, is_video]:
1 Comment
any() and all(). Thank youBoolean algebra satisfies De Morgan's laws,
(De Morgan 1) (¬x)∧(¬y) = ¬(x∨y)
(De Morgan 2) (¬x)∨(¬y) = ¬(x∧y).
Thus you could change it to
if not ( is_text and is_archive and is_hidden and is_system_file and is_xhtml and is_audio and is_video):
is_unrecognised = True
else:
#get the value which is True out of
#is_text, is_archive, is_hidden, is_system_file,
#is_xhtml, is_audio, is_video
Comments
It looks like you will have to find out exactly which of the conditions is true anyway. In that case, I'd suggest to write it like this:
if is_text:
# do something
elif is_archive:
...
elif is_video:
# do something
else:
is_unrecognised = True
This construction is similar to a switch or case statement in other languages.
Edit: and yes, as suggested in the comments, perhaps your original code should contain ands instead of ors. So that it goes like: if it is (1) not a text and (2) not a video and (...) not all other recognizable things, then it is unrecognized.
5 Comments
#get the value which is True out of... comment supposed to mean, then?I think the shortest and Pythonic wa to do it is some modification from the @Grijesh answer. Namely,
conditions = (
is_text,
is_archive,
is_hidden,
is_system_file,
is_xhtml,
is_audio,
is_video
)
is_unrecognised = True if not any(conditions) else False
Comments
What everyone else has said so far is correct, that you can use De Morgan's laws and rewrite the if test.
However, as far as I can see the biggest problem at the moment is that if I understand your code correctly, it doesn't do what you think it does.
What you actually want seems to be either
if not (is_text or is_archive or is_hidden or \
is_system_file or is_xhtml or is_audio or is_video):
is_unrecognised = True
or
if not any(is_text, is_archive, is_hidden, is_system_file, is_xhtml, is_audio, is_video):
is_unrecognised = True
Edit: Or Gassa's solution which seems to be even more in line with what you are actually trying to do.
Comments
Your data representation may be leading you astray here. What if instead you did something like
tests = dict()
testkeys = ['text', 'archive', 'hidden', 'system', 'xhtml', 'audio', 'video']
[tests[i] = False for i in testkeys]
# whatever code you have now to set is_text should now instead set tests['text'], etc
if not True in tests.values():
is_unrecognized = True
else:
recognized = [k for k in tests if tests[k] is True] # f'rinstance
(I'm sure there are more idiomatic ways of doing this. Just suggesting a different mode of thinking, really.)
Comments
Even though this question has already been answered. I present an alternative which covers a comment in the code of the question.
As pointed out by @tripleee the original question asked in the code comment to get the variables with value True.
@tripleee's answer asumes creating a dictionnary with the variable names.
An alternative to it is to get the names from locals. The following code
is_text = False
is_archive = True
is_hidden = False
is_system_file = False
is_xhtml = False
is_audio = True
is_video = False
the_size = 34 # <- note also this
conditions = (
is_text,
is_archive,
is_hidden,
is_system_file,
is_xhtml,
is_audio,
is_video,
the_size,
)
result = [(k, v) for k, v in list(locals().iteritems()) \
if id(v) in [id(condition) for condition in conditions] and v]
if len(result) == 0:
is_unrecognized = True
else:
# do what you want with your variables which have value True
# as example print the variable names and values
for k, v in result:
print 'variable "%s" is %s' % (k, v)
is_hiddeneven in there, anyway? Does whether a file is hidden or not really have any bearing on whether you recognize it?)