vks
vks

Reputation: 67968

"is" operator not working as intended

Just have a look at this code:

import re

ti = "abcd"
tq = "abcdef"
check_abcd = re.compile('^abcd')
print id(check_abcd.search(ti))
print id(check_abcd.search(tq))
print check_abcd.search(ti)
print check_abcd.search(tq)
if check_abcd.search(ti) is check_abcd.search(tq):
    print "Matching"
else:
    print "not matching"

Output:

41696976
41696976
<_sre.SRE_Match object at 0x00000000027C3ED0>
<_sre.SRE_Match object at 0x00000000027C3ED0>
not matching

Definition of is:

`is` is identity testing, == is equality testing. 
 is will return True if two variables point to the same object

1)Now why is the is not returning True when id as well as object reference is same.

2)When is is replaced by == it is still returning false.Is that the expected behaviour when comparing objects using ==.

Upvotes: 2

Views: 145

Answers (3)

Martijn Pieters
Martijn Pieters

Reputation: 1121476

You never assigned the return values, so after printing the id() value of the return value of check_abcd.search() calls, Python discards the return value object as there is nothing referencing it anymore. CPython object lifetimes are directly governed by the number of references to them; as soon as that reference count drops to 0 the object is removed from memory.

Discarded memory locations can be re-used, so you'll like to see the same values crop up in id() calls. See the id() documentation:

Return the “identity” of an object. This is an integer (or long integer) which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

At no point in your code did you actually have one object, you have two separate objects with non-overlapping lifetimes.

Assign return values if you want to make sure id() values are not reused:

>>> import re
>>> ti = "abcd"
>>> tq = "abcdef"
>>> check_abcd = re.compile('^abcd')
>>> ti_search = check_abcd.search(ti)
>>> tq_search = check_abcd.search(tq)
>>> id(ti_search), id(tq_search)
(4378421952, 4378422056)
>>> ti_search, tq_search
(<_sre.SRE_Match object at 0x104f96ac0>, <_sre.SRE_Match object at 0x104f96b28>)
>>> ti_search is tq_search
False

By assigning the return values of check_abcd.search() (the regular expression MatchObjects) an additional reference is created and Python cannot reuse the memory location.

Upvotes: 6

Larry Lustig
Larry Lustig

Reputation: 50970

Martjin has given you the correct answer, but for further clarification here is an annotated version of what's happening in your code:

# this line creates returns a value from .search(), 
# prints the id, then DISCARDS the value as you have not 
# created a reference using a variable.
print id(check_abcd.search(ti)) 

# this line creates a new, distinct returned value from .search()
# COINCIDENTALLY reusing the memory address and id of the last one.
print id(check_abcd.search(tq))

# Same, a NEW value having (by coincidence) the same id
print check_abcd.search(ti)

# Same again
print check_abcd.search(tq)

# Here, Python is creating two distinct return values.  
# The first object cannot be released and the id reused
# because both values must be held until the conditional statement has 
# been completely evaluated.  Therefore, while the FIRST value will
# probably reuse the same id, the second one will have a different id.
if check_abcd.search(ti) is check_abcd.search(tq):
    print "Matching"
else:
    print "not matching"

Upvotes: 2

jsbueno
jsbueno

Reputation: 110208

WHen you do: print id(check_abcd.search(ti)) in a line and don't store the return value of search anywhere, its reference count goes to zero and it is destroyed. The call in the line bellow that creates another object, which happens to be in the same memory address (which is used by CPython as an object ID) - but it is not the same object.

When you use the is operator, the previous object still has to exist in order for the comparison to occur, and its address will be different.

Just put the results of the calls to check_abcd.search in a variable before printing their ID (and use different variables) and you will be able to see what is actually going on.

Moreover: continuing in these lines can be instructive if you want to learn about the behavior of "is" and object IDs - but if you want to compare strings, and return values, just use the == operator, never is: subsequent function calls, even if returning the same value are not supposed to return the same object - the is comparison is only recommended when comparing with "None" (which is implemented as a singleton)

Upvotes: 2

Related Questions