2016-08-15 8 views
0

초보자 여기 자바 배경에서 오는 파이썬 코더. 나는 여전히이 당황 해요 :"with", 컨텍스트 관리자, python : 간단한 용어로 무엇이 진행되고 있습니까?

with open(...) as f: 
    do_something(f) 

심지어 인터넷 검색 여기에 몇 가지 답변을 읽은 후 (난 그냥 그들 주위에 내 머리를 가져올 수 없습니다).

제 생각에는 작성된 파일에 대한 참조를 포함하는 일종의 래퍼 인 컨텍스트 관리자라는 것이 있습니다. 위의

import numpy as np 

아래 '와 같은'처럼 '으로'

as f: 

에 대해서는하면 그냥 별칭입니다. 'f'는 파일을 나타내지 않고 컨텍스트 관리자를 가리 킵니다. 컨텍스트 관리자는 데코레이터 패턴을 사용하여 열려있는 파일의 모든 메서드를 구현하므로 파일 객체처럼 취급 할 수 있습니다 (파일에 대해 호출되는 적절한 메서드를 호출하여 파일 객체를 가져올 수 있음). 컨텍스트 관리자 내부). 물론 블록이 완료되면 파일이 닫힙니다 (이 점의 전체 내용).

이것은 open()이 일반적으로 파일 (또는 파일에 대한 참조) 또는 컨텍스트 관리자를 반환합니까? 일반적으로 컨텍스트 관리자를 반환합니까, 그리고 그것은 우리가 모르는 사이에 항상 사용하고있는 것입니까? 또는 컨텍스트 관리자와 다른 뭔가를 반환 할 때이 특수한 상황을 제외하고는 파일 형식을 반환합니다.

오른쪽 근처에 있습니까? 누구든지 명확하게하고 싶습니까?

+1

파일 관리자는 * 컨텍스트 관리자입니다. – user2357112

+0

열린 후'with'는 쓰기 후에 파일을 안전하게 닫습니다. – n1c9

+1

https://www.python.org/dev/peps/pep-0343/을 읽으셨습니까? –

답변

3

파일 객체 __enter____exit__ 메쏘드가 있다는 점에서 콘텍스트 관리자입니다. with__enter____exit__을 각각 호출하여 컨텍스트가 입력 및 종료 될 때 file 개체에 알리고, 파일 개체가 파일을 닫는 방법을 "알 수있는"방법입니다. 여기에 관련된 래퍼 객체는 없습니다. 파일 객체는 두 가지 방법을 제공합니다 (자바에서는 파일 객체가 컨텍스트 관리자 인터페이스를 구현한다고 말할 수 있습니다).

asimport module as altname과 같이 별칭이 이 아니고이 아닙니다. 대신 반환 값contextmanager.__enter__() 인 대상에 할당됩니다.fileobject.__enter__() 방법은 self을 반환 (그래서 파일 객체 자체), 쉽게 구문을 사용할 수 있도록 :이 작업을 수행하지 않았다

with open(...) as fileobj: 

fileobject.__enter__()하지만 중 하나는 None 반환 또는 다른 개체가, 당신은 open()를 인라인 없습니다 요구; 아무것도 중지 없다는 것을

fileobj = open(...) 
with fileobj as something_enter_returned: 
    fileobj.write() 

또는

fileobj = open(...) 
with fileobj: # no as, ignore whatever fileobj.__enter__() produced 
    fileobj.write() 

참고 : 반환 된 파일 개체에 대한 참조를 유지하기 위해 먼저 컨텍스트 매니저로 사용하기 전에 변수에 open()의 결과를 할당해야 할 것 당신은 자신의 코드에서 후자의 패턴을 사용하지 않는다. 이미 파일 객체에 대한 다른 참조가있는 경우 을 입력하면 여기 as target 부분을 사용하거나 파일 객체에 더 액세스 할 필요가 없습니다.

그러나 다른 컨텍스트 관리자는 다른 것을 반환 할 수 있습니다.

conn = database.connect(....) 
with conn as cursor: 
    cursor.execute(...) 

하고 상황을 종료하면 커밋되거나 롤백 할 트랜잭션 발생 (거세한 숫양에 따라 여부 예외가 있었다) : 일부 데이터베이스 커넥터는 데이터베이스 커서를 반환합니다.

0

컨텍스트 관리자는 매우 간단한 동물입니다 ... 그들은 단지 two separate methods (__enter____exit__)을 정의하는 클래스입니다. __enter__에서 반환되는 것은 with 문이 실행될 때 with 문의 as x 절에 바인딩됩니다.

여기 정말 바보 같은 예입니다 :

>>> class CM(object): 
... def __enter__(self): 
...  print('In __enter__') 
...  return 'Hello world' 
... def __exit__(self, *args): 
...  print('In __exit__') 
... 
>>> with CM() as x: 
... print(x) 
... 
In __enter__ 
Hello world 
In __exit__ 

