Python) with open(…) as f 에서 f의 정체는?

Photo by Dương Hữu on Unsplash

파이썬에서

with open(...) as f 

를 많이 볼 수 잇다.

근데, with를 사용하지 않고

f = open(...) 

이렇게 해서 open함수를 사용해주는경우도 있다(이 경우 f.close()반드시 해줘야함).

그런데, 두 경우에서 ‘f’ 는 마치 같은 녀석처럼 쓰인다.

만약 그렇다면, f는 open함수의 리턴값이니까, with A as B 에서 A는 B 와 같은 녀석인가??

결론부터 말하면, 일반적인 경우, 그렇지 않다.

open함수의 경우가 특별한 것이다.

with A as B:

라고 하면,

A는 ‘context manager’ 가 되는 객체이고,

B는 [A.__enter__메서드의 리턴값] 이다.

‘context manager’가 되기 위해서는, __enter__메서드와 __exit__메서드를 가지고 있어야 한다.

(참고로, with 구문이 시작될때 바로 이 __enter__메서드가 호출되며, with 구문을 빠져나가면서 __exit__메서드가 자동으로 호출되는 것이다. with 구문에서 open함수를 사용할때 굳이 파일오브젝트를 close()해주지 않아도 되는 원리가 여기에 있다.)

자주 쓰이는

with open(...) as f:

에서 open(…)함수가 리턴하는 객체는 ‘file object’ 인데, 이 객체는 __enter__와 __exit__ 메서드를 가지고있도록 만들어져있기 때문에 ‘context manager’로서 역할하게 된다.

그런데, 이 객체(open함수가 리턴하는 file object)의 __enter__메서드는 리턴값이 self다. 즉, file object 자신을 리턴하게 되어있다.

따라서, with open(…) as f 에서 f는 open(…)함수가 리턴한 file object가 되는것이다.

그렇기 때문에,

f = open(…)try:    print(f.read())finally:    f.close()

위와같이 with 를 쓰지 않고 open함수 사용시 f=open(…)이라고 해줄때의 f와, 위에서의 with open(…) as f 에서의 f결과적으로는 같은녀석이 되는것이다(둘 다 open함수가 리턴하는 file object가 된다).

하지만, 직접 context manager 클래스를 만들어 줄 경우, __enter__메서드의 리턴값을 self로 하지 않을수도 있기 때문에, with A as B에서 A와 B는 같지 않다.

많이 쓰이는 with open(…) as f 구문 때문에 괜히 헷갈리지 말자!