2019.01.03 - [파이썬 코딩의 기술] - Study01

3 분 소요

본 포스팅은 파이썬 코딩의 기술 이라는 책을 참고하여 개인 공부를 하면서 정리하고 있습니다. 문제 될 시 삭제하겠습니다.

[파이썬 코딩의 기술] 01장 파이썬 다운 생각

WPS 수업이 끝나고 같이 수업 들었던 분들과 파이썬 코딩의 기술이라는 책으로 진행한 study내용을 정리했습니다.

bytes, str, unicode 차이

python3에서는 bytes와 str 두 가지 타입으로 문자 시퀀스를 나타낸다.

bytes 인스턴스는 로 8비트(raw 8bit) 값을 저장하고, str 인스턴스는 유니코드 문자를 저장한다.

  • 유니코드 문자 => raw 8bit(binary data) = encode
  • raw 8bit(binary data) => 유니코드 문자 = decode

binary data는 컴퓨터에서 저장과 처리를 위해 이진 형식으로 인코딩 된 데이터를 말한다.

  • 핵심정리

    • 파이썬3에서 bytes는 8비트 값을 저장하고, str은 유니코드 문자를 저장한다. ‘>’나 ‘+’와 같은 연산자에 bytes와 str 인스턴스를 함께 사용할 수 없다.
    • 헬퍼 함수를 사용해서 처리할 입력값이 원하는 문자 시퀀스 타입(8비트 값, UTF-8인코딩 문자, 유니코드 문자 등)으로 되어 있게 한다.
    • 바이너리 데이터를 파일에서 읽거나 쓸 때는 파일을 바이너리 모드(‘rb’ 혹은 ‘wb’)로 오픈한다.

헬퍼함수는 내장된 함수가 아니다. 반복 사용되는 코드나 코드의 간결성을 위해 만들어진 함수로써 직접 만들어주어야 한다.

복잡한 표현식 대신 헬퍼 함수를 작성하자

파이썬에서는 간단한 문법을 통해 많은 로직의 코드들을 한 줄로 쉽게 작성할 수 있게 해준다. 하지만 이렇게 코드를 줄여서 사용하게 되면 오히려 다른사람들이 봤을 때 코드를 쉽게 이해할 수 없게 된다. 이러한 코드들은 좋은 코드가 아니다. 따라서 조금 더 코드를 작성하더라도 코드의 가독성을 높여주는 것이 중요하다.

from urllib.parse import parse_qs
my_values = parse_qs('red=5&blue=0&green=',
                     keep_blank_values=True)
print(repr(my_values))

>>>
{'red': ['5'], 'green': [''], 'blue': ['0']}

red = my_values.get('red', [''])[0] or 0
green = my_values.get('green', [''])[0] or 0
opacity = my_values.get('opacity', [''])[0] or 0
print('Red:     %r' % red)
print('Green:   %r' % green)
print('Opacity: %r' % opacity)

>>>
Red:	  '5'
Green:   0
Opacity: 0

위의 코드를 헬퍼함수를 통해 바꾸면 아래와 같다

def get_first_int(values, key, default=0):
	found = values.get(key, [''])
	if found[0]:
		found = int(found[0])
	else:
		found = default
	return found

이렇게 헬퍼함수를 만들어 놓고 사용하면 or를 사용한 복잡한 표현식보다 호출 코드가 훨씬 더 명확해진다.

green = get_first_int(my_values, 'green')

따라서 무조건 짧은 코드를 만들기보다는 가독성을 선택하는게 좋다. 첫번째 코드와 같이 이해하기 어려운 복잡한 표현식에는 파이썬의 함축적인 문법을 최대한 사용하지 않는 것이 좋다.

if/else 표현식을 이용하면 or 나 and 같은 bool 연산자를 사용할 때보다 읽기 수월한 코드를 작성할 수 있다.

시퀀스 슬라이싱

시퀀스에 속하는 객체는 문자열, 리스트, 튜플이다. 이 시퀀스의 특징은 indexing, slicing, concatenation, repitition, member inspection(in 연산자), length(len())가 있다.

파이썬은 기본적으로 시퀀스를 슬라이스해서 조각으로 만드는 문법을 제공한다. 이 슬라이스를 하게 되면 최소한의 노력으로 시퀀스 아이템을 원하는 부분만 가져올 수 있다. 이 슬라이싱 문법은 기본적으로 다음과 같다.

somelist[start:end:stride]

이 슬라이싱 문법을 사용할 때는 가독성을 좋게 만들어주는 것이 중요하다.

  • stride를 사용해야하는 경우에는 양수값을 사용하도록 한다.
  • 한 슬라이스 내에서 start, end 와 stride 3가지를 동시에 사용하지 않도록한다. 만약 3가지를 동시에 사용해야한다면 stride를 사용한 값을 인스턴스에 넣고 그 인스턴스를 슬라이싱하여 원하는 값을 뽑아내도록 한다.

리스트 컴프리헨션(list comprehension), 제너레이터(generator)

리스트 컴프리헨션

map과 filter대신 리스트 컴프리헨션을 사용하는 것이 좋다. 왜냐하면 리스트 컴프리헨션을 사용하는 경우 추가적인 lambda 표현식이 필요 없기 때문에 내장 함수인 map, filter를 사용한 것보다 코드가 더 명확하다. 하지만 리스트 컴프리헨션에서 표현식을 두 개 이상 사용하게 될 경우에는 코드의 가독성이 떨어진다. 이러한 경우에는 일반적인 if문과 for문을 사용하거나 헬퍼 함수를 작성하는 것이 더 좋다.

제너레이터

일반적으로 리스트 컴프리헨션의 데이터가 클 경우에는 제너레이터를 사용하는 것이 더 좋다. 입력이 적은 경우에는 괜찮지만 클 경우에는 메모리를 많이 소모해서 프로그램을 망가뜨리는 원인이 되기 때문이다. 하지만 제너레이터의 경우에는 이터레이터로 한 번에 한 출력만 만드므로 메모리 문제를 피할 수 있다.

range보다는 enumerate 사용하기

enumerate는 이터레이터에서 루프 인덱스와 다음 값을 한 쌍으로 가져와서 넘겨준다. enumerate로 작성한 코드는 다음과 같다.

flavor_list = ['vanilla', 'chocolate', 'pecan', 'strawberry']

for i, flaovr in enumerate(flavor_list):
    print(i + 1, flavor)
    
>>>
1 vanilla
2 chocolate
3 pecan
4 strawberry

enumerate는 이터레이터를 순회하면서 이터레이터에서 각 아이템의 인덱스를 얻어오는 간결한 문법을 제공한다. 따라서 range로 루프를 실행하고 시퀀스에 인덱스로 접근하기보다는 enumerate를 사용하는 것이 좋다. 그리고 enumerate에서 두 번째 파라미터를 사용하면 세기 시작할 숫자를 지정할 수 있다.(default 값은 0이다.)

태그:

카테고리:

업데이트: