문제

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

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top