0

Can someone help me understand why the second comparison between z and c variables resolve as False?

t = [1, 2, 3]
h = t
print(id(h), " ", id(t))
print(h is t)

x = ('bla', t)
y = ('bla', t)

z, c = str(x[1]), str(y[1])

print(id(z), " ", id(c))
print(z is c)

My initial impression is that x[1] and y[1] would be pointing to the same reference since we're directly assigning that index of the tuples to the t variable. Does this mean Python is passing in the value of t rather than the object of the variable? Why does h is t evaluate to True but z is c evaluate to false? *** scratches head ***

EJP
  • 23
  • 4
  • 2
    You're not assigning the index of the tuple. You are taking `t`, which is a list, and converting it to a string. Trivial strings are cached, longer strings are not. – Tim Roberts Feb 07 '22 at 04:55
  • In this case if no string type casting is done z is c returns true. Since the strings are identical in value between z and c (ie. ==), are your suggesting the only reason they do not point to the same reference (z is c evaluate to False) is because of caching? And if this is the case does this caching behavior also apply to other primitive types? – EJP Feb 07 '22 at 04:58
  • 1
    No, _lack_ of caching, in this example. Strings are cached when they are literals, and satisfy [some other constraints](https://stackoverflow.com/questions/42684966/are-strings-cached), at least in CPython: `a = '0'; b = '0'; a is b`. However, the default `str` does not cache, it will blindly convert its argument into a new string: `a = str(0); b = str(0); c = '0'; a is not b; a is not c`. – Amadan Feb 07 '22 at 05:07
  • excellent answers thank you – EJP Feb 07 '22 at 05:49

2 Answers2

1

This has nothing to do with tuples themselves, but with str being applied to basically anything that is not already a string (unless a class redefines its __str__ method to cache results):

x = 0

x is x
# True

str(x) is str(x)
# => False

This is because str(x) converts its argument into a new string each time.

Consequently, z and c in your example are different strings that happen to have the same content ('[1, 2, 3]').

Amadan
  • 191,408
  • 23
  • 240
  • 301
  • But strings are immutable... doesn't this mean if their value is identical they should point to the same reference in memory and therefore be the same object? – EJP Feb 07 '22 at 05:05
  • 2
    @EJP: No. Nothing about immutability would imply that. – user2357112 Feb 07 '22 at 05:06
  • 1
    Think about what that would require. It would require the interpreter to search through every string in memory to see if it matched the current one. That isn't sensible. It can do that for literal strings, because it has the time, but not for strings generated at run-time. – Tim Roberts Feb 07 '22 at 05:12
  • @Amadan: Interning strings doesn't make them immortal in Python. Quoting the [docs](https://docs.python.org/3/library/sys.html#sys.intern): "Interned strings are not immortal; you must keep a reference to the return value of intern() around to benefit from it." – user2357112 Feb 07 '22 at 05:15
  • @user2357112supportsMonica Ah, TIL. Thank you. – Amadan Feb 07 '22 at 05:16
0

Immutability of a string is a necessary but not sufficient condition for having identical strings share the same object. There is some overhead in looking up a string to see if it already exists, so most of the time Python doesn't bother. It does provide a facility for interned strings so you can do it yourself if you want.

>>> import sys
>>> str(0) is str(0)
False
>>> sys.intern(str(0)) is sys.intern(str(0))
True
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622