본문 바로가기

Python

Python - File Handling & With Statement

안녕하세요 이번에는 파이썬에서 파일을 어떻게 다루는지에 대해서 알아보려고 합니다. 그럼 시작하겠습니다 :)

File


우선 File에 대해 기본적으로 이야기해보면 위키피디아에서는 File을 컴퓨터에서 정보를 저장하는 논리적 단위라고 정의하고 있다. 개인적으로 다른 언어들에 비해서 파이썬에서 File Handling하는 것이 특히 쉽고 짧다고 생각한다. 이러한 파일은 text file과 binary file로 나뉜다.

Text File은 character들의 연속으로 저장된 파일로 user가 이해할 수 있는 형태의 파일이라고 보면 될 것 같다. 우리가 작성하는 파이썬 소스코드 파일같은 .py의 확장자를 가진 파일 또한 text file일 것이다.
Binary File은 0 or 1의 데이터의 연속으로 저장된 파일로 컴퓨터가 이해할 수 있는 형태의 파일이다. 일반적으로 우리에게는 text file이더라도, 컴퓨터는 text file을 이해하기 위해서 binary file로 바꿔서 저장하게 된다. 앞서 다뤘던 pyc같은 확장자를 가진 파일이 binary file이 되겠다. 혹은 특정 application에 종속적인 엑셀파일이나 Word파일 같은 것이 되겠다.

이 둘을 구분하는 가장 쉬운 방법은 Text Editor를 통해서 열어보는 것이다. 그리고 우리에게 가장 쉽고 익숙한 텍스트 에디터는 "메모장"이다!! 메모장으로 열어보면 해당 파일이 text file인지 binary file인지 한 번에 확인할 수 있다. 전자라면 내용이 그대로 확인가능하고, 후자라면 내용이 깨져보이게 된다.

Binary File in Text Editor

File I/O


우리는 이러한 파일을 파이썬을 통해 읽고, 쓰고, 수정하고 등을 하고 싶다. 그러기 위해서는 먼저 파이썬에서 파일 처리를 해야한다. 파이썬에서 read 나 write같은 operation을 하기에 앞서, File을 처리하기 위해 가져와야하고 처리를 다 했다면 닫아줘야 한다. 이러한 개념을 Python에서는 File I/O를 위한 built-in function인 open()과 file 객체의 메소드 close()를 통해 처리하고 있다. 

file = open("hosik.txt", 'r')
file.close()

이렇게 close()를 통해서 종료시켜줘야, 데이터가 날라가게 되는 등의 위험이 적어지고, 특정 프로그램에 대한 resource를 해제 할 수 있다. 그런데, 위의 예제에서 'r'은 뭘까? 

Mode

파이썬에서의 File I/O에서 해당 파일을 어떤 목적으로 처리할 것인지에 대한 mode를 선택할 수 있도록 제공하고 있다. 따라서 우리는 특정 파일을 open할 때 해당 파일을 open해 어떤 목적으로 처리할 것인지를 선택하게 된다. 

f = open(filename, mode)

그렇다면, 이 mode에는 어떤 것들이 있을까? 파이썬 공식문서를 참고해보자면 아래와 같다. 여기서 우리가 관심있게 볼 것 들은 아마도 'r', 'w', 'a' 정도일 것 같다. 예시를 통해 하나씩 살펴보도록 하자.

https://docs.python.org/3/library/functions.html#open

먼저 메모장을 통해 간단한 text file을 하나 만들어보도록 하자. 파일명은 hosik.txt로 했다.

이러한 text file을 파이썬에서 처리해보자. 우선은 해당 파일을 열어야하므로 open을 해줘야 할 것이고, 우선은 해당 파일에 어떤 내용이 쓰여져있는지를 확인해야하므로 read mode를 통해서 우선을 읽어 보겠다. 이 때 우리가 추가적으로 알아야할 것들이 몇개 있다. 우리가 open을 통해 file을 열게 될 때 우리가 binary mode혹은 text mode를 설정해주지 않게되면 해당 파일은 text file로 열리게 되고, Text file I/O wrapper로 쌓인 file 객체가 된다. 이 객체는 몇가지 메소드를 가지고 있다. 

f = open('hosik.txt','r')
dir(f)
>>> [...,
 'buffer',
 'close',
 'closed',
 'detach',
 'encoding',
 'errors',
 'fileno',
 'flush',
 'isatty',
 'line_buffering',
 'mode',
 'name',
 'newlines',
 'read',
 'readable',
 'readline',
 'readlines',
 'reconfigure',
 'seek',
 'seekable',
 'tell',
 'truncate',
 'writable',
 'write',
 'write_through',
 'writelines']

너무 많아 일부를 잘라 냈다. 여기서 주목해 봐야할 것들은 read, write, close등이 있겠다. 이들에 대해서는 직관적으로 어떤 역할을 하는지 알 수 있을 것이라 생각하고 아래 예시를 통해 간단히 살펴보도록 하겠다. 추가적으로 사용하고 싶은게 있다면 파이썬 공식문서를 참고해서 사용해보기를 권장한다.

Read

