입출력

입출력은 여러 가지 형식으로 가능하다.

input()

input([입력시 표시될 문자열(옵션)]) 함수를 이용해서 키보드로부터 문자열을 입력받을 수 있다.

>>> num = input('입력하세요:')
입력하세요:123 문자

>>> print('num = ', num)
num =  123 문자

입력된 문자열을 원하는 객체로 변경하려면 문자열 객체 메소드 split()을 이용한다. 다음과 같이 문자열 12 34 문자를 입력받는다.

In [22]:
입력 = input('입력하세요:')
입력하세요:12 34 문자

입력 문자열을 공백 문자를 구분으로 리스트로 저장한다.

In [2]:
문자열 = 입력.split()
print(문자열)
['12', '34', '문자']

리스트 축약을 이용해 숫자형 문자열만 숫자로 변환하고 연산을 해본다.

In [19]:
,  = [int() for  in 문자열[:2]]
print("{} + {} = {}".format(, ,  + ))
12 + 34 = 46

print()

print(객체) 함수는 키워드인자가 아닌 모든 인자들을 str(객체) 함수를 이용해서 변환된 것을 출력한다. 여러 객체를 출력하기 위해서는 쉼표로 구분해서 나열하면 된다.

In [25]:
print('한글과', '컴퓨터의', '만남')
한글과 컴퓨터의 만남

기본적으로 각 객체 사이를 공백 문자를 넣어서 출력한다. 출력할 때 출력 객체 사이에 들어갈 문자열을 sep 옵션을 이용해 지정할 수 있다. 다음은 각 문자열 객체 사이에 ***를 삽입하고 있다.

In [32]:
print('한글과', '컴퓨터의', '만남', sep='***')
한글과***컴퓨터의***만남

다음은 구분 문자로 쉼표와 공백 문자를 넣어서 출력한 것이다.

In [1]:
print('하나', '둘', '셋', sep=', ')
하나, 둘, 셋

출력 문자열 끝을 end= 옵션을 이용해 바꿀 수 있다. 기본값은 end=\n이다.

In [33]:
print('한글', end='의 \n')
print('우수성', end='')
한글의
우수성

str()

str(객체) 함수는 객체.__str__() 메소드를 실행한다. 만일 객체__str__() 메소드를 구현하지 않았다면 repr(객체)를 실행한다. 다음과 같이 사람 클래스를 만들고 길동 객체를 만들어 print(길동)을 해보자.

In [2]:
class 사람:

    def __init__(self, 이름=None, 성별=None):
        self.이름 = 이름
        self.성별 = 성별

길동 = 사람('홍길동', '남')
print(길동)
<__main__.사람 object at 0x000001D86B09E898>

길동.__str__() 메소드가 구현되어 있지 않기 때문에 repr(길동)을 실행하게 된다.

In [3]:
repr(길동)
Out[3]:
'<__main__.사람 object at 0x000001D86B09E898>'

print(길동) 과 같은 결과가 나오는 것을 알 수 있다. 다음은 사람 클래스에 __str__() 메소드를 정의한 것이다.

In [5]:
class 사람:

    def __init__(self, 이름=None, 성별=None):
        self.이름 = 이름
        self.성별 = 성별

    def __str__(self):
        return '이름:{}, 성별:{}'.format(self.이름, self.성별)

길동 = 사람('홍길동', '남')
print(길동)
이름:홍길동, 성별:남

print(길동)의 결과는 print(길동.__str__())를 실행한 것과 같은 결과가 나오는 것을 알 수 있다.

In [6]:
print(길동.__str__())
이름:홍길동, 성별:남

즉, __str_() 메소드가 구현되어 있으면 이것을 사용하는 것을 알 수 있다.

repr()

repr(객체)는 문자열을 반환한다. repr(객체)객체.__repr()__ 메소드를 실행한다. 객체__repr()__ 메소드를 구현하지 않았다면 기본적으로 객체"<타입 이름 메모리 주소>"와 같은 정보가 출력된다. 대부분 __repr()__ 메소드는, eval(repr(객체)) 함수를 실행했을 때 원하는 결과가 나오도록 만든다.

사람 클래스를 이용해서 살펴보자. 길동 객체를 출력해보자.

In [7]:
class 사람:

    def __init__(self, 이름=None, 성별=None):
        self.이름 = 이름
        self.성별 = 성별

길동 = 사람('홍길동', '남')
print(길동)
<__main__.사람 object at 0x000001D86B09E4E0>

