forked from mCodingLLC/VideosSampleCode
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsuper_implementation.py
162 lines (122 loc) · 3.91 KB
/
super_implementation.py
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import inspect
class Super:
"""
A crazy implementation of the builtin super from within Python.
Probably full of bugs, for instructional purposes only.
"""
def __init__(self, cls=None, obj_or_cls=None, /):
if cls is None and obj_or_cls is None:
frame = inspect.currentframe()
caller_locals = frame.f_back.f_locals
assert frame.f_back.f_code.co_argcount > 0
obj_or_cls = next(iter(caller_locals.values()))
try:
cls = caller_locals['__class__'] # depends on caller user __class__
except KeyError:
raise RuntimeError(
"For zero-argument Super, you need to put __class__ in the same function "
"that Super is used to make compiler magic work, the real super "
"doesn't have this restriction")
assert inspect.isclass(cls), "cls must be a class"
self.__thisclass__ = cls
self._bind_self(cls, obj_or_cls)
def _bind_self(self, cls, obj_or_cls, /):
if obj_or_cls is None:
self.__self__ = None
self.__self_class__ = None
elif inspect.isclass(obj_or_cls):
assert issubclass(obj_or_cls, cls), "obj_or_cls is a class but not a subclass of cls"
self.__self__ = obj_or_cls
self.__self_class__ = obj_or_cls
else:
assert isinstance(obj_or_cls, cls), "obj_or_cls is an object but not an instance of cls"
self.__self__ = obj_or_cls
self.__self_class__ = type(obj_or_cls)
def __get__(self, instance, owner=None):
if self.__self__ is not None:
return self
if instance is not None:
obj_or_cls = instance
else:
assert owner is not None, "cannot bind to None"
obj_or_cls = owner
self._bind_self(self.__self_class__, obj_or_cls)
return self
def __getattr__(self, item):
if item == "__class__":
return self.__class__
if self.__self__ is None:
raise AttributeError(item)
mro = self.__self_class__.__mro__
n = len(mro)
i = mro.index(self.__thisclass__) + 1
while i < n:
cls = mro[i]
try:
res = cls.__dict__[item]
except KeyError:
pass
else:
try:
get = type(res).__get__ # get(self, instance, owner)
except AttributeError:
return res
else:
return get(res,
None if self.__self__ == self.__self_class__ else self.__self__,
self.__self_class__)
i += 1
raise AttributeError(item)
class A:
def f(self):
return ["A"]
class B(A):
def f(self):
__class__ # adds __class__ to locals
return ["B"] + Super().f()
class B_super(A):
def f(self):
return ["B"] + super().f()
class C(B):
def f(self):
__class__
return ["C"] + Super().f()
class C_super(B):
def f(self):
return ["C"] + super().f()
class E(A):
def f(self):
__class__
return ["E"] + Super().f()
class E_super(A):
def f(self):
return ["E"] + super().f()
class F(C, E):
def f(self):
__class__
return ["F"] + Super().f()
class F_super(C, E):
def f(self):
return ["F"] + super().f()
class G(F):
pass
class H(G):
def f(self):
__class__
return ["H"] + Super().f()
class H_super(G):
def f(self):
return ["H"] + super().f()
def main():
print(B().f())
print(B_super().f())
print(C().f())
print(C_super().f())
print(E().f())
print(E_super().f())
print(F().f())
print(F_super().f())
print(H().f())
print(H_super().f())
if __name__ == '__main__':
main()