teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

3

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

2018/05/01 04:14

投稿

YouheiSakurai
YouheiSakurai

スコア6151

answer CHANGED
@@ -23,7 +23,7 @@
23
23
 
24
24
  # 追記:ビジーループでwatcherを書いてみた
25
25
 
26
- `locals()`を監視しても`locals()`を呼ばないと辞書の内容が更新されないということがわかったので、最終的にフレームを監視することにしました。でも、ビジーループで監視しているので、CPU使用率が上がってしまう悪い例です。その点は留意ください。
26
+ `locals()`が返す辞書を監視しても`locals()`を呼ばないと辞書の内容が更新されないということがわかったので、最終的にフレームを監視することにしました。でも、ビジーループで監視しているので、CPU使用率が上がってしまう悪い例です。その点は留意ください。
27
27
 
28
28
  ```python
29
29
  from copy import deepcopy

2

書いてみた

2018/05/01 04:14

投稿

YouheiSakurai
YouheiSakurai

スコア6151

answer CHANGED
@@ -19,4 +19,65 @@
19
19
  return inner
20
20
 
21
21
  locals().__setitem__ = hook(locals().__setitem__)
22
+ ```
23
+
24
+ # 追記:ビジーループでwatcherを書いてみた
25
+
26
+ `locals()`を監視しても`locals()`を呼ばないと辞書の内容が更新されないということがわかったので、最終的にフレームを監視することにしました。でも、ビジーループで監視しているので、CPU使用率が上がってしまう悪い例です。その点は留意ください。
27
+
28
+ ```python
29
+ from copy import deepcopy
30
+ from inspect import currentframe
31
+ from threading import Event
32
+ from threading import Thread
33
+ from threading import Lock
34
+
35
+
36
+ class LocalsWatcher(Thread):
37
+ def __init__(self, frame):
38
+ super().__init__()
39
+ self.frame = frame
40
+ self.targets = {}
41
+ self.lock = Lock()
42
+ self.stopping = Event()
43
+
44
+ def add(self, name, callback):
45
+ with self.lock:
46
+ self.targets[name] = (
47
+ deepcopy(self.frame.f_locals.get(name)), callback)
48
+
49
+ def remove(self, name):
50
+ with self.lock:
51
+ self.targets.pop(name, None)
52
+
53
+ def stop(self):
54
+ self.stopping.set()
55
+
56
+ def run(self):
57
+ while not self.stopping.is_set():
58
+ with self.lock:
59
+ for name in self.targets:
60
+ original, callback = self.targets[name]
61
+ current = self.frame.f_locals.get(name)
62
+ if current != original:
63
+ callback(name, original, current)
64
+ self.targets[name] = (deepcopy(current), callback)
65
+
66
+ def __enter__(self):
67
+ self.start()
68
+ return self
69
+
70
+ def __exit__(self, *_):
71
+ self.stop()
72
+
73
+
74
+ def main():
75
+ with LocalsWatcher(currentframe()) as watcher:
76
+ watcher.add("i", print)
77
+ for i in range(10):
78
+ pass
79
+
80
+
81
+ if __name__ == "__main__":
82
+ main()
22
83
  ```

1

return追加

2018/05/01 04:07

投稿

YouheiSakurai
YouheiSakurai

スコア6151

answer CHANGED
@@ -15,7 +15,7 @@
15
15
  def hook(fn):
16
16
  def inner(*args, **kwargs):
17
17
  print(*args, *kwargs.items())
18
- fn(*args, **kwargs)
18
+ return fn(*args, **kwargs)
19
19
  return inner
20
20
 
21
21
  locals().__setitem__ = hook(locals().__setitem__)