사람 클래스는 __str__() 메소드가 없기 때문에 repr(길동) 을 실행할 것이고, repr(길동)길동.__repr__()메소드를 실행하려고 하는데 __repr__() 메소드가 구현되어있지 않기 때문에 기본적인 정보인 타입 이름과 메모리 주소 정보가 출력 된다. 다음과 같이 __repr__() 메소드를 구현해보자.

In [8]:
class 사람:

    def __init__(self, 이름=None, 성별=None):
        self.이름 = 이름
        self.성별 = 성별

    def __repr__(self):
        return '이름은 "{}"이고 성별은 "{}"입니다.'.format(self.이름, self.성별)

길동 = 사람('홍길동', '남')
print(길동)
이름은 "홍길동"이고 성별은 "남"입니다.

print(길동)을 실행하면 길동.__str__() 메소드를 실행하려고 하는데 구현되어 있지 않으므로 repr(길동)을 실행하게 된다. 즉, 길동.__repr__() 메소드를 실행한다.

파일(File)

디렉토리, 파일들을 검색, 변경, 읽기, 쓰기하는 것에 대해서 알아보자. 파일이란 문서, 음악, 영상 데이터와 같은 다양한 종류의 데이터를 저장 장치(하드 디스크, 외장 하드, USB 저장 장치 등)에 저장하기 위해 사용되는 컴퓨터 자원이다. 디렉토리(또는 폴더라고도 불린다.)란 파일들 또는 또 다른 디렉토리들의 모임을 일컫는 이름이다. 경로(path)란 파일 또는 디렉토리를 나타내는 유일한 위치를 표시하기 위한 이름이다. 경로는 디렉토리와 디렉토리 또는 파일들을 경로 구분자로 연결하여 표현 한다. 경로 구분자는 윈도우즈는 역슬래시 \를 사용하고 유닉스 계열은 슬래시 /를 사용한다. 윈도우즈의 예를 들면 다음과 같다.

'c:\work\subdir\file.txt'

윈도우즈 경로는 맨 앞에 드라이브 이름과 콜론을 포함한다. 유닉스의 경우는 드라이브 이름이 없으며 최상위 디렉토리는 /로 시작한다. 유닉스의 경로 예는 다음과 같다.

/usr/lib/local

파일은 myfile.txt와 같이 표시하고 myfile을 파일이름(filename), txt를 확장자라고 부른다. 확장자가 없는 경우는 파일과 파일이름이 같다. 참고로 파일과 파일 이름에 대한 정의는 저서마다 다를 수 있다.

경로를 다룰 때 os, os.path, glob 모듈들은 문자열과 pathlib로부터 만든 객체를 사용할 수 있고, pathlib 모듈은 경로 객체를 사용한다.

pathlib 모듈

pathlib 모듈은 객체 형식의 경로를 사용하여 운영체제와 독립적으로 파일을 다룰 수 있게 해준다. pathlib.Path(path)를 이용하여 객체를 만들어 사용한다. os.path 함수들의 반환값은 문자열이지만 pathlib 메소드들의 반환값은 대부분 PurePath로부터 상속받은 객체이다. 다음과 같이 c:\work에 대한 경로를 Path 클래스를 이용해서 만들 수 있다.

In [24]:
import pathlib

my_path = pathlib.Path('c:\\work')
my_path
Out[24]:
WindowsPath('c:/work')

my_path는 결과에서 보는 바와 같이 WindowsPath 객체인 것을 알 수 있다. WindowsPathPurePath의 하위 클래스이다. 또한 경로 구분자로 슬래시 /를 사용할 수 있다. 윈도우즈 운영체제는 경로 구분자가 백슬래시이지만 슬래시도 혼용해서 사용할 수 있다. 하지만 혼용해서 사용하는 것은 오류의 가능성을 높여 주기 때문에 사용하지 않는 것이 좋다. pathlib는 경로가 객체이기 때문에 이러한 오류는 발생하지 않는다.

경로 만들기

경로는 단순한 문자열 그 자체(pathlib의 경우는 문자열로부터 만들어진 경로 객체)이기때문에 주어진 경로가 실제로 존재하는지는 필요할 때 반드시 확인을 해야 한다. 그렇지 않으면 오류가 발생한다.

os.path 모듈 이용

