3

I want to compare a variable I set to None, which was a string element before, with is but it fails.

When I compare this variable to None with ==, it works.

This is the variable I'm talking about:

print type(xml.a) -> <type 'lxml.objectify.StringElement'>

Because some libraries I use have None as a default argument (i.e., def f(x=None)), I converted my nullstrings earlier like this:

if xml.a == '':
    xml.a = None

Afterwards the type has changed to:

print type(xml.a) -> <type 'lxml.objectify.NoneElement'>

Which is not the same as:

print type(None) -> <type 'NoneType'>

When I compare this value as I described above I get the following result:

if xml.a is None:
    print 'what I expect'
else:
    print 'what I do NOT expect'  # sadly this one is printed

if xml.a == None:
    print 'what I do NOT expect'  # this one is printed again...
else:
    print 'what I expect'

I already know that when comparing objects that are not the same instance, is returns false. But my understanding is that I had set xml.a earlier to the None instance. On the other hand they don't match in their types and is returns false so it can't be the same instance as None.

  • Why?
  • Do I have no other choice than to use ==?

For those who want to know more about the difference between is and isinstance there has been a discussion about it here.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
WaltheRed
  • 47
  • 10

1 Answers1

9

You are using the lxml.objectify API; this API uses a special object to represent None values in the objectified XML tree. When you assigned None to xml.a, lxml stored that special object, so that it can transform that to a XML element in an XML document.

What you have is not the None singleton. You have an instance of the lxml.objectify.NoneElement class instead.

You can test for that element's type instead:

from lxml.objectify import NoneElement

if isinstance(xml.a, NoneElement):
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Martijn: So the `lxml.objectify` API rebinds the name `None` to something else -- because when I try something like that in the Python shell I get a `SyntaxError: cannot assign to None`? – martineau Sep 18 '14 at 18:40
  • 1
    @martineau: no, assigning to an attribute on a `lxml.objectify` tree sets a specific `objectify` type object based on the value you just assigned. So assigning `None` to such an attribute is handled in a `__setattr__` call and stored as `lxml.objectify.NoneElement`. `None` itself is not rebound anywhere. – Martijn Pieters Sep 18 '14 at 18:47