Is There Any Difference Between "Foo Is None" and "Foo == None"

Is there any difference between foo is None and foo == None?

is always returns True if it compares the same object instance

Whereas == is ultimately determined by the __eq__() method

i.e.


>>> class Foo(object):
def __eq__(self, other):
return True

>>> f = Foo()
>>> f == None
True
>>> f is None
False

What is the difference between is None and == None

The answer is explained here.

To quote:

A class is free to implement
comparison any way it chooses, and it
can choose to make comparison against
None mean something (which actually
makes sense; if someone told you to
implement the None object from
scratch, how else would you get it to
compare True against itself?).

Practically-speaking, there is not much difference since custom comparison operators are rare. But you should use is None as a general rule.

Is there a difference between == and is?

is will return True if two variables point to the same object (in memory), == if the objects referred to by the variables are equal.

>>> a = [1, 2, 3]
>>> b = a
>>> b is a
True
>>> b == a
True

# Make a new copy of list `a` via the slice operator,
# and assign it to variable `b`
>>> b = a[:]
>>> b is a
False
>>> b == a
True

In your case, the second test only works because Python caches small integer objects, which is an implementation detail. For larger integers, this does not work:

>>> 1000 is 10**3
False
>>> 1000 == 10**3
True

The same holds true for string literals:

>>> "a" is "a"
True
>>> "aa" is "a" * 2
True
>>> x = "a"
>>> "aa" is x * 2
False
>>> "aa" is intern(x*2)
True

Please see this question as well.

difference between 'is' and '=='

The first checks for identity the second for equality.

Examples:

The first operation using is may or may not result in True based on where these items, i.e., strings, are stored in memory.

a='this is a very long string'
b='this is a very long string'

a is b
False

Checking, id() shows them stored at different locations.

id(a)
62751232

id(b)
62664432

The second operation (==) will give True since the strings are equal.

a == b
True

Another example showing that is can be True or False (compare with the first example), but == works the way we'd expect:

'3' is '3'
True

this implies that both of these short literals were stored in the same memory location unlike the two longer strings in the example above.

'3' == '3'
True

No surprise here, what we would have expected.

I believe is uses id() to determine if the same objects in memory are referred to (see @SvenMarnach comment below for more details)

if (foo or bar or baz) is None:

The short-circuiting behavior causes foo or bar or baz to return the first of the three values that is boolean-true, or the last value if all are boolean-false. So it basically means "if all are false and the last one is None".

Your changed version is slightly different. if None in (opts.foo, opts.bar, opts.baz) will, for instance, enter the if block if opts.foo is None and the other two are 1, whereas the original version will not (because None or 1 or 1 will evaluate to 1, which is not None). Your version will enter the if when any of the three is None, regardless of what the other two are, whereas the original version will enter the if only if the last is None and the other two are any boolean-false values.

Which of the two versions you want depends on how the rest of the code is structured and what values the options might take (in particular, whether they might have boolean-false values other than None, such as False or 0 or an empty string). Intuitively your version does seem more reasonable, but if the code has peculiar tricks like this in it, you never know what corner cases might emerge.

False or None vs. None or False

The expression x or y evaluates to x if x is true, or y if x is false.

Note that "true" and "false" in the above sentence are talking about "truthiness", not the fixed values True and False. Something that is "true" makes an if statement succeed; something that's "false" makes it fail. "false" values include False, None, 0 and [] (an empty list).

Foo.objects.get(id=None) returns Foo instance, sometimes

This behaviour is caused by deeply strange (in this coder's humble opinion) MySQL behaviour, controlled by the SQL_AUTO_IS_NULL variable (which is 1 by default in MySQL < 5.5.3):

If this variable is set to 1, then after a statement that successfully inserts an automatically generated AUTO_INCREMENT value, you can find that value by issuing a statement of the following form:

SELECT * FROM tbl_name WHERE auto_col IS NULL

If the statement returns a row, the value returned is the same as if you invoked the LAST_INSERT_ID() function

There is a Django bug (closed: wontfix) describing similar confusion caused by this "feature", in which a core developer states

If you don't want that behaviour, you should configure your database to do the right thing for your preferences

The solution, then, is to disable the SQL_AUTO_IS_NULL option of your MySQL database using the SET statement. You can do this in settings.py with something like:

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
# ... your DB options
'OPTIONS': {
'init_command': 'SET SQL_AUTO_IS_NULL=0;'
},
}
}

Longer-term, you can try and drum-beat on the django-developers list to get them to reconsider their earlier position:

Fortunately, my thinking here isn't burning any bridges. If somebody
wanted to test that out, or use it by default, they can use the database
initialisation options via DATABASE_OPTIONS in settings ... Both
"read_default_file" and "init_command" are useful there.

I'm not saying this should be "no, forever", but right now I'm not
convinced it's worth doing this. Balanced against that is how to let
people know that it might happen... shrug.. I might add something to
databases.txt, for a start. I hate this sort of balancing act. :-(



Related Topics



Leave a reply



Submit