os.path 모듈은 경로를 나타내는 문자열 또는 pathlib의 경로 객체를 사용한다. 정확히는 유사 경로 객체(path-like object)이다. 예를 들어 경로 c:\work\subdir\file.txt의 디렉토리를 반환하는 메소드 os.path.dirname(path)에서 인자 path는 다음과 같이 문자열이 들어갈 수 있다.

In [1]:
import os

path = "c:\\work\\subdir\\file.txt"
os.path.dirname(path)
Out[1]:
'c:\\work\\subdir'

또는 다음과 같이 pathlib의 객체가 들어갈 수 있다.

In [5]:
import os
import pathlib

path = "c:\\work\\subdir\\file.txt"
path_obj = pathlib.Path(path)

os.path.dirname(path_obj) # pathlib 객체 대입
Out[5]:
'c:\\work\\subdir'

pathlib 모듈 이용

기존의 경로 객체에 추가하고자 하는 경로에 대한 문자열 또는 추가하려는 경로 객체를 합쳐서 새로운 경로를 만들 수 있다. joinpath(다른경로) 메소드를 이용해서 만들 수 있다. c:\work 폴더와 files 경로를 더해서 c:\work\files 경로를 만들어보자. 먼저 문자열 files와 기존 경로 객체를 합쳐서 새로운 경로를 만든다.

In [31]:
import pathlib

my_path = pathlib.Path('c:/work') # 경로 구분자로 슬래시를 이용해도 된다.

path_str = 'files' # 문자열

new_path = my_path.joinpath(path_str)
new_path
Out[31]:
WindowsPath('c:/work/files')

다음은 다른 경로 객체(other_path)와 결합하여 새로운 경로 객체를 만든는 예이다.

In [32]:
other_path = pathlib.Path('files') # 다른 경로 객체

new_path = my_path.joinpath(other_path)
new_path
Out[32]:
WindowsPath('c:/work/files')

경로 존재 판단

경로는 어떠한 문자열도 될 수 있으므로 주어진 경로가 존재하는지를 판단해야 한다.

os.path 모듈 이용

주어진 경로가 존재하는 지를 판단하는 함수로 os.path.exists(경로)를 사용할 수 있다. c:\work 디렉토리가 존재하는지를 알아보기 위해서는 다음과 같이 한다.

In [33]:
import os

os.path.exists('c:\\work')
Out[33]:
True

경로 c:\work\file.txt은 존재하지 않는다. 즉, c:\work 디렉토리는 존재하지만 그 안에 file.txt는 존재하지 않는다. 따라서 다음과 같이 exists메소드의 결과가 거짓이 나오는 것을 알 수 있다.

In [34]:
import os

os.path.exists('c:\\work\\file.txt')
Out[34]:
False

pathlib 모듈 이용

pathlib 모듈을 이용하려면 pathlib 객체의 exists() 메소드를 사용하면 된다.

In [35]:
import pathlib

my_path = pathlib.Path('c:\\work')
my_path.exists()
Out[35]:
True

위와 같이 exists() 매소드를 사용하려면 경로(Path) 객체를 먼저 만들어야 한다.

파일/디렉토리 판단

앞에서 주어진 경로가 실제로 존재하는지를 판단했다. 다음으로 존재하는 경로가 디렉토리 경로인지 파일 경로인지를 판단하자.

os.path 모듈 이용

주어진 경로가 실제로 존재하는 파일인지 디렉토리인지를 판단하는 방법은 os.path.isfile(경로) 또는 os.path.isdir(경로)를 사용한다.

In [36]:
import os

os.path.isfile('c:\\work')
Out[36]:
False
In [37]:
import os

os.path.isdir('c:\\work')
Out[37]:
True

pathlib 모듈 이용

pathlib 모듈를 사용한다면 Path.is_file() 또는 Path.is_dir() 메소드를 사용하면 된다.

In [39]:
import pathlib

my_path = pathlib.Path('c:/work')
my_path.is_dir()
Out[39]:
True
In [40]:
import pathlib

my_path = pathlib.Path('c:/work')
my_path.is_file()
Out[40]:
False

경로 순회

다양한 방법으로 주어진 경로 안에 있는 파일 및 디렉토리들을 순회할 수 있다. 경로는 모듈 os.path 메소들에서는 문자열을 이용하고 pathlib 모듈은 Path 객체를 이용한다.

os.walk 이용

