Python 2.4에 대한 "With"진술에 대한 드롭 인 교체 개선
-
20-09-2019 - |
문제
Python 2.4에서 작동 할 "With"문에 대한 드롭 인 교체를 코딩하는 방법을 제안 할 수 있습니까?
그것은 해킹 일지 모르지만, 프로젝트를 Python 2.4에 더 멋지게 포트 할 수 있습니다.
편집하다:관련없는 중첩 스케치를 제거했습니다
해결책
시도 만 사용하십시오.
실제로, 이것은 정신 운동으로 좋을지 모르지만 실제로 코드로 수행하면 코드를 유지하기가 어렵습니다.
다른 팁
당신은 (AB) 데코레이터를 사용하여이를 수행 할 수 있다고 생각합니다. 다음 작품, 예를 들어 :
def execute_with_context_manager(man):
def decorator(f):
target = man.__enter__()
exc = True
try:
try:
f(target)
except:
exc = False
if not man.__exit__(*sys.exc_info()):
raise
finally:
if exc:
man.__exit__(None, None, None)
return None
return decorator
@execute_with_context_manager(open("/etc/motd"))
def inside(motd_file):
for line in motd_file:
print line,
(Python 2.4 파일 객체에는 __enter__ 및 __exit__ 방법이 없지만 그렇지 않으면 작동합니다)
아이디어는 다음과 함께 라인을 대체하는 것입니다.
with bar() as foo:
do_something_with(foo)
do_something_else_with(foo)
# etc...
장식 된 기능 "선언"을 사용하여 :
@execute_with_context_manager( bar() )
def dummyname( foo ):
do_something_with(foo)
do_something_else_with(foo)
# etc...
그러나 동일한 동작을 얻습니다 (do_something _... 코드 실행). 참고 데코레이터는 함수 선언을 an으로 변경합니다 즉시 호출 조금 악한 것 이상입니다.
오류가 아닌 오류 중에 컨텍스트 관리자를 종료해야하므로 메타 클래스가있는 일반적인 유행성을 수행 할 수는 없다고 생각합니다. 당신은 그것을 위해 시도/마침내 블록이 필요할 것입니다.
그러나 아마도 당신의 경우 다른 일을 할 수 있습니다. 그것은 당신이 컨텍스트 관리자를 사용하는 것에 따라 다릅니다.
사용 __del__
거래 리소스와 같은 경우에도 도움이 될 수 있지만, 호출 할 수 없으므로 프로그램이 종료 될 때 릴리스 될 리소스를 해제해야합니다. 예외를 처리하는 경우에도 작동하지 않습니다. __exit__
방법.
가장 깨끗한 방법은 전체 컨텍스트 관리를 일종의 컨텍스트 관리로 래핑하고 코드 블록을 메소드로 추출하는 것입니다. 이와 같은 것 (테스트되지 않은 코드이지만 대부분 PEP 343에서 도난당했습니다) :
def call_as_context_manager(mgr, function):
exit = mgr.__exit__
value = mgr.__enter__()
exc = True
try:
try:
function(value)
except:
exc = False
if not exit(*sys.exc_info()):
raise
finally:
if exc:
exit(None, None, None)
이건 어때?
def improvize_context_manager(*args, **kwargs):
assert (len(args) + len(kwargs)) == 1
if args:
context_manager = args[0]
as_ = None
else: # It's in kwargs
(as_, context_manager) = kwargs.items()[0]
def decorator(f):
exit_ = context_manager.__exit__ # Not calling it yet
enter_ = context_manager.__enter__()
exc = True
try:
try:
if as_:
f(*{as_: enter_})
else:
f()
except:
exc = False
if not exit_(*sys.exc_info()):
raise
finally:
if exc:
exit_(None, None, None)
return None
return decorator
용법:
@improvize_context_manager(lock)
def null():
do(stuff)
어느 것과 유사합니다 with
없는 키워드 as
.
또는:
@improvize_context_manager(my_lock=lock)
def null(my_lock):
do(stuff_with, my_lock)
어느 것과 유사합니다 with
키워드 as
.
블록을 얻기 위해 DEF를 사용하고 즉시 실행하는 데코레이터를 사용하는 경우 기능 서명을 사용하여 명명 된 케이스에 대해 더 자연스러운 것을 얻을 수 있습니다.
import sys def with(func): def decorated(body = func): contexts = body.func_defaults try: exc = None, None, None try: for context in contexts: context.__enter__() body() except: exc = sys.exc_info() raise finally: for context in reversed(contexts): context.__exit__(*exc) decorated() class Context(object): def __enter__(self): print "Enter %s" % self def __exit__(self, *args): print "Exit %s(%s)" % (self, args) x = Context() @with def _(it = x): print "Body %s" % it @with def _(it = x): print "Body before %s" % it raise "Nothing" print "Body after %s" % it