1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
"""
A pure Python implementation of statesaver.c that runs on top of PyPy.
See description in statesaver.c.
Difference: this supports new-style instances too.
Use statesaver.standard_build() as the inst_build() if you want.
"""
from _pickle_support import generator_new
import types
def standard_build(self):
if type(self) is types.InstanceType:
# old-style instance
return types.InstanceType(self.__class__)
else:
# new-style instance
return type(self).__new__(type(self))
# ____________________________________________________________
def not_copied(x, memo):
return x
def copy_custom_instance(x, memo):
try:
return memo[id(x)]
except KeyError:
y = x.inst_build()
memo[id(x)] = y
for key, value in list(x.__dict__.items()):
y.__dict__[key] = copyrec(value, memo)
return y
def copy_tuple(x, memo):
return tuple([copyrec(item, memo) for item in x])
def copy_list(x, memo):
try:
return memo[id(x)]
except KeyError:
y = []
memo[id(x)] = y
for item in x:
y.append(copyrec(item, memo))
return y
def copy_dict(x, memo):
try:
return memo[id(x)]
except KeyError:
y = {}
memo[id(x)] = y
for key, value in list(x.items()):
y[copyrec(key, memo)] = copyrec(value, memo)
return y
def copy_function(x, memo):
if not x.__defaults__:
return x # not copied
try:
return memo[id(x)]
except KeyError:
y = types.FunctionType(x.__code__, x.__globals__, x.__name__)
memo[id(x)] = y
y.__defaults__ = copyrec(x.__defaults__, memo)
return y
def copy_method(x, memo):
return types.MethodType(copyrec(x.__func__, memo),
copyrec(x.__self__, memo),
x.__self__.__class__)
def copy_generator(x, memo):
try:
return memo[id(x)]
except KeyError:
y = generator_new(copyrec(x.gi_frame, memo), x.gi_running)
memo[id(x)] = y
return y
def copy_frame(x, memo):
try:
return memo[id(x)]
except KeyError:
frame_new, args, state = x.__reduce__()
y = frame_new(*args)
memo[id(x)] = y
newstate = []
for item in state:
if not (item is x.f_globals or item is x.f_builtins):
item = copyrec(item, memo)
newstate.append(item)
y.__setstate__(newstate)
return y
def copy_seqiter(x, memo):
try:
return memo[id(x)]
except KeyError:
# XXX self-recursion is not correctly handled here
seqiter_new, args = x.__reduce__()
args = [copyrec(item, memo) for item in args]
y = seqiter_new(*args)
memo[id(x)] = y
return y
# ____________________________________________________________
type_handlers = {tuple: copy_tuple,
list: copy_list,
dict: copy_dict,
types.FunctionType: copy_function,
types.MethodType: copy_method,
types.GeneratorType: copy_generator,
types.FrameType: copy_frame,
type(iter([])): copy_seqiter,
}
def no_handler_found(x, memo):
if hasattr(x, '__dict__') and hasattr(x.__class__, 'inst_build'):
handler = copy_custom_instance
else:
handler = not_copied
type_handlers[x.__class__] = handler
return handler(x, memo)
def copyrec(x, memo):
try:
cls = x.__class__
except AttributeError:
return x # 'cls' is likely an old-style class object
return type_handlers.get(cls, no_handler_found)(x, memo)
def copy(x):
return copyrec(x, {})
|