回答編集履歴

3

`locals()`が返す辞書と変更

2018/05/01 04:14

投稿

YouheiSakurai
YouheiSakurai

スコア6142

test CHANGED
@@ -48,7 +48,7 @@
48
48
 
49
49
 
50
50
 
51
- `locals()`を監視しても`locals()`を呼ばないと辞書の内容が更新されないということがわかったので、最終的にフレームを監視することにしました。でも、ビジーループで監視しているので、CPU使用率が上がってしまう悪い例です。その点は留意ください。
51
+ `locals()`が返す辞書を監視しても`locals()`を呼ばないと辞書の内容が更新されないということがわかったので、最終的にフレームを監視することにしました。でも、ビジーループで監視しているので、CPU使用率が上がってしまう悪い例です。その点は留意ください。
52
52
 
53
53
 
54
54
 

2

書いてみた

2018/05/01 04:14

投稿

YouheiSakurai
YouheiSakurai

スコア6142

test CHANGED
@@ -41,3 +41,125 @@
41
41
  locals().__setitem__ = hook(locals().__setitem__)
42
42
 
43
43
  ```
44
+
45
+
46
+
47
+ # 追記:ビジーループでwatcherを書いてみた
48
+
49
+
50
+
51
+ `locals()`を監視しても`locals()`を呼ばないと辞書の内容が更新されないということがわかったので、最終的にフレームを監視することにしました。でも、ビジーループで監視しているので、CPU使用率が上がってしまう悪い例です。その点は留意ください。
52
+
53
+
54
+
55
+ ```python
56
+
57
+ from copy import deepcopy
58
+
59
+ from inspect import currentframe
60
+
61
+ from threading import Event
62
+
63
+ from threading import Thread
64
+
65
+ from threading import Lock
66
+
67
+
68
+
69
+
70
+
71
+ class LocalsWatcher(Thread):
72
+
73
+ def __init__(self, frame):
74
+
75
+ super().__init__()
76
+
77
+ self.frame = frame
78
+
79
+ self.targets = {}
80
+
81
+ self.lock = Lock()
82
+
83
+ self.stopping = Event()
84
+
85
+
86
+
87
+ def add(self, name, callback):
88
+
89
+ with self.lock:
90
+
91
+ self.targets[name] = (
92
+
93
+ deepcopy(self.frame.f_locals.get(name)), callback)
94
+
95
+
96
+
97
+ def remove(self, name):
98
+
99
+ with self.lock:
100
+
101
+ self.targets.pop(name, None)
102
+
103
+
104
+
105
+ def stop(self):
106
+
107
+ self.stopping.set()
108
+
109
+
110
+
111
+ def run(self):
112
+
113
+ while not self.stopping.is_set():
114
+
115
+ with self.lock:
116
+
117
+ for name in self.targets:
118
+
119
+ original, callback = self.targets[name]
120
+
121
+ current = self.frame.f_locals.get(name)
122
+
123
+ if current != original:
124
+
125
+ callback(name, original, current)
126
+
127
+ self.targets[name] = (deepcopy(current), callback)
128
+
129
+
130
+
131
+ def __enter__(self):
132
+
133
+ self.start()
134
+
135
+ return self
136
+
137
+
138
+
139
+ def __exit__(self, *_):
140
+
141
+ self.stop()
142
+
143
+
144
+
145
+
146
+
147
+ def main():
148
+
149
+ with LocalsWatcher(currentframe()) as watcher:
150
+
151
+ watcher.add("i", print)
152
+
153
+ for i in range(10):
154
+
155
+ pass
156
+
157
+
158
+
159
+
160
+
161
+ if __name__ == "__main__":
162
+
163
+ main()
164
+
165
+ ```

1

return追加

2018/05/01 04:07

投稿

YouheiSakurai
YouheiSakurai

スコア6142

test CHANGED
@@ -32,7 +32,7 @@
32
32
 
33
33
  print(*args, *kwargs.items())
34
34
 
35
- fn(*args, **kwargs)
35
+ return fn(*args, **kwargs)
36
36
 
37
37
  return inner
38
38