os.walk(top_dir) 함수를 이용하여 디렉토리 경로 top_dir를 포함한 모든 하위 디렉토리 및 파일들을 나열할 수 있다. os.walk()는 3개의 원소를 갖는 튜플 (dirpath, dirnames, filenames)을 반환한다. dirpathtop_dir를 포함한 모든 하위 디렉토리들의 이름 문자열이다. dirpathtop_dir 디렉토리부터 시작해서 하위 디렉토리로 차례로 내려가면서 순회한다. os.walk()는 생성자(generator)라서 각각의 디렉토리(dirpath) 안의 하위 폴더와 파일 리스트를 반환한다. dirnames는 주어진 디렉토리 안에 있는 하위 디렉토리 이름들의 리스트이다. filenames는 주어진 디렉토리 안에 있는 하위 디렉토리가 아닌 파일 이름들이다. c:\work 폴더와 모든 하위 폴더에 있는 파일 이름을 나열하기 위해서는 다음과 같이 한다.

import os

top_path = 'c:\\work'

for dirpath, dirnames, filenames in os.walk(top_path):
    for filename in filenames:
        print(os.path.join(dirpath, filename))

여기서 주의해야 할 것은 윈도우즈에서 경로를 구분하는 문자 백슬래시 \를 이용할 때는 반드시 백슬래시 2번 \\을 사용하는 것이 안전하다. 왜냐면 문자열에서 백슬래시는 탈출문자로서 특수한 역할을 감당하기 때문이다. 예를 들면 \xab에서 \x 뒤의 두 자리문자는 16진수에 해당하는 문자이어야 하고 \xab는 그 숫자에 해당하는 문자를 의미한다. 16진수 ab는 정수 171이고 이 숫자에 해당하는 문자는 <<가 되어 아래와 같이 출력하게 된다.

In [20]:
print('c:\xab')
c:«

그러므로 c:\xab 문자 그대로 출력하려면 다음과 같이 탈출문자를 붙여야한다.

>>> print('c:\\xab')

c:\ab

glob.glob() 이용

모듈 glob의 메소드 glob(path)을 이용해서 원하는 파일과 디렉토리들을 찾을 수 있다. glob 메소드 인자 path에 특수 문자 *, ?, [] 들을 사용하여 좀 더 자유롭게 파일들을 찾을 수 있다. *는 모든 문자를 의미하고 ?는 임의의 문자 하나를 의미한다. 다음은 현재 작업 디렉토리의 파일 및 디렉토리들의 문자열 리스트를 반환한다.

import glob

glob.glob('*')

다음은 c:\work 디렉토리 밑의 확장자가 txt인 파일들을 모두 찾아 문자열 리스트 형식으로 반환한다.

glob.glob('c:\\work\*.txt')

**recursive=True를 이용하면 주어진 경로와 경로 아래의 모든 하위 디렉토리에 대해서 검색을 하게 된다. 다음은 c:\work 와 모든 하위 디렉토리에서 확장자가 py인 파일들의 문자열 리스트를 반환한다.

glob.glob('c:\\work\\**\\*.py')

파일 이름/확장자 분리

주어진 경로가 존재하는 파일이라면 파일과 경로로 분리하고 파일이름과 확장자로 분리할 수 있다. 파일과 디렉토리 경로로 분리하는 함수는 os.path.split(경로)를 사용한다. 다음은 c:\work\subdir\file.txt라는 파일을 파일 file.txt와 나머지 디렉토리 c:\work\subdir로 분리한다. 여기서 주의해야 할 것은 os.path.split(경로) 메소드는 주어진 경로가 실재로 있는지 없는지를 상관하지 않고 작동한다.

In [42]:
import os

os.path.split('c:\\work\\subdir\\file.txt')
Out[42]:
('c:\\work\\subdir', 'file.txt')

위 결과에서 보는 바와 같이 os.path.split 메소드는 경로의 맨 끝(file.txt)과 그 나머지(c:\\work\\subdir)로 구성된 문자열 튜플을 반환한다. 경로의 맨 끝이란 경로 구분자 백슬래시 다음 항목을 의미한다. 다음 경로 c:\work\는 마지막 백슬래시 뒤에 아무것도 없으므로 다음과 같이 두번째 항목이 빈 문자인 것을 알 수 있다.

In [43]:
import os

os.path.split('c:\\work\\')
Out[43]:
('c:\\work', '')

따라서 c:\work 경로를 분리하면 아래와 같이 첫번째 항목은 c:\이고 두번째 항목은 work가 되는 것을 알 수 있다. 그러므로 split 메소드를 사용할 때 이러한 점을 유의해야 한다.

