본문 바로가기
코딩 연습/코딩배우기

파이썬 코딩의 기술 - 1.Pythonic #1

by good4me 2020. 11. 15.

goodthings4me.tistory.com

 

■ Effective_python1.Pythonic #1

01.사용중인 파이썬 버전 확인

## python --version 또는 python -V

#C:\>python --version
#Python 3.8.3
#
#C:\>python -V
#Python 3.8.3

import sys
print(sys.version)
# 3.8.3 (default, Jul  2 2020, 17:30:36) [MSC v.1916 64 bit (AMD64)]
print(sys.version_info)
# sys.version_info(major=3, minor=8, micro=3, releaselevel='final', serial=0)

 

02. PEP8 스타일 가이드

PEP8 : 파이썬 코드 작성 스타일 가이드

공백(whitespace, 탭/스페이스/새줄(newline))

- 탭 대신 스페이스로 들여쓰기
- 문법적으로 중요한 들여쓰기는 스페이스 4칸 사용
- 한 줄에 79자 이하로 함
- 식이 길어 다음 줄에 이어쓸 경우 일반적인 들여쓰기보다 4칸(스페이스) 더 들여씀
- 파일 내에서 함수와 클래스는 빈 줄 두개로 구분
- 클래스 내에서 메서드는 빈 줄 하나로 구분
- 딕셔너리(dictionary)에서 키와 콜론(:) 사이는 붙이고, 키와 값은 콜론 다음에 스페이스 1개 넣는다.
- 변수 대입(=) 앞,뒤에 스페이스 하나만 사용함
- 타입 표기를 덧붙이는 경우에는 변수 이름과 콜론 사이에 공백을 넣지않으며, 콜론과 타입 정보 사이에 스페이스 1개 넣는다.
리스트 인덱스, 함수 호출, 키워드 인수 할당에는 스페이스를 사용하지 않는다.



명명규약

- 함수, 변수, 속성(attribute) : lowercase_underscore (snake case)
- 보호(protected) 인스턴스 속성 : _leading_underscore
- 비공개(private) 인스턴스 속성 : __leading_undersocre
- 클래스(예외 포함) : CapitalizedWord (camel case)
- 모듈 수준 상수 : ALL_CAPS (단어와 단어 사이 밑줄)
- 클래스의 인스턴스 메서드의 첫 번째 파라미터(호출 대상 객체 참조) 이름은 반드시 self로 사용
- 클래스 메서드의 첫 번재 파라미터(해당 클래스 참조) 이름은 반드시 cls로 사용



식과 문장

- 긍정적인 식을 부정하지 말고(if no a is b) 부정을 내부에 넣어라(if a is not b)
- 빈 컨테이너(container)나 시퀀스([]나 '' 등)를 검사할 때는 길이를 0과 비교(if len(something) == 0) 하지말고,
  빈 컨테이너나 시퀀스 값이 암묵적으로 False라는 사실을 활용해 'if not 컨테이너' 조건문을 써라
- 비어있지 않은 컨테이너나 시퀀스([1]이나'hi' 등)를 검사할 때도 길이를 0보다 큰지 비교하지 말고, 
  'if 컨테이너'가 비어있지 않은 경우 암묵적으로 True라는 사실을 사용하라.
- 한 줄로 된 if문, for, while loop, except 복합문을 사용하지 말라. (명확성을 위해 각 부분을 여러 줄로 나눠 배치)
- 식을 한 줄로 쓸수 없는 경우, 식을 괄로로 묶고 줄바꿈과 들여쓰기를 추가해라.
- 여러 줄에 걸쳐 식을 쓸 경우, 계속을 의미하는 \ 문자보다는 괄호를 사용해라.



임포트

- 항상 파일의 맨 위에 import(from x import y도 포함) 문을 놓는다.
- 모듈을 임포트할 때는 절대적인 이름(absolute name)을 사용하고, 현 모듈의 경로에 상대적인 이름은 사용하지 말라
  (예로, import foo 대신 from bar import foo 사용)
