0

I'm curious why replacing == with is causes a .py to fail when launched directly.

if __name__ == '__main__':
    main()

vs

if __name__ is '__main__':
    main()

How is object identity working here?

I'm specifically curious about the mechanics, purpose for __name__ and __main__ having different identities.

enrico.bacis
  • 30,497
  • 10
  • 86
  • 115

2 Answers2

4

is means that the two things are the same object (i.e. they have the same id). Apparently the __name__ is a different string than '__main__' (even though they have the same text).

In general, only use is if you really mean "Check that these are the exact same object" -- never use it to mean "These objects are equal".

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • 1
    One way to get a string that isn't 'exactly the same' is to split a list. e.g. `'one __main__ two'.split()[1] is '__main__'` returns `False`. `is` is not a good test for strings in `sys.argv`. – hpaulj Aug 16 '14 at 01:55
1

A few examples will make it more obvious:

In [7]: foo = 1000

In [8]: bar = 1000

In [9]: foo is bar # same value but different objects so identity test is False
Out[9]: False

In [10]: foo == bar # equality test is True
Out[10]: True

In [11]: id(foo) # both have different id's
Out[11]: 41007616

In [12]: id(bar)
Out[12]: 40841432

In [13]: foo = bar # now make foo point to the object bar

In [14]: foo is bar # now foo is bar so identity check is True
Out[14]: True

In [15]: id(bar) # matching id's
Out[15]: 40841432

In [16]: id(foo)
Out[16]: 40841432

To compare values use == to check identity use is

Something to be aware of is e small integers -5 to 256 and strings are cached and reused in python so if you assign a = 10 and b = 10,they actually both point to the same object so a is b .

In [20]: a = 256    
In [21]: b = 256
In [22]: a is b
Out[22]: True
In [23]: a = 257
In [24]: b = 257    
In [25]: a is b
Out[25]: False
In [26]: foo = "foo"
In [27]: bar = "foo"   
In [28]: foo is bar
Out[28]: True
In [29]: foo = "$bar"
In [30]: bar = "$bar"
In [31]: foo is bar # now False because it does not start with an _ or a letter
Out[31]: False

strings are only cached if they start with an underscore or a letter and contain only letters, numbers or underscores:

A final example of why is __main__ fails:

# first  __main__  object inside locals dict, second is just a string __main__
print id(locals()['__name__']),id("__main__")  
print (locals()['__name__']) is "__main__" # so not the same object 
print (locals()['__name__'])  == "__main__" # but == strings

if __name__ == "__main__":
    print id(locals()['__name__']), id(__name__ ) # same id's 
    print (locals()['__name__']) is __name__ ) # same object stored in locals

140168071262544 140168071262592
False
True
140168071262544 140168071262544
True
Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
  • 1
    But, to confuse things, try `foo = 100` and `bar = 100`. With cPython, `foo is bar` => `True` because Python does an optimization of caching and reusing small integer objects. Just another reason to be really careful about using `is`. – Ned Deily Aug 16 '14 at 00:41
  • @NedDeily, I knew someone would say that I was going to add it but I thought it would just confuse things more, `bar = "foo"` and `foo = "foo"` would also confuse things. – Padraic Cunningham Aug 16 '14 at 00:50