In [44]:
import os

os.path.split('c:\\work')
Out[44]:
('c:\\', 'work')

그러므로 다음 예제와 같이 파일이 존재하는지를 먼저 확인하고 파일과 디렉토리로 구분하는 것이 좋을 것이다.

In [59]:
import os

path = 'c:\\work\\files\\123.txt'

if os.path.isfile(path):
    print("디렉토리 = '{}, 파일 = '{}'".format(*os.path.split(path)))
elif os.path.isdir(path):
    print('디렉토리 = ', path)
else:
    print('경로가 존재하지 않습니다.')
디렉토리 = 'c:\work\files, 파일 = '123.txt'

파일을 파일 이름과 확장자로 분리하는 것은 os.path.splitext(파일)을 사용한다.

In [60]:
import os

os.path.splitext('123.txt')
Out[60]:
('123', '.txt')

위 결과에서 주의해야 할 것은 튜플의 두번째 항목에 (.)이 포함된다는 것이다. os.path.splitext() 메소드는 인자로 파일이 아니라 경로가 들어갈 수 있다. 이 때는 결과로 반환되는 두번째 항목은 점과 뒤의 확장자가 되고 첫번째 항목은 그 나머지가 된다. 즉 첫번째 항목에 디렉토리와 파일 이름이 포함된다.

In [62]:
import os

os.path.splitext('c:\\work\\1234.txt')
Out[62]:
('c:\\work\\1234', '.txt')

파일 입출력

파일 입출력을 위해 open 함수를 이용해 파일 객체를 생성한 후 readline, readlines, read, write 메소드들을 이용하면 된다. 파일 객체를 만들 때 읽는 모드와 쓰는 모드로 지정해 줄 수 있다. 파일을 읽거나 쓰는 일을 모두 마친 후에는, close 메소드를 호출하여 파일 자원에 대한 사용을 종료해야 한다.

파일에 쓰기

In [20]:
 = open('새로운파일.txt', 'w')
.close()

파일을 쓰기 모드('w')로 열게 되면 해당 파일이 이미 존재할 경우 기존 파일 내용이 모두 사라지고, 해당 파일이 존재하지 않으면 새로운 파일이 생성된다. 위의 예에서는 디렉토리에 파일이 없는 상태에서 새로운파일.txt를 쓰기 모드인 'w'로 열었기 때문에 새로운파일.txt라는 이름의 새로운 파일이 현재 디렉토리에 생성되는 것이다.

만약 새로운파일.txt라는 파일을 C:\work라는 디렉토리에 만들고 싶다면 다음과 같이 작성해야 한다.

In [21]:
 = open("C:\\work\\새로운파일.txt", 'w')
.close()

파.close()는 열려 있는 파일 객체()를 닫아 주는 역할을 한다. 프로그램을 종료할 때 파이썬이 열려 있는 파일의 객체를 모두 닫아주기 때문에 close() 문장을 생략할 수 있지만, 프로그램 종료 전에 열려있는 파일을 다른 어딘가에서 사용하려고 하면 오류가 발생한다. 그러므로 반드시 열었던 파일은 닫아주어야 한다.

경로를 이용해서 파일에 쓰는 방법에 대해서 알아보자. os.makedirs(경로, exist_ok=False) 함수를 이용해서 주어진 경로의 디렉토리가 없으면 재귀적으로 만든다.

my_dirpath = 'c:\\work\\files\\subdir1\\subsubdir1'

os.makedirs(my_dirpath)
  • 새로운 파일 만들기

새로운 파일의 경로를 설정한다.

file_path = 'c:\\work\\files\\subdir1\\subsubdir2\\test.txt'

os.path.dirname(경로)를 이용해서 디렉토리만 추출한 후, 디렉토리가 없으면 만든다.

os.makedirs(os.path.dirname(file_path), exist_ok=True)

내장 함수 open()과 쓰기 모드 w를 이용해 파일을 생성한다. 그리고 생성된 파일 객체 fwrite() 메소드를 이용해 파일에 쓴다.

with open(file_path, 'w') as f:
    f.write('lalala')

파일 객체의 write 메소드를 이용해 파일에 쓸 수 있다.

In [22]:
 = open("새로운파일.txt", 'w')
.write("안녕하세요.")
.close()

 = open("새로운파일.txt", 'r')
 = .read()