- 상대적인 임포트를 반드시 해야하는 경우, from . import foo처럼 명시적 구문을 사용하라.
- 임포트 순서는 표준 라이브러리 모듈 > 서드파티 모듈 > 자신이 만든 모듈 순으로 하고, 각각의 하위 섹션에서는 알파벳 순서로 임포트하라.

 

good4me.co.kr

 

03. bytes와 str의 차이

▷파이썬의 문자열 시퀀스 표현 타입 : bytes, str

## 아래 코드에서 bytes 인스턴스는 부호 없는 8바이트 데이터가 들어감

a = b'h\x65llo'

print(a)
# b'hello'

al = list(a)
print(al)
# [104, 101, 108, 108, 111]

print(type(al[0]), hex(al[0]))
# <class 'int'> 0x68

 

▷str 인스턴스에는 사람이 사용하는 언어의 문자를 표현하는 유니코드 코드 포인트(code point)가 들어감

a = 'a\u0300 propos'
print(a)
# à propos

print(list(a))
# ['a', '̀', ' ', 'p', 'r', 'o', 'p', 'o', 's']

 

▷bytes나 str은 상호 직접 대응하는 인코딩이 없다.

## str 인스턴스에는 이진 인코딩이 없고, bytes 인스턴스에는 텍스트 인코딩이 없다.
## str을 유니코드 데이터로 변환하여 사용하는데, str의 ecode() 메서드를 호출하고,
## 이진 데이터를 유니코드로 데이터로 변환 시 bytes의 decode() 메서드 호출함
## 일반적으로 시스템 디폴트 인코딩 방식은 utf-8임


## str 인스턴스를 받아 encode() 후 bytes로 반환 또는 bytes 인스턴스를 받아 decode() 후 str로 반환
def to_bytes_or_str(bytes_or_str):
    if isinstance(bytes_or_str, str):
        value = bytes_or_str.encode('utf-8')
    elif isinstance(bytes_or_str, bytes):
        value = bytes_or_str.decode('utf-8')
    else:
        value = bytes_or_str
    
    return value


print(to_bytes_or_str(b'foo'))
# foo

print(to_bytes_or_str('bar'))
# b'bar'

print(to_bytes_or_str('한글'))
# b'\xed\x95\x9c\xea\xb8\x80'

print(to_bytes_or_str(b'\xed\x95\x9c\xea\xb8\x80'))
# 한글

 

파이썬에서 이진 8비트 값과 유니코드 문자열을 다룰 때, bytes와 str은 + 연산자, 이항 연산자(> 또는 <), format string의 % 연산자 등에서 같은 형식을 대입해야 한다.

 

▷04. C 스타일 형식 문자열을 str.format과 쓰기보다는 인터폴레이션 f-문자열을 사용하라

형식화(formatting)란, 미리 정의된 문자열에 데이터 값을 끼워 넣어서 사람이 보기 좋은 문자열로 저장하는 과정임
파이썬 언어에 내장된 기능과 표준 라이브러리 통해 형식화

☞ 형식화 연산자 % 사용

## 파이썬은 %d, %f, %s, %x 등 C언어 printf 사용하는 대부분의 형식 지정자 지원

a = 0b10111011
b = 0xc5f
print('2진수: %d, 16진수: %d' % (a, b))  
# 2진수: 187, 16진수: 3167


key = 'my_var'
value = 1.234
formatted = '%-10s = %.2f' % (key, value)
print(formatted)
# my_var     = 1.23



pantry = [
    ('아보카도', 1.25),
    ('바나나', 2.5),
    ('체리', 12),
]

for i, (item, count) in  enumerate(pantry):
    print('#%d: %-10s = %.2f' % (i, item, count))

# 0: 아보카도       = 1.25
# 1: 바나나        = 2.50
# 2: 체리         = 12.00


for i, (item, count) in  enumerate(pantry):
    print('#%d: %-10s = %.2f' % (i+1, item.title(), round(count)))

#1: 아보카도       = 1.00
#2: 바나나        = 2.00
#3: 체리         = 12.00



template = '%s는 음식을 좋아해. %s가 요리하는 모습을 봐요.'
name = '철수'
formatted = template % (name, name)
print(formatted)
# 철수는 음식을 좋아해. 철수가 요리하는 모습을 봐요.

 

