Skip to content

Latest commit

 

History

History
257 lines (222 loc) · 9.29 KB

211120.md

File metadata and controls

257 lines (222 loc) · 9.29 KB

Day 48

한 권으로 개발자가 원하던 파이썬 심화 A to Z

표준 입출력 처리

표준 입력 input은 메소드, 표준 출력 print는 함수다.

input # <bound method ~~~>
print # <function print>

문자열 형식화

문자열 출력이 필요하면 __str__이 자동으로 호출된다.

class User:
    def __str__(self):
        return 'User class {}'.format(id(self))
    
    def __repr__(self):
        return 'repr class {}'.format(id(self))

u = User()
print(u) # User class ~~~
print(u.__str__) # print(u)와 같게 출력된다.

# 주피터 노트북 셀은 개발환경이므로 기본으로 __repr__이 실행된다.
# 셀에서 객체를 출력하면 __repr__을 실행한다.
u # repr class ~~~
u.__repr__() # u를 쳤을 때와 같게 출력된다.

str(u) # User class ~~~, 내장 함수 str은 __str__을 호출해서 처리한다.
repr(u) # repr class ~~~, 내장 함수 repr은 __repr__을 호출해서 처리한다.

문자열의 포매팅은 함수와 메소드를 사용해서 처리하는 방식이 기본이다.

format # <function format(value, format_sepc='', /)>, 함수
str.format # <method 'format' of 'str' objects>, 메소드

a, b, c = 1, 2, 3
format('%d, %d, %d' %(a, b, c)) # '1, 2, 3'
print('%d, %d, %d' %(a, b, c)) # 1, 2, 3

# 아무것도 지정되지 않은 중괄호의 개수와 실제 변수의 개수는 같아야 한다.
print('a = {}, b = {}, c = {}'.format(a, b, c)) # a = 1, b = 2, c = 3

# 숫자로 지정하면 중괄호의 개수와 변수의 개수가 같지 않아도 된다.
print('a = {0}, b = {1}, c = {2}'.format(a, b, c)) # 인자의 위치와 매핑
print('a = {0}, b = {0}, c = {0}'.format(a, b, c)) # a = 1, b = 1, c = 1 출력

# 딕셔너리 이용
d = {'a': 2, 'b': 4, 'c': 6}
'a = {0[a]}, b = {0[ b]}, c = {0[c]}'.format(d) # 'a = 2, b = 4, c = 6' 출력
                                                # 숫자 다음에 대괄호를 붙이고 키 값을 인자로 전달
'a = {a}, b = {b}, c = {c}'.format(**d) # 위와 출력 값이 같다. 중괄호에 키를 입력하면 매핑된다.

# 변수 위치 다음에 콜론을 지정하고 숫자 포맷을 지정한다.
# 숫자 포맷 앞의 숫자는 자릿수를 의미하고, 숫자의 자릿수 앞에 <는 좌측 정렬, >는 우측 정렬, ^는 가운데 정렬이다.
print('{0:5d}, {1:>10d}, {1:<10d}, {2:^9d}'.format(a, b, c)) # ____1, _________2, 2_________, ____3____ 출력, _는 원래 띄어쓰기이나 가시성을 위해 이렇게 작성

# 실수는 소수점 길이가 추가된다.
# 실수의 자릿수 전체 길이와 소숫점 길이를 분리해서 사용한다.
'{0:>5.5f}'.format(1.33) # ____1.33000

# 천 단위로 쉼표
'{:,}'.format(10000) # 10,000

# 백분율 처리
'{:.2%}'.format(19/22) # 86.36%

# 날짜
import datetime
d = datetime.datetime(2021, 11, 20, 17, 25, 24)
'{:%Y-%m-%d %H:%M:%S}'.format(d) # '2021-11-20 17:25:24'
print(f'{d:%Y-%m-%d %H:%M:%S}') # 2021-11-20 17:25:24

파일 읽고 쓰기

파일은 문자열로 작성되어 있으므로 유니코드와 바이트 문자열을 기준으로 처리한다.
쓰기

f = open('file.txt', 'wt') # 파일 이름과 쓰기모드를 지정해 파일 객체를 만들고 변수 f에 할당
w = '''file 
i
o
'''
f.writelines(w) # 이 파일 객체의 메소드로 문자열 작성
f.close # 파일을 닫으면 이 파일이 디스크에 생성된다.

읽기

fr = open('file.txt', 'rt') # 파일을 읽기 모드로 열고 변수에 객체를 할당
fr # <_io.TextIOWrapper name='file.txt' mode='rt' encoding='cp949'>
# Windows에서 파일을 만들면 문자 세트를 유니코드가 아닌 cp949를 사용하기 때문에 encoding이 cp949인 것이다.

fr.readline() # file 출력, 작성한 파일이 한 줄을 읽는다.
fr.readline() # i 출력, 다음 줄을 읽는다.
fr.readline() # o 출력
fr.close() # 파일을 더 사용하지 않을 때는 close 메소드로 닫아준다.

인코딩을 지정해 파일을 열기

fu = open('file.txt', 'rt', encoding='euc-kr')
fu # <_io.TextIOWrapper name='file.txt' mode='rt' encoding='euc-kr'>

a = fu.readline().encode(encoding='utf-8') # 한 줄을 읽는다. 암호화할 때 인코딩을 변경한다.
a.decode(encoding='utf-8') # 복호화할 때도 같은 인코딩 처리
fu.close()

인코딩을 지정해 파일 생성

