2.4. OOP Interning
2.4.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.4.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.4.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.4.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.4.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.4.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.4.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.4.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.4.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.4.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)