2.5. OOP Interning — Python
2.5.1. Caching
>>> a = 256 >>> >>> a == 256 True >>> >>> a is 256 SyntaxWarning: "is" with a literal. Did you mean "=="? True
>>> b = 257 >>> >>> b == 257 True >>> >>> b is 257 SyntaxWarning: "is" with a literal. Did you mean "=="? False
2.5.2. Integer Caching
Values between -5 and 256 are cached from start
After using any integer two times it is being cached
Python caches also the next integer
Cached numbers are invalidated after a while
>>> x = 256 >>> id(x) 4474506792 >>> >>> del x >>> >>> x = 256 >>> id(x) 4474506792
>>> x = 257 >>> id(x) 4509456400 >>> >>> del x >>> >>> x = 257 >>> id(x) 4509455696
>>> id(256) 4514832592 >>> >>> id(256) 4514832592 >>> >>> id(256) 4514832592 >>> >>> id(256) 4514832592
>>> id(257) 4561903248 >>> >>> id(257) 4561904272 >>> >>> id(257) 4561903344 >>> >>> id(257) 4561903344
>>> id(-5) 4423729200 >>> >>> id(-5) 4423729200
>>> id(-6) 4463320144 >>> >>> id(-6) 4463321840
Mind, that address for objects less or equal to 256 is the same, but above 256 object address is different:
>>> a = 256 >>> b = 257 >>> >>> id(a) 4565299048 >>> id(b) 4602009488 >>> >>> del a >>> del b >>> >>> a = 256 >>> b = 257 >>> >>> id(a) 4565299048 >>> id(b) 4602005616
Mind, that address for objects less or equal to 256 is the same, but above 256 object address is different:
>>> a = 256 >>> b = 256 >>> x = 257 >>> y = 257 >>> >>> id(a) 4565299048 >>> >>> id(b) 4565299048 >>> >>> id(x) 4602004784 >>> >>> id(y) 4602012112
2.5.3. Float Caching
It takes a bit more hits for float to start being cached
Cached numbers are invalidated after a while
>>> id(1.0) 4491972048 >>> >>> id(1.0) 4492804656 >>> >>> id(1.0) 4491972048 >>> >>> id(1.0) 4492804656 >>> >>> id(1.0) 4492811728 >>> >>> id(1.0) 4492817392 >>> >>> id(1.0) 4492811792 >>> >>> id(1.0) 4492817392 >>> >>> id(1.0) 4492817616
2.5.4. Bool Type Identity
Bool object is a singleton
It always has the same identity (during one run)
>>> id(True) 4469679168 >>> >>> id(True) 4469679168
>>> id(False) 4469679896 >>> >>> id(False) 4469679896
2.5.5. None Type Identity
NoneType object is a singleton
It always has the same identity (during one run)
>>> id(None) 4469761584 >>> >>> id(None) 4469761584
2.5.6. String Type Identity
>>> a = 'Mark Watney' >>> b = 'Mark Watney' >>> >>> a == b True >>> a is b False
>>> 'Mark Watney' is 'Mark Watney' <...>:1: SyntaxWarning: "is" with a literal. Did you mean "=="? True
2.5.7. String Interning
Caching mechanism
String intern pool
String is immutable
Each time an instance of a string is created Python will create a new object with completely new identity:
>>> id('Watney') 4354445296 >>> >>> id('Watney') 4354447728
However if we create an identifier, then each time a string is created it will result with the same interned string. Value of an identifier will add to the string interning pool, from which Python returns a new objects:
>>> name = 'Watney' >>> >>> id('Watney') 4354447984 >>> >>> id('Watney') 4354447984
However if we delete entry from string interning pool, Python will now create a new instance of a string each time:
>>> del name >>> >>> id('Watney') 4354449136 >>> >>> id('Watney') 4354449328
Example:
>>> a = 'Mark' >>> b = 'Mark' >>> c = format('Mark') >>> d = str('Mark') >>> e = str('Mark'+'') >>> f = str.__new__(str, 'Mark') >>> g = a + '' >>> >>> id(a) 4498017136 >>> id(b) 4498017136 >>> id(c) 4498017136 >>> id(d) 4498017136 >>> id(e) 4498017136 >>> id(f) 4498017136 >>> id(g) 4498017136
Intuitively, we can think of the string interning pool as a cache of strings:
>>> string_interning_pool = { ... 'hello': '0x106f37e40', ... 'world': '0x106db8120', ... }
2.5.8. Object Identity
>>> class User: ... def __init__(self, firstname, lastname): ... self.firstname = firstname ... self.lastname = lastname >>> >>> >>> a = User('Mark', 'Watney') >>> b = User('Mark', 'Watney') >>> >>> a is b False >>> >>> id(a) 4421890496 >>> id(b) 4421893328 >>> >>> hex(id(a)) '0x10790b1c0' >>> hex(id(b)) '0x10790bcd0' >>> >>> print(a) <User object at 0x107905820> >>> print(b) <User object at 0x10790bcd0>
2.5.9. Class Identity
Class object is a singleton
It always has the same identity (during one run)
>>> class User: ... pass >>> >>> class Admin: ... pass >>> >>> >>> User is User True >>> >>> Admin is Admin True >>> >>> User is Admin False >>> >>> id(User) 140570740200304 >>> >>> id(Admin) 140570185653984
2.5.10. Performance
Cached int:
>>> %%timeit -r 1000 -n 1000 ... x = 1 15.5 ns ± 5.22 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each) >>> >>> >>> %%timeit -r 1000 -n 1000 ... x = int(1) 69.4 ns ± 22.2 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
Uncached int:
>>> %%timeit -r 1000 -n 1000 ... x = 257 16 ns ± 8.24 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each) >>> >>> >>> %%timeit -r 1000 -n 1000 ... x = int(257) 64.7 ns ± 19.6 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
str:
>>> %%timeit -r 1000 -n 1000 ... x = 'Mark' 17.8 ns ± 6.41 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each) >>> >>> >>> %%timeit -r 1000 -n 1000 ... x = str('Mark') 33.3 ns ± 6.99 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)