그럼 다시 파일을 읽어보는 것부터 해보도록 하자. 아래와 같이 text file에 쓰여진 내용이 잘 읽어지는 것을 볼 수 있다.

f = open('hosik.txt','r')
print(f.read())
f.close()

>>> Hi! I'm Hosik!
>>> How are you?

 

그럼 다음으로는 해당 파일에 어떤 내용을 쓰고 싶은 상황이다. 이 때 주의해야할 점이 있다. write mode에 대해서 오해를 하는 경우가 많은데, Python 공식문서에 적힌 내용을 보면 write mode에서는 우선 해당 파일을 truncated한다. 즉 파일을 갈고 새로운 내용을 쓸 때 wrtie mode를 사용한다는 것이다. 따라서 동일한 파일에 대해서 write를 통해 내용을 적은 후 다시 읽어보겠다.

Write

f = open('hosik.txt','w')
f.write('ccccc')
f.close()

f = open('hosik.txt','r')
print(f.read())
f.close()
>>> ccccc

이렇게 기존의 내용은 모두 사라지고 우리가 새롭게 적은 내용만 존재하는 것을 확인할 수 있다. 그렇다면 내용을 추가로 적고싶을 때는 어떻게 해야하는 걸까? 이 때 사용하는 것이 append mode다. 즉, 기존의 text file의 맨 뒷단에 추가적인 내용을 적고싶다면 append mode를 사용해야한다는 것이다.

Append

f = open('hosik.txt','a')
f.write('\nddddd')
f.close()

f = open('hosik.txt','r')
print(f.read())
f.close()
>>> ccccc
>>> ddddd

이 때 append는 단순히 마지막 문자열에 붙이는 것이기 때문에 다른 line에 적어주고 싶다면 \n을 사용해야한다. 

Caution in using write()

그런데 이렇게 wirte mode와 append모드 처럼 write()가 필요한 경우에는 주의할 점이 있다. 서로 다른 OS를 사용할 경우 encoding type이 맞아야 파일을 읽고 쓰기가 가능하다. 따라서 다른 OS를 사용하는 사용자들간의 협업을 할 때를 고려해 encoding type을 설정해서 파일을 써줘야한다는 것을 주의하자.

f = open('hosik.txt','w', encoding ='utf8')
f.write('ccccc')
f.close()

With Statement


마지막으로 이러한 File I/O를 with 구문을 사용해서 해줄 수 있다. 이에 대해서 자세히 살펴보자. 종종 with statement를 사용하는 것을 봤을 것이다. 그러면 이러한 with 구문은 어떻게 동작하는 것일까?

우선 with문을 사용하는 이유부터 보자. 특정 프로세스가 끝나면 그 이후의 다른 프로세스를 위해 앞서 모두 사용한 것들을 닫아줘야한다. 예를 들자면 DB 세션을 사용할 때 다른 프로세스를 위해 반납해줘야하는 것이다. 과거에는 Exception Handling을 통해서 이를 처리했다. 하지만 Python 2.5 이후에 with문이 등장한 이후에는 with문을 사용하고 있다. 이러한 with문은 파이썬의 Context Manager가 with문의 body scope내에서만 특정 리소스에 접근가능하게하고 with절이 종료되면 해당 절에서의 모든 리소스를 해제하는 것이다. 사용예시를 살펴보자. 

with open('hosik.txt', 'r') as f:
    contents = f.read()
    print(contents)

이렇게 with문을 사용하게 될 경우 with 구문에서 특정 expression을 적어주고 해당 객체를 as를 통해서 특정 variable에 넣어주게 된다. 그러면 그 variable을 with절 내에서 자유롭게 접근할 수 있고, with절이 종료되면 관련 모든 리소스가 해제되는 것이다. 그래서 위의 예시에서 file을 open한 후 close해주는 코드를 작성하지 않았음에도 동일한 작업이 진행된 것이다.

정리하자면
with문을 통해서 (첫 줄) resource를 획득하고,
with절 내에서 자유롭게 그 리소스를 사용하고,
with절이 끝날 때 해당 리소스가 해제 반납되는 것이다.

그렇다면 with문은 어떻게 이런게 가능하게하는 것일까? Python 공식문서를 가보면 무척 복잡한 이야기들이 적혀있다. 몇가지 핵심 키워드를 가져오자면, with 구문은 Context Manager프로토콜을 준수하는 Context Manager라는 타입을 가진 객체에 대해서 이러한 처리를 가능하게 해준다는 것이다. 그렇다면 Context Manager가 뭔데 이런게 가능하게 하는 것일까?

조금 더 읽어보면 결국 __exit__()__enter__()라는 매직메소드를 가지고 있는 객체를 말하게 된다. 조금 더 자세히 이야기하자면, __enter__() 메소드는 with 구문이 실행될 때 해당 객체에 이러한 메소드가 있다면 contetx manager 프로토콜에 의해서 바로 실행되고, 이렇게 들어온 리소스를 as 뒤에 적힌 variable로 획득하게 된다. 그리고 with 절내에서 어떤 처리가 이루어지는 것은 두 매직메소드 외의 메소드들에 의해서 처리가 될 것이고, 이러한 처리가 이루어진 후에 with절이 종료될 때, 무조건 __exit__() 메소드가 실행되어 리소스를 해제한다. 직접 하나를 만들어보면서 확인해보자.