자주 단순히 __enter__ 방법에서 self을 반환 컨텍스트 관리자를 볼 수 있습니다,하지만 난 당신이 필요가 없다는 것을 입증하기 위해 위의 예제를 썼다. 또한이 with 문 문맥 관리자를 구성 할 필요가 없습니다, 당신은 시간의 전방을 구성 할 수 있습니다 :

cm = CM() 
with cm as x: 
    ... 

컨텍스트 관리자에 대한 이유는 그 with 문, 파이썬과 함께 사용하는 경우 with 제품군 내부에서 예외가 발생하더라도 __exit__이 호출됨을 보장합니다. .

file 개체는 컨텍스트 관리자 API (그들이 잘 __enter____exit__ 방법을 정의) 컨텍스트 관리자입니다 그래서 file 객체를 사용하여 구현됩니다. with 문과 함께 사용하면 python은 with 슈트가 종료 될 때 파일이 닫히도록 보장합니다.

예를 들어. 컴퓨터가 망가질 경우 ...

+0

따라서 __enter__ 및 __exit__ 메소드를 구현하는 모든 클래스는 컨텍스트 관리자입니다. 상속이나 인터페이스 구현에 대해 생각하고 있기 때문에 혼란 스럽지만 File에 대해서는 아무 것도 볼 수 없습니다. –

+0

@Detroitteatime - 나는 내가 이해하고 있는지 확신하지 못합니다. python2.5 -> python2.7'help (file)'를 입력하면'__enter__'과'__exit__'가 거기에 나열됩니다. 아마도 'open'은 파일 객체를 반환하는 팩토리 메서드입니까? – mgilson

+0

@Detroitteatime : 어쨌든 컨텍스트 관리자를 인터페이스로 생각할 수 있습니다. 파일 객체는 해당 인터페이스를 구현합니다. –

1

이것은 당신이 만들 수있는 가장 기본적인 문맥 관리자입니다 :

class UselessContextManager(object): 
    def __enter__(self): 
     pass 

    def __exit__(self, type, value, traceback): 
     pass 

with UselessContextManager() as nothing: 
    print(nothing is None) 

당신이 실제로 프로세스 흐름이 어떻게 생겼는지에 대한 약간의 느낌을 얻고 싶다면, 노력이 하나

class PrintingContextManager(object):           
    def __init__(self, *args, **kwargs):          
     print('Initializing with args: {} and kwargs: {}'.format(args, kwargs)) 

    def __enter__(self):              
     print('I am entering the context')          
     print('I am returning 42')            
     return 42                

    def __exit__(self, type, value, traceback):         
     print('And now I am exiting')           


print('Creating manager')              
manager = PrintingContextManager()            
print('Entering with block')             
with manager as fnord:               
    print('Fnord is {}'.format(fnord))           
    print('End of context')              
print('Out of context')               

출력 :

Creating manager 
Initializing with args:() and kwargs: {} 
Entering with block 
I am entering the context 
I am returning 42 
Fnord is 42 
End of context 
And now I am exiting 
Out of context 

코드를 다음과 같이 수정해야합니다. type, value, traceback을 인쇄 한 다음 with 블록에서 예외를 발생시킵니다.

>>> f = open('/tmp/spanish_inquisition.txt', 'w') 
>>> f.__enter__ 
<function TextIOWrapper.__enter__> 
>>> f.__exit__ 
<function TextIOWrapper.__exit__> 
: 당신은 파일을 항상 상황에 맞는 관리자 것을 볼 수 있습니다

thing = ContextManager() 
try: 
    stuff = thing.__enter__() 
except Exception as e: 
    stuff.__exit__(type(e), e.args[0], e.__traceback__) 

Though truthfully it's a bit different

:

당신이 볼 수 있듯이, with 구문에 대한 거의 단지 짧은

파일이 ContextManager 일 수 있다는 것을 몰랐습니다. 수퍼 클래스를 상속하거나 명시 적으로 인터페이스를 구현하지 않고 두 가지 메소드를 구현하면됩니다. 다시 말하지만, 저는이 언어를 처음 접했습니다.

파이썬에서는 이 인터페이스를 명시 적으로 구현하는입니다. Java에서는 준수 할 인터페이스를 지정해야합니다. 파이썬에서는 단지 그렇게합니다. 파일과 같은 객체가 필요합니까? .read() 메서드를 추가하십시오. 어쩌면 .seek(), .open().close() 일 것입니다. 하지만 파이썬에서 ...

it = DecoyDuck() 
if it.walks_like_a_duck() and it.talks_like_a_duck() and it.quacks_like_a_duck(): 
    print('It must be a duck')