print()
.close()
안녕하세요.

기존 파일에 추가하기

파일을 열 때 모드를 'a'로 하면 추가모드가 되어 기존 파일 내용의 맨 끝에 새로운 내용을 추가한다. 아래 코드를 실행해보고 새로운파일.txt 파일을 열어 확인해 보자.

In [4]:
 = open("새로운파일.txt", 'a')
.write("새로운 내용을 추가했습니다.")
.close()

다음은 이육사 시인의 청포도이다. 청포도.txt 파일에 저장해 보자.

In [14]:
청포도 = """내 고장 칠월은
청포도가 익어 가는 시절.

이 마을 전설이 주저리주저리 열리고
먼 데 하늘이 꿈꾸며 알알이 들어와 박혀,

하늘 밑 푸른 바다가 가슴을 열고
흰 돛 단 배가 곱게 밀려서 오면,

내가 바라는 손님은 고달픈 몸으로
청포(靑袍)를 입고 찾아온다고 했으니,

내 그를 맞아 이 포도를 따 먹으면
두 손은 함뿍 적셔도 좋으련,

아이야, 우리 식탁엔 은쟁반에
하이얀 모시 수건을 마련해 두렴."""

# 쓰기위해 파일 열기
 = open('청포도.txt', 'w', encoding='utf-8')
# 파일에 쓰기
.write(청포도)
# 파일 닫기
.close()

파일 읽기

내장 함수 open(파일경로, 모드)파일경로라는 파일을 모드라는 형태로 만들어 파일 객체를 반환한다.

모드 설명
r 읽기 전용 모드
w 쓰기 전용 모드. 새로운 파일을 만든다.(같은 이름의 파일이 있으면 지운다)
a 기존 파일에 추가한다.(파일이 없으면 새로 만든다.)
r+ 읽기와 쓰기 둘 다 가능하다.
b 바이너리 파일 모드로 읽고 쓴다. rb 또는 wb
t 텍스트 형식으로 읽고 쓴다. rt 또는 wt

파일 객체의 readline() 메소드를 이용하여 파일 내용을 읽는다. 앞에서 저장한 청포도.txt 파일을 읽어보자.

In [16]:
#  모드가 설정되어 있지 않으면 기본은 읽기('r')모드
 = open('청포도.txt', encoding='utf-8')
 = .readline()
while :
    print(, end='')
     = .readline()
.close()
내 고장 칠월은
청포도가 익어 가는 시절.

이 마을 전설이 주저리주저리 열리고
먼 데 하늘이 꿈꾸며 알알이 들어와 박혀,

하늘 밑 푸른 바다가 가슴을 열고
흰 돛 단 배
... 생략 ...

직접하기

  • 청포도.txt 파일에 제목 “청포도”와 저자 “이육사”를 함께 저장하는 프로그램을 작성하시오.

파일 객체 입출력 메소드들은 다음과 같다.

메소드 설명
read([크기]) 파일을 열 때 모드에 따라 크기가 주어지면 크기 만큼의 바이트 또는 글자수를 읽어온다. 크기가 없으면 파일 전체를 읽어 온다.
readlines([크기]) 크기 줄 만큼을 읽어온다. 그렇지 않으면 파일 전부를 줄 단위로 읽어 온다.
write(문자열) 문자열을 파일에 쓴다.
writelines(문자열리스트) 줄 단위의 문자열 리스트를 파일에 쓴다.
close() 파일 자원을 닫는다.
flush() 버퍼에 있는 것을 디스크에 쓴다.
seek(위치) 주어진 위치로 스트림을 이동한다.
closed 파일 자원이 닫혔으면 참(True) 반환

with

파일 입출력을 위해서는 openclose를 반복해야 한다.

 = open("file.txt", 'w')
.write("파일을 open() 하면 반드시 close()를 해야 한다.")
.close()

이러한 과정을 자동으로 처리할 수 있게 한 것이 with문이다.

with문맥 관리자(context manager)와 관련되어 더 많은 작업을 할 수 있다.

In [18]:
with open("청포도.txt", encoding='utf-8') as :
    for  in :
        print(, end='')
내 고장 칠월은
청포도가 익어 가는 시절.

이 마을 전설이 주저리주저리 열리고
먼 데 하늘이 꿈꾸며 알알이 들어와 박혀,

하늘 밑 푸른 바다가 가슴을 열고
흰 돛 단 배
... 생략 ...