5
votes

As any Python programmer knows, you should use == instead of is to compare two strings for equality. However, are there actually any cases where ( s is "" ) and ( s == "" ) will give different results in Python 2.6.2?

I recently came across code that used ( s is "" ) in code review, and while pointing out that this was incorrect I wanted to give an example of how this could fail. But try as I might, I can't construct two empty strings with different identities. It seems that the Python implementation must special-case the empty string in lots of common operations. For example:

>>> a = ""
>>> b = "abc"[ 2:2 ]
>>> c = ''.join( [] )
>>> d = re.match( '()', 'abc' ).group( 1 )
>>> e = a + b + c + d 
>>> a is b is c is d is e
True

However, this question suggests that there are cases where ( s is "" ) and ( s == "" ) can be different. Can anyone give me an example?

7

7 Answers

12
votes

Python is tests the objects identity and not equality. Here is an example where using is and == gives a different result:

>>> s=u""
>>> print s is ""
False
>>> print s==""
True
11
votes

As everyone else has said, don't rely on undefined behaviour. However, since you asked for a specific counterexample for Python 2.6, here it is:

>>> s = u"\xff".encode('ascii', 'ignore')
>>> s
''
>>> id(s)
10667744
>>> id("")
10666064
>>> s == ""
True
>>> s is ""
False
>>> type(s) is type("")
True

The only time that Python 2.6 can end up with an empty string which is not the normal empty string is when it does a string operation and it isn't sure about in advance how long the string will be. So when you encode a string the error handler can end up stripping characters and fixes up the buffer size after it has completed. Of course that's an oversight and could easily change in Python 2.7.

7
votes

You shouldn't care. Unlike None which is defined to be a singleton, there is no rule that says there is only one empty string object. So the result of s is "" is implementation-dependent and using is is a NO-NO whether you can find an example or not.

3
votes

It seems to work for anything which actually is a string, but something which just looks like a string (e.g. a unicode or subclass of str or something similar) will fail.

>>> class mysub(str):
    def __init__(self, *args, **kwargs):
        super(mysub, self).__init__(*args, **kwargs)

>>> 
>>> q = mysub("")
>>> q is ""
False
>>> q == ""
True

edit:

For the purposes of code review & feedback I would suggest that it was bad practice because it implements an unexpected test (even if we ignore the uncertainty of whether it will always behave the same when the types match).

if x is ""

Implies that x is of the correct value and type, but without an explicit test of type which would warn future maintainers or api users, etc.

if x == ""

Implies that x is just of the correct value

1
votes

You can't find a example because some things are unique and not muteable - so Python keeps them around exactly once and therefore is works. These include (), '',u'', True, False, None CPython even keeps a few frequently used numbers, ie 0, 0.0, 1, 1.0,

0
votes

Probably no, CPython seems to optimize spurious instances of "" away in all cases. But as the others say, don't rely on that.

0
votes

Undefined behavior is a murky issue. There are things the Python specification defines and adhering implementations must conform to, and there are things left to choice. You may get convinced, by looking into the source code of Python, that this behavior can never happen for actual string objects (unlike unicode vs. non-unicode and other close-but-irrelevant examples shown). Happy, you will leave such a test in a code.

But the Python implementation doesn't guarantee it will always work. Some future implementation may cause it to change and you'll have a painful incompatibility.

So the rule of thumb with this is simple: don't do it. Use operators only for their intended and well documented use. Don't rely on artifacts of implementation that may very well change in the future.