0

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?

12
  • 6
    read any() and all() functions Commented Mar 7, 2014 at 9:30
  • see Demorgans theorem en.wikipedia.org/wiki/De_Morgan%27s_laws Commented Mar 7, 2014 at 9:33
  • en.wikipedia.org/wiki/De_Morgan's_laws Commented Mar 7, 2014 at 9:33
  • 4
    There is no loop here. Commented Mar 7, 2014 at 9:35
  • 1
    Your current version is almost certainly not correct, unless you really want to only consider the thing recognized if it is text, an archive, hidden, a system file, xhtml, audio, and video all at once. (Why is is_hidden even in there, anyway? Does whether a file is hidden or not really have any bearing on whether you recognize it?) Commented Mar 7, 2014 at 9:40

8 Answers 8

4
  1. Read De Morgan's laws:

    "not (A and B)" is the same as "(not A) or (not B)"

  2. 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 False

    conditions = (  # 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 
Sign up to request clarification or add additional context in comments.

3 Comments

Is (a) creating an iterable tuple, (b) iterating it, and (b) calling 'any' or 'all' really an optimization? The code is of course more readable. But, is it really optimized?
@wolfrevo may be creating tuple cause extra overhead but if you are thinking of short-circuiting then yes any(), all() supports short-circuiting and stops evaluating as soon as result evaluated.
Yes, I meant that. Thanks for the hint to short-circuiting support!
3

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

I was looking for something like this before! Thanks. But using built-in function is good any() and all(). Thank you
3

Boolean 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

3

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

I don't have to do anything if is_text or is_image or is_audio or is_video .. etc Since nesting is not required here!
What's the #get the value which is True out of... comment supposed to mean, then?
You could be right! Sorry. But I think anyhow nesting is not required to get any true Value out of those!
No, but what do you need the value for? Whatever code needs that answer might make sense to inline here.
What I'm going to say is a bit speculative, but even if you are just assigning a variable, like "if is_text: type = "TEXT" elif is_archive: type = "ARCHIVE" else ...", such an enumeration of cases (call it nesting if you wish) makes sense to future reader. Usually, the code does not have to look clever, it just has to be readable. Sure, it is long-ish though.
1

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

1

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

1

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

1

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.