1

Consider below code

a,b="hello","hello" 
print id(a),id(b)

output

28954752 28954752

output will be same for char,string etc but now consider a list

list1=[1,2,3,4]
list2=[1,2,3,4]
print id(list1),id(list2)

output

139706054367136 139706054368360

we can see address is given is different in case of list/tuple/dict, if they are reference variables so why string gives same address for same values?

piyush singh
  • 395
  • 8
  • 24
  • 3
    Which behavior surprised you? The fact that the ints had equal IDs, or the fact that the lists did not? – user2357112 Aug 12 '16 at 04:32
  • that question focus only for string i asked about list/tuple. – piyush singh Aug 12 '16 at 04:36
  • @julienbernu I'm not satisfied with that answer. – piyush singh Aug 12 '16 at 05:00
  • @piyushsingh I don't think the compiler worries about that, it's still using the same rules so that's still the same answer. Essentially in your first case the values are compile-time constants so the compiler can intern the values, while your second example involves enough complexity that the compiler isn't sure it can safely intern the list. For an explanation of interning, see https://en.wikipedia.org/wiki/String_interning (which also applies to interning of other types). – Todd Knarr Aug 12 '16 at 05:11
  • Where did you get the idea that the IDs will be the same for floats? See what happens if you put them on different lines (assign one value at a time). – John Y Aug 12 '16 at 05:12
  • @johny I made en edit. – piyush singh Aug 12 '16 at 05:15
  • 3
    If you're planning on _doing_ anything based on object IDs or the memory addresses of your data, you probably shouldn't. Different Python interpreters (CPython vs. PyPy vs. ActivePython vs. ...) will handle internal details like this differently... and I suspect even the same "brand" of Python could behave differently on different architectures. – Kevin J. Chase Aug 12 '16 at 05:33
  • 1
    @KevinJ.Chase: The reference interpreter is theoretically capable of disabling several of the caches based on compile options, so even on the same architecture, a custom build could behave differently. – ShadowRanger Aug 12 '16 at 05:36

2 Answers2

2

Sometimes (and by design it's an implementation detail) Python caches certain values for reuse.

In particular it can only safely cache immutable types like strings and integers. Since list1 and list2 are mutable, it would be problematic for them to refer to the same object internally as mutations of one would then be reflected in the other.

Suppose Python had some sort of list-caching, such that list1 and list2 end up referencing the same object:

> print(id(list1) == id(list2))
True
> list1[0] = 5
> print(list2)
[5, 2, 3, 4]

It's a good thing that's not how it works - it'd be a huge hassle to work with!

Community
  • 1
  • 1
dimo414
  • 47,227
  • 18
  • 148
  • 244
  • your first line will give False – piyush singh Aug 12 '16 at 05:40
  • @piyushsingh: Yes, that is the point. The code was made up (notice the prompts are not real Python prompts). You have to read the surrounding text in conjunction with the code. – John Y Aug 12 '16 at 05:48
  • @piyushsingh right; *if* it were true, there'd be problems. Thus the difference between how lists and strings are handled. – dimo414 Aug 12 '16 at 05:59
1
list1=[1,2,3,4]
list2=[1,2,3,4]

creates 2 objects that happen to hold same values. The objects being different they have different ids. (in this case you can modify either of them independently.)

list1=list2=[1,2,3,4]

creates 2 references to the same object. The objects being the same they have identical ids. (In this case you cannot modify list1 without changing list2.)

For strings it is a bit more subtle: python creates only one object "hello" even if you you do

a = "hello"
b = "hello"

BTW you may as well call id("hello") directly and find the same result.

Julien
  • 13,986
  • 5
  • 29
  • 53
  • string1="string" string2="string" now in this case objects are different but ids are same ? – piyush singh Aug 12 '16 at 05:04
  • 2
    @piyushsingh The compiler is interning the strings. Since they're the same value and never changed, it's safe for it to create one object and make all references to that string value refer to that single object. – Todd Knarr Aug 12 '16 at 05:08
  • strings are not mutable (unlike lists), same behavior as with `int`'s. Not quite sure why the behavior is different with tuples (which are not mutable) though... – Julien Aug 12 '16 at 05:09
  • @toddknarr Why compiler not do the same for list ? – piyush singh Aug 12 '16 at 05:10
  • @julienbernu but What about tuple ? – piyush singh Aug 12 '16 at 05:10
  • 3
    You made your answer worse with your edit. Try checking larger `int` values. – John Y Aug 12 '16 at 05:11
  • @JohnY hmm. Good point! Reverted to strings (which is also matches the edit in the question now). However, can you shed some light on the different behavior for long ints and tuples? – Julien Aug 12 '16 at 05:18
  • 2
    @piyushsingh Complexity. It can only intern values if it can be absolutely sure they're never modified. Figuring that out can involve a lot of computation, and Python's interpreted so that hit's going to be when the program is run. Usually the interpreter writers avoid that huge computation hit by limiting interning to only certain data types and forms of declarations (so eg. declaring a string initialized to a literal constant may be eligible for interning while one initialized by another string variable may not be). – Todd Knarr Aug 12 '16 at 05:23
  • @toddknarr I'm agree with your point, but in a single line what is the answer for my question ? – piyush singh Aug 12 '16 at 05:25
  • 1
    It's not just `long`, but plain `int` as well. The rules governing Python's interning behavior are extremely complex and not easily predicted. What you can be sure of is that two mutable objects can never have the same address. Two immutable objects may or may not have the same address. There are very few hard and fast rules regarding those. `None` is a special case, guaranteed to be singleton. Off the top of my head, I can't think of any others. – John Y Aug 12 '16 at 05:28
  • 1
    @piyushsingh: String literals and small ints have special caches (as does the empty `tuple`) that mean a single instance is shared. Other objects don't, either due to mutability, or the complexity isn't worth the benefits. Sometimes they do maintain a free list (`tuple` does this, so when a small `tuple` is released and another `tuple` of the same size subsequently allocated, it doesn't actually perform allocation), but it's largely implementation details, and you should not generally rely on identity tests for anything that's not a documented singleton (e.g. `None`). – ShadowRanger Aug 12 '16 at 05:31
  • @piyushsingh In a single line: interning of values. – Todd Knarr Aug 12 '16 at 05:33
  • @JohnY: `True` and `False` are also guaranteed singletons, as is `Ellipsis` (though you rarely use the latter, and the former is usually produced implicitly; you'd almost never want to test against `True` or `False`, identity or equality testing). – ShadowRanger Aug 12 '16 at 05:33
  • @ShadowRanger: Guaranteed in Python 3. The situation is slightly murky in Python 2 because those can all be reassigned. ;) But all of that is academic; as you say, there aren't many situations where you would be testing against those three values. – John Y Aug 12 '16 at 05:41
  • @JohnY: The objects are still singletons even when the names are shadowed/reassigned. You can stomp the name, but there is still only one `True` and one `False` in the whole interpreter, and you can't make different instances of the `bool` type. – ShadowRanger Aug 12 '16 at 12:15
  • @ShadowRanger: The objects are still singletons, but that's not what matters in the context of the question, which is testing using `is` or `id()`. If you can stomp the name, then there **isn't** only one `True`, in the sense that `id(True)` could return different values if it is called multiple times in the same program or the same interactive session. That is what I meant by murky. In contrast, you can't have this behavior in Python 3, nor with `id(None)` in any Python. – John Y Aug 12 '16 at 15:25