☞ dictionary key는 형식지정자 키와 매칭

key = 'my_car'
value = 1.234

new_way = '%(key)-10s = %(value).2f' % {'key': key, 'value': value}
## 형식지정자에 매칭되는 형식화 식의 위치를 바꿔도 된다.
reordered = '%(key)-10s = %(value).2f' % {'value': value, 'key': key}

print(new_way)
# my_car     = 1.23
print(reordered)
# my_car     = 1.23


template = '%(name)s는 음식을 좋아해. %(name)s가 요리하는 모습을 봐요.'
name = '철수'
after = template % {'name': name}
print(after)
# 철수는 음식을 좋아해. 철수가 요리하는 모습을 봐요.

 

 내장 함수 format과 str.format (파이썬 3부터)

a = 1234.45678
formatted = format(a, ',.2f')  ## ,는 천단위 구분자
print(formatted)
# 1,234.46

b = 'my 문자열'
formatted = format(b, '^20s')  ## ^는 중앙에 값 표시
print('*', formatted, '*')
# *        my 문자열        *

 

 str 타입에 새로 추가된 format() 호출

key = 'my_car'
value = 1.234

formatted = '{} = {}'.format(key, value)
print(formatted)
# my_car = 1.234

formatted = '{1} = {0}'.format(key, value)
print(formatted)
# 1.234 = my_car

formatted = '{:<10} = {:.2f}'.format(key, value)  ## 좌측 정렬 10칸, 소숫점 2
print(formatted)
# my_car     = 1.23

name = '철수'
formatted = '{0}는 음식을 좋아해. {0}가 요리하는 모습을 봐요.'.format(name)
print(formatted)
# 철수는 음식을 좋아해. 철수가 요리하는 모습을 봐요.


pantry = [
    ('아보카도', 1.25),
    ('바나나', 2.5),
    ('체리', 12),
]

for i, (item, count) in  enumerate(pantry):
    print('#{}: {:<10} = {}'.format(i, item, count))

#0: 아보카도       = 1.25
#1: 바나나        = 2.5
#2: 체리         = 12

 

파이썬 문자열 formatting 권장 방법 - 인터폴레이션(interpolation), 일명 f-문자열 (3.6부터)

key = 'my_car'
value = 1.234

formatted = f'{key} = {value}'
print(formatted)
# my_car = 1.234

formatted = f'{key:<10} = {value:.2f}'
print(formatted)
# my_car     = 1.23

formatted = f'{key!r:<10} = {value:.2f}'  ## !r은 값을 유니코드나 repr 문자열로 변환
print(formatted)
# 'my_car'   = 1.23



pantry = [
    ('아보카도', 1.25),
    ('바나나', 2.5),
    ('체리', 12),
]


for i, (item, count) in enumerate(pantry):
    print(f'#{i+1} {item:<10} = {count:.2f}')

#1 아보카도       = 1.25
#2 바나나        = 2.50
#3 체리         = 12.00

for i, (item, count) in enumerate(pantry):
    print(f'#{i+1} '
          f'{item:<10} = '
          f'{count:.2f}')
    
#1 아보카도       = 1.25
#2 바나나        = 2.50
#3 체리         = 12.00

 

☞ 정리

c_tuple = '%-10s = %.2f' % (key, value)
c_dict = '%(k)-10s = %(v).2f' % {'k': key, 'v': value}
str_args = '{:<10} = {:.2f}'.format(key, value)
str_kw = '{k:<10} = {v:.2f}'.format(k=key, v=value)
f_string = f'{key:<10} = {value:.2f}'
print('\n' + c_tuple + '\n' + c_dict + '\n' + str_args + '\n' + str_kw + '\n' + f_string)
# my_car     = 1.23
# my_car     = 1.23
# my_car     = 1.23
# my_car     = 1.23
# my_car     = 1.23

 

 파이썬 식을 형식 지정자 옵션에 넣기

places = 3
number = 1.23456
print(f'내가 고른 숫자는 {number: .{places}f}')  ## places 넣기
# 내가 고른 숫자는  1.235

 

[참고] Effective Python (파이썬 코딩의 기술) 2nd

 

댓글