class Hello:
    def __enter__(self):
        # 사용할 자원을 가져오거나 만든다(핸들러 등)
        # file을 열거나 외부 리소스와 같은 것을 얻는 처리가 해당된다.
        print('enter...')
        return self # 반환값이 있어야 VARIABLE를 블록내에서 사용할 수 있다
        
    def sayHello(self, name):
        # 자원을 사용한다. ex) 인사한다
        print('hello ' + name)

    def __exit__(self, exc_type, exc_val, exc_tb):
        # 마지막 처리를 한다(자원반납 등)
        print('exit...')
        
   출처 : https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=wideeyed&logNo=221653260516

__enter__는 결국 with구문 시작시 제일 먼저 실행되는 메소드이고,
__exit__는 with 절 종료시 무조건 실행되는 메소드 인 것이다.
이를 활용해, 리소스를 받아오고, 해제할 수 있도록 구성함으로써, 우리가 사용하는 with구문이 가능해진 것이다.

위와같이 Hello라는 클래스를 만들고, 해당 클래스 내에 두 메소드를 정의함으로써, 해당 클래스 객체가 context manager 타입의 성격을 가질 때 with문의 expression에 사용할 수 있는 것이다. 즉, with 구문의 expression에는 반드시 이러한 두가지 메소드를 가진 객체가 들어올 수 있어야하는 것이다. 그러면 해당 객체 내에서 저 두가지 메소드가 불리면서 with구문이 동작하는 것이다. 

with Hello() as h:
    h.sayHello('obama')

>>> enter...
>>> hello obama
>>> exit...

# 출처 : https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=wideeyed&logNo=221653260516

따라서 우리가 지금 보고있던 File I/O에서 open을 통해 파일을 열게 될 경우 해당 객체는 context manager의 성격을 가지게 된다.( 내부적으로 __exit____enter__를 가지고 있다. ) 따라서, 이와 같이 with구문을 통해서 처리할 수 있는 것이고, 이러한 context manager의 프로토콜을 준수하는 성격을 가지는 객체들을 with구문을 통해서 처리할 수 있다는 것이다. 실제로 확인해보면 __exit____enter를 가지고 있는 것을 확인할 수 있다.

f = open('hosik.txt','r')
dir(f)
>>> [... ,
 '__enter__',
 ... ,
 '__exit__',
 ...]
with open('hosik.txt', 'r') as f:
    contents = f.read()
    print(contents)

이렇게 FIle Handling과 함께 With 구문에 대해서도 살펴봤습니다. 다음 번에는 Exception을 핸들링하는 방법과 Pickle에 대해서 알아보도록 하겠습니다. :)

 

References :

https://www.geeksforgeeks.org/file-handling-python/

 

File Handling in Python - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

https://ko.wikipedia.org/wiki/%EC%BB%B4%ED%93%A8%ED%84%B0_%ED%8C%8C%EC%9D%BC

 

컴퓨터 파일 - 위키백과, 우리 모두의 백과사전

 

ko.wikipedia.org

https://blockdmask.tistory.com/454

 

[python] 파이썬 파일읽기, 파일쓰기 (open , close, write, read, tell, seek)

안녕하세요. BlockDMask 입니다. 오늘은 파이썬에서 파일을 생성하고 읽고 쓰는 파일 입출력을 한번 다뤄볼까 합니다. 여기서 다룰 파일 관련 함수는 open, close, write, writeline, writelines, read, readline..

blockdmask.tistory.com

https://projooni.tistory.com/entry/Python-with%EC%A0%88-%EB%AC%B8%EB%B2%95%EC%9D%98-%EC%9D%B4%ED%95%B4

 

Python with절 문법의 이해

Python with절 문법의 이해 자원을 획득하고, 사용하고, 반납할때 주로 사용한다. 예를들어 파일을 여는 경우, 다른 프로세스를 위해 사용한 뒤에 닫아주어야 한다. 또는 DB 세션을 사용하는 경우,

projooni.tistory.com

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=wideeyed&logNo=221653260516 

 

[Python] with문 이해하기

Python의 with문에 대해서 알아보겠습니다. 자원을 획득하고 사용 후 반납해야 하는 경우 주로 사용합니다...

blog.naver.com

https://www.geeksforgeeks.org/with-statement-in-python/

 

with statement in Python - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

https://docs.python.org/3/reference/compound_stmts.html

 

8. Compound statements — Python 3.10.2 documentation

8. Compound statements Compound statements contain (groups of) other statements; they affect or control the execution of those other statements in some way. In general, compound statements span multiple lines, although in simple incarnations a whole compou

docs.python.org

 

'Python' 카테고리의 다른 글

Python - JSON & Pickle  (0) 2022.02.17
Python - Exception Handling  (0) 2022.02.16
Python - Module & Project  (0) 2022.02.15
Python OOP - Part2  (0) 2022.02.13
Python - Magic Method  (0) 2022.02.13