Last active
May 18, 2018 05:01
-
-
Save domodomodomo/3ec95155e270e9641770f7c5fde5a749 to your computer and use it in GitHub Desktop.
Show object's identity recursively.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""Show object's identity recursively. | |
sample code 1 ... difference between copy and deepcopy | |
sample code 2 ... reason why [[0]*3]*3 is not good for 2d list initialization | |
""" | |
def ids(identifier: object) -> dict: | |
"""Return the “identity” of an object, recursively.""" | |
# Effective Python item 26 | |
# http://bit.ly/2HgJAyr | |
# list | |
if isinstance(identifier, list): | |
iterator = enumerate(identifier) | |
# dict | |
elif isinstance(identifier, dict): | |
iterator = identifier.items() | |
# object mutable | |
elif hasattr(identifier, '__dict__'): | |
iterator = identifier.__dict__.items() | |
# object immutable | |
else: | |
return id(identifier) | |
return id(identifier),\ | |
{attribute: ids(value) for attribute, value in iterator} | |
def sample_code1(Computer, Cpu, Memory, Ssd): | |
"""Show a difference between copy and deepcopy. | |
To understand the difference, | |
check how identities contained in variables and attributes change. | |
copy.copy | |
creates only one instance | |
contained in variable. | |
copy.deepcopy | |
creates all intances | |
contained in variable and attributes except immutable objects') | |
""" | |
import copy | |
import pprint | |
pc = Computer( | |
Cpu('2.3GHz', 5), | |
Memory('8GB', '2133MHz', 'DDR4'), | |
Ssd('256GB')) | |
print('# pc') | |
pprint.pprint(ids(pc)) | |
print('# copy.copy(pc)') | |
pprint.pprint(ids(copy.copy(pc))) | |
print('# copy.deepcopy(pc)') | |
pprint.pprint(ids(copy.deepcopy(pc))) | |
def sample_class1(): | |
"""Define sample classes.""" | |
class Computer(object): | |
def __init__(self, cpu, | |
primary_memory, auxiliary_memory): | |
self.cpu = cpu | |
self.primary_memory = primary_memory | |
self.auxiliary_memory = auxiliary_memory | |
class Cpu(object): | |
def __init__(self, clock, core): | |
self.clock = clock | |
self.core = core | |
class Memory(object): | |
def __init__(self, volume, clock, type_): | |
self.volume = volume | |
self.clock = clock | |
self.type_ = type_ | |
class Ssd(object): | |
def __init__(self, volume): | |
self.volume = volume | |
return (Computer, Cpu, Memory, Ssd, ) | |
def sample_code2(Obj): | |
"""Show you why [[Obj()]*3]*3 is not good for 2d list initialization. | |
Bad: | |
list2d = [[Obj() * 3]] * 3 | |
Good: | |
list2d = [[Obj() for i in range(3)] for j in range(3)] | |
""" | |
import pprint | |
arr1 = [[0] * 3] * 3 | |
arr2 = [[0 for i in range(3)] for j in range(3)] | |
# arr1 and arr2 are same at a grance. | |
assert arr1 == [ | |
[0, 0, 0], | |
[0, 0, 0], | |
[0, 0, 0] | |
] | |
assert arr2 == [ | |
[0, 0, 0], | |
[0, 0, 0], | |
[0, 0, 0] | |
] | |
# but the operation results are not same. | |
arr1[2][2] = 1 | |
arr2[2][2] = 1 | |
assert arr1 == [ | |
[0, 0, 1], | |
[0, 0, 1], | |
[0, 0, 1] | |
] | |
assert arr2 == [ | |
[0, 0, 0], | |
[0, 0, 0], | |
[0, 0, 1] | |
] | |
# Why did this happen? | |
# 3 elements contained in arr1 are same, only 1 list. | |
# 3 elements contained in arr2 are not same, 3 lists. | |
assert (arr1[0] is arr1[1] is arr1[2]) is True | |
assert (arr2[0] is arr2[1] is arr2[2]) is False | |
# Point | |
# if you use multiplication operand, | |
# Python just push a reference to the object. | |
# if you use list complehenstion, | |
# Python instantiate a object. | |
arr3 = [[Obj(0)] * 3] * 3 | |
arr4 = [[Obj(0) for i in range(3)] for j in range(3)] | |
print('# arr3 and arr4\'s representations are same.') | |
print('## arr3: ', arr3) | |
print('## arr4: ', arr4) | |
print('# but, arr3 and arr4\'s composition are different.') | |
print('## arr3 uses same identities:') | |
pprint.pprint(ids(arr3)) | |
print('## arr4 uses different identities:') | |
pprint.pprint(ids(arr4)) | |
def sample_class2(): | |
class Obj(object): | |
def __init__(self, n): | |
self.n = n | |
def __eq__(self, other): | |
return self.n == other.n | |
def __repr__(self): | |
return 'Obj(%d)' % self.n | |
return (Obj, ) | |
if __name__ == '__main__': | |
sample_code1(*sample_class1()) | |
sample_code2(*sample_class2()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment