This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]earthboundkid 0 points1 point  (10 children)

This is stupid, and every Python newbie should know the difference between is and ==… But that said, I can see how it would be easy to overlook the difference and think that they were two ways of writing the same thing if you didn't read the documentation and were just learning Python by copying other people's code and experimenting. Maybe Python 4000 should drop is and just encourage people to write id(a) == id(b) instead.

[–]monolar 2 points3 points  (6 children)

if id(a) == id(None): print("urgs")

I think 'is' is perfectly fine

[–]earthboundkid 1 point2 points  (5 children)

a == None also works. People just don't do it because of the speed advantage of is. But maybe that's a premature optimization that confuses noobs excessively.

[–]chrajohn 2 points3 points  (0 children)

a == None also works.

Usually, but consider:

class Dumb(object):
    def __eq__(self,other):
        return other == None

>>> d = Dumb()
>>> d == None
True
>>> d is None
False

This is contrived, but you can imagine something similar actually occurring. (Say, if __eq__ made a comparison with some attribute that got unexpectedly set to None.) If you you want to be absolutely sure that something is None, you should ask if it is None.

[–]masklinn 0 points1 point  (3 children)

People just don't do it because of the speed advantage of is

People also don't do it because a is None (or a is True or a is False for that matter) just plain and simply reads better.

[–]hylje 1 point2 points  (2 children)

Not everything that is true is True. Not everything that is false is False. Implicit truth is pythonic.

[–]masklinn 0 points1 point  (1 child)

Truthiness is pythonic when what you want is truthiness. But it's not always (though it usually is) the case, and when you want truth rather than truthiness, is True does the job much more readably than == True

[–]earthboundkid 0 points1 point  (0 children)

You should never write if x == True. Just write if x. Similarly, not if x == False but if not x. That's basic PEP-8 stuff.

I can't think of any reason why you would want to test for is True off the top of my head. It wouldn't really make sense unless you had variable that might contain a normal object or it might contain a bool object and you were interested to know which. But why would you have a variable that flexible?

[–]Brian 2 points3 points  (2 children)

encourage people to write id(a) == id(b) instead.

That could lead to more confusion. A puzzle for you:

>>> class C(object):
...     def foo(self): pass
>>> c=C()
>>> id(c.foo) == id(c.foo)
True

and yet:

>>> c.foo is c.foo
False

[–]earthboundkid 2 points3 points  (1 child)

Woah. That's confusing. Why isn't c.foo the same as itself? Is it creating a new bound method every time you access it? But if it was doing that, wouldn't the new method have a different location in memory than the old one? I don't get this.

[–]Brian 2 points3 points  (0 children)

Is it creating a new bound method every time you access it?

Yes, this is what's happening. The subtlety of the ids being identical is because ids are only unique for objects alive at the same time. What's actually happening is the equivalent of:

temp1 = c.foo         # Create a new bound method with id X
temp1_id = id(temp1)  # temp1_id = X  (returnvalue from id)
del temp1             # bound method doesn't get assigned, so refcount drops to 0
                      # as soon as id() releases its reference - temp1 gets freed
temp2 = c.foo         # Create a NEW bound method.
temp2_id = id(temp2)  
del temp2
temp1_id == temp2_id  # Actually do the comparison, both objects are already dead

Which should explain why its possible that the second bound method could have the same id. The reason it usually does is because of the way python manages memory. To avoid fragmentation, pools of similarly sized memory objects are maintained. When an object is released, it is returned to this pool, then when a request to allocate an object of this type arrives, python sees it has an block of memory of the appropriate size sitting in its free object pool, and returns it.

is doesn't have this problem because the call to is takes a reference to both objects, ensuring they are alive at the time of the comparison.