f_u = open('file_u.txt', 'wt', encoding='utf-8')
f_u.writelines(w)
f_u.close()
f_u = open('file_u.txt', 'rt', encoding='utf-8')
f_u # <_io.TextIOWrapper name='file_u.txt' mode='rt' encoding='utf-8'>

s = f_u.read() # 한 번에 모든 것을 읽는다.
len(s) # 전체 문자의 길이를 확인한다.
f_u.close()

파일도 객체이고 객체 내의 원소가 줄인 반복형 객체이므로 순환문에 직접 open해서 사용할 수 있다.

for i in open('file_u.txt', 'rt', encoding='utf-8'):
    print(i)
'''출력
file

i

o
'''
# 빈줄 출력 방지
for i in open('file_u.txt', 'rt', encoding='utf-8'):
    print(i, end='')

파일을 바이트 문자열로 처리할 때는 바이트 단위로 처리하도록 모드를 t에서 b로 바꾼다.
영어로 된 바이트 문자열은 문자열 앞에 항상 b가 표시된다.

fb = open('file_b.txt', 'wb')
fb.write(b'This is byte')
fb.close()

fb = open('file_b.txt', 'rb')
fb # <_io.BufferedReader name='file_b.txt'>, 바이트는 버퍼 처리의 객체인 것을 알 수 있다.
fb.read() # b'This is byte'
fb.close()

임시파일 처리

간단한 정보는 임시파일로 만들어 사용하고 마지막에 파일에 저장해도 된다.

import io

s = io.StringIO('Python') # 문자열 객체를 저장하는 임시파일 생성
s # StringIO 객체
s.read(), s.getvalue() # ('Python', 'Python'), 모든 파일을 읽거나 저장된 모든 파일을 가져올 수 있다.
s.close() # 임시파일도 사용하고 나면 닫는다.

print 문으로 줄을 추가할 수 있다.

output = io.StringIO()
output.write('First line.\n') #문자열을 넣고 쓴다.
print('Second line.', file=output) # print 함수에 임시 파일을 넣고 출력

# 현재 파일 위치는 tell 메소드로 확인할 수 있다.
output.tell() # 25

# 첫 줄로 이동하려면 seek 메소드에 정보를 0으로 전달한다.
output.seek(0)
output.read() # 'First line.\nSecond line.\n'

# 임시파일을 사용하면 닫아야 하는데 그전에 다른 변수에 할당하면 임시파일과 상관없이 사용할 수 있다.
contents = output.value() # 작성한 값을 변수에 할당하고 임시파일을 닫는다.
output.close()
contents # 'First line.\nSecond line.\n'

BytesIO 클래스로 직접 임시파일을 객체로 만들어 사용할 수 있다.
바이트 문자열과 유니코드 문자열의 차이는 바이트 문자열은 getbuffer 메소드로 복사해 별도의 memoryview 객체를 만들어서 사용한다.

b = io.BytesIO(b'abcdef')
b # BytesIO 객체
view = b.getbuffer() # 객체를 버퍼로 표시한 후에 슬라이스로 변경할 수 있다.
view[2:4] = b'56'
view # <memory at ~~~>, 실제 튜플을 제공하므로 바이트 문자열의 임시파일이 갱신된다.

b.read(), b.getvalue() # (b'ab56ef', b'ab56ef')

# 유니코드와 마찬가지로 파일을 쓰고 tell과 seek도 사용 가능하다.
bc = io.BytesIO()
bc.write(b'Hello World!!!')
bc.tell() # 14
bc.seek(0)
bc.read() # b'Hello World!!!'
bc.close()

컨텍스트 환경 처리

컨텍스트 환경을 사용하면 파일을 열고 닫는 것을 자동으로 해준다.

# 컨텍스트 환경인 with문에서 파일을 열고 내부에 for문으로 출력한다. 사용을 마치면 자동으로 파일을 닫는다.
with open('withfile.txt', 'rt') as wf:
    for i in wf:
        print(i, end='')

# 파일을 저장한 wf를 확인하면 __enter__, __exit__ 메소드가 구현되어 있다.
# 컨텍스트 환경에 들어갈 때는 __enter__가, 다 사용했을 때는 __exit__이 자동으로 실행된다.
wf.__enter__ # <function TextIOWrapper.__enter__>
wf.__exit__ # <function TextIOWrapper.__exit__>

사용자 환경에 컨텍스트 구현

class File:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode

    def __enter__(self): # 컨텍스트 환경에 들어갈 때 __enter__ 정의
        self.open_file = open(self.filename, self.mode) # 파일을 열어 객체 저장
        return self.open_file # 객체 반환

    def __exit__(self, type, value, traceback): # 종료되거나 예외가 발생하면 인자로 전달되고, 내부에 예외 처리
        print('type ', type)
        print('value ', value)
        print('traceback ', traceback)
        self.open_file.close()
        if type != None:
            return True

with File('with_1.txt', 'w') as infile:
    infile.write('foo ')
'''출력
type None
value None
traceback None
'''

with File('with_1.txt', 'rt') as f:
    print(f)
    for i in f:
        print(i)
    f.seek(0)
    print(f.read())
'''출력
<_io.TextIOWrapper name='with_1.txt' mode='rt' encoding='cp949'>
foo
foo
type None
value None
traceback None
'''

with File('with_1.txt', 'rt') as f: # 파일을 읽고 난 후, 예외를 발생시키면, __exit__ 스페셜 메소드가 처리
    raise FileNotFoundError('No File')
'''출력
type <class 'FileNotFoundError'>
value No File
traceback <traceback object at ~~~~~~~>
'''