Skip to content

Instantly share code, notes, and snippets.

@domodomodomo
Last active May 18, 2018 05:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save domodomodomo/3ec95155e270e9641770f7c5fde5a749 to your computer and use it in GitHub Desktop.
Save domodomodomo/3ec95155e270e9641770f7c5fde5a749 to your computer and use it in GitHub Desktop.
Show object's identity recursively.
"""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