Last active
April 14, 2018 05:03
-
-
Save tell-k/c7552ef551f06620e2f029f1495fe173 to your computer and use it in GitHub Desktop.
ブロック内のコードをスキップできる + スコープを共有しない with statetment
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 1. ブロック内のコードを実行しない with ------- | |
# refs http://stackoverflow.com/questions/12594148/skipping-execution-of-with-block | |
import sys | |
import inspect | |
class SkipContext: | |
def __enter__(self): | |
# 1. SkipContextの外側のframeを取得 | |
self.frame, _, _, _, _, _ = inspect.getouterframes(inspect.currentframe())[1] | |
self.frame.f_trace = self.trace | |
sys.settrace(lambda *args, **keys: None) # 2. settraceを有効にする | |
def trace(self, frame, event, arg): | |
raise Exception('Skip with block') # 4. 3の行が実行される前にフックされて raiseされる | |
def __exit__(self, exec_type, exec_value, traceback): | |
# 5. 3の行は実行されずに、__exit__ にたどり着いて強制的にwithが終了 | |
sys.settrace(None) | |
return True | |
with SkipContext(): | |
print('Not execute this line.') # 3. この行が実行されようとする | |
# 2. スコープを共有しない with ------------ | |
import inspect | |
import copy | |
class IsolatedScopeContext: | |
def __enter__(self): | |
self.frame, _, _, _, _, _ = inspect.getouterframes(inspect.currentframe())[1] | |
self.orig_globals = copy.copy(self.frame.f_globals) # 1. with に入る前の globalsを保存 | |
def __exit__(self, exec_type, exec_value, traceback): | |
# 2. with を抜ける時に1で保存した globalsを復活 | |
for k in list(self.frame.f_globals.keys()): | |
self.frame.f_globals.pop(k, None) | |
for k, v in self.orig_globals.items(): | |
self.frame.f_globals[k] = v | |
return True | |
spam = 'spam' | |
with IsolatedScopeContext(): # withの抜けたあとに、この時点でのglobalsを復元する | |
spam = 'egg' | |
with IsolatedScopeContext(): | |
print(spam) # => 'spam' | |
# 3 1 と 2を mix したやつ ------------------ | |
import inspect | |
import sys | |
import copy | |
class SkipException(Exception): | |
pass | |
class SkippableContext: | |
def __init__(self, skip=False, isolated_scope=False): | |
self.skip = skip | |
self.isolated_scope = isolated_scope | |
def __enter__(self): | |
self.frame, _, _, _, _, _ = inspect.getouterframes(inspect.currentframe())[1] | |
if self.skip: | |
self.frame.f_trace = self.trace | |
sys.settrace(lambda *args, **keys: None) | |
if self.isolated_scope: | |
self.orig_globals = copy.copy(self.frame.f_globals) | |
def trace(self, frame, event, arg): | |
raise SkipException('Skip this context.') | |
def restore_globals(self): | |
for k in list(self.frame.f_globals.keys()): | |
self.frame.f_globals.pop(k, None) | |
for k, v in self.orig_globals.items(): | |
self.frame.f_globals[k] = v | |
def __exit__(self, exec_type, exec_value, traceback): | |
sys.settrace(None) | |
if self.isolated_scope: | |
self.restore_globals() | |
if exec_type is SkipException: | |
return True | |
with SkippableContext(): | |
print('Execute this line.') | |
with SkippableContext(skip=True): | |
print('Not Execute this line.') | |
var1 = 'var1' | |
with SkippableContext(isolated_scope=True): | |
var1 = 'update1' | |
print(var1) | |
with SkippableContext(isolated_scope=True): | |
print(var1) | |
var1 = 'update2' | |
print(var1) # => 'var1' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment