91

Is it bad practice to use the following format when my_var can be None?

if my_var and 'something' in my_var:
    #do something

The issue is that 'something' in my_var will throw a TypeError if my_var is None.

Or should I use:

if my_var:
    if 'something' in my_var:
        #do something

or

try:
    if 'something' in my_var:
        #do something
except TypeError:
    pass

To rephrase the question, which of the above is the best practice in Python (if any)?

Alternatives are welcome!

tgray
  • 8,826
  • 5
  • 36
  • 41

6 Answers6

105

It's safe to depend on the order of conditionals (Python reference here), specifically because of the problem you point out - it's very useful to be able to short-circuit evaluation that could cause problems in a string of conditionals.

This sort of code pops up in most languages:

IF exists(variable) AND variable.doSomething()
    THEN ...
Dan Lew
  • 85,990
  • 32
  • 182
  • 176
  • 3
    When I see code like the second, I assume the coder didn't understand how short-circuit evaluation works. – Dana Apr 15 '09 at 16:04
  • 1
    -1: No quote from the documentation: http://docs.python.org/library/stdtypes.html#boolean-operations-and-or-not – S.Lott Apr 15 '09 at 17:02
  • @cfi: Since I can change my vote after the answer changes, I'm unclear on what the problem is. – S.Lott Nov 22 '11 at 19:12
  • @cfi: Do whatever you think is most valuable to others. My -1 on the comment is **unrelated** to my actual vote. Interestingly, that allows one to make a lasting remark unrelated to the actual value of the response. – S.Lott Nov 23 '11 at 00:49
  • 2
    for everyone who is being negative, this is a valid question and isn't the same for every language. VB will evaluate both unless you use `andalso` or `orelse` – blindguy Dec 01 '15 at 22:46
  • @blindguy Hows does C do it? – Saad Rehman Shah Aug 24 '16 at 05:58
42

Yes it is safe, it's explicitly and very clearly defined in the language reference:

The expression x and y first evaluates x; if x is false, its value is returned; otherwise, y is evaluated and the resulting value is returned.

The expression x or y first evaluates x; if x is true, its value is returned; otherwise, y is evaluated and the resulting value is returned.

vartec
  • 131,205
  • 36
  • 218
  • 244
4

I may be being a little pedantic here, but I would say the best answer is

if my_var is not None and 'something' in my_var:
    #do something

The difference being the explicit check for None, rather than the implicit conversion of my_var to True or False.

While I'm sure in your case the distinction isn't important, in the more general case it would be quite possible for the variable to not be None but still evaluate to False, for example an integer value of 0 or an empty list.

So contrary to most of the other posters' assertions that it's safe, I'd say that it's safe as long as you're explicit. If you're not convinced then consider this very contrived class:

class Contrived(object):
    def __contains__(self, s):
        return True
    def __nonzero__(self):
        return False

my_var = Contrived()
if 'something' in my_var:
    print "Yes the condition is true"
if my_var and 'something' in my_var:
    print "But this statement won't get reached."
if my_var is not None and 'something' in my_var:
    print "Whereas this one will."

Yes I know that's not a realistic example, but variations do happen in real code, especially when None is used to indicate a default function argument.

Scott Griffiths
  • 21,438
  • 8
  • 55
  • 85
  • surely, if you have an empty list or any container, for that matter, doing the `in` operation is meaningless. I think OP has it exactly right. while it's possible to construct anything to prove one's point, I don't believe that any decent code should shoot itself in the foot. – SilentGhost Sep 01 '09 at 11:44
  • 1
    Yes, it's a contrived example, but my main point is that it's easy to get into the bad habit of saying '`if var`' when you really mean '`if var is not None`'. Once you get into that habit it can easily bite you, particularly with defaulted arguments. – Scott Griffiths Sep 01 '09 at 12:03
  • I think it's quite clear that OP's intention was to say `if var` and that's what he did. – SilentGhost Sep 01 '09 at 12:05
2

It's not that simple. As a C# dude I am very used to doing something like:

if(x != null && ! string.isnullorempty(x.Name))
{
   //do something
}

The above works great and is evaluated as expected. However in VB.Net the following would produce a result you were NOT expecting:

If Not x Is Nothing **And** Not String.IsNullOrEmpty(x.Name) Then

   'do something

End If

The above will generate an exception. The correct syntax should be

If Not x Is Nothing **AndAlso** Not String.IsNullOrEmpty(x.Name) Then

   'do something

End If

Note the very subtle difference. This had me confused for about 10 minutes (way too long) and is why C# (and other) dudes needs to be very careful when coding in other languages.

Jason Plank
  • 2,336
  • 5
  • 31
  • 40
1

I would go with the try/except, but it depends on what you know about the variable.

If you are expecting that the variable will exist most of the time, then a try/except is less operations. If you are expecting the variable to be None most of the time, then an IF statement will be less operations.

Jason Coon
  • 17,601
  • 10
  • 42
  • 50
0

It's perfectly safe and I do it all the time.

FogleBird
  • 74,300
  • 25
  • 125
  • 131