Chapter 1 파이썬 답게 생각하기
BETTER WAY 1 사용 중인 파이썬의 버전을 알아두라
기억해야 할 내용
- Python3은 현재의 최신 버전이며 가장 활발하게 지원되고 있다.
- Python의 실행 파일이 원하는 버전인지 확인하라.
- Python2는 더이상 공식적인 지원을 하지 않는다.
BETTER WAY 2 PEP 8 스타일 가이드를 따르라
PEP 8 (Python Enhancement Proposal)
- Python 코드를 어떤 형식으로 작성할지 알려주는 스타일 가이드
- 일관된 스타일을 사용해 코드에 더 친숙하게 접근하고, 코드를 더 쉽게 읽을 수 있다.
- doc : python.org/dev/peps/pep-0008
공백 (whitespace) [ Tab, Space, NewLine ]
- 탭 대신 스페이스를 사용해 들여쓰기하라.
- 중요한 들여쓰기에는 4칸 스페이스를 사용하라.
- 라인 길이는 79개 문자 이하여야 한다.
- 각 함수와 클래스 사이에는 빈 줄을 두 줄 넣어라.
- 클래스 안에서 메서드와 메서드 사이에는 빈 줄을 한 줄 넣어라.
- Dictionary에서 키와 콜론 사이에는 공백을 넣지 않는다.
- Dictionary에서 한 줄 안에 키와 값이 같이 넣는 경우에는 콜론 다음에 스페이스를 하나 넣는다.
- 변수 대입에서 = 전후에는 스페이스를 하나씩만 넣는다.
- Type 표기를 덧붙이는 경우에는 변수 이름과 콜론 사이에 공백을 넣지 않도록 주의
- 콜론과 Type 정보 사이에는 스페이스를 하나 넣어라.
명명 규약 ☆☆☆
- 함수, 변수, Attribute는 lowercase_underscore처럼 소문자와 밑줄을 사용한다 (Snake Case)
- (Protected) 보호돼야 하는 인스턴스 Attribute는 일반적인 Attribute 이름 규칙을 따르되, _leading_underscore처럼 밑줄로 시작한다.
- (Private) Private 인스턴스 Attribute는 일반적인 Attribute 이름 규칙을 따르되, __leading_underscore처럼 밑줄 두 개로 시작한다.
- 클래스는 CaptializedWord처럼 여러 단어를 이어 붙이되, 각 단어의 첫 글자를 대문자로 만든다.
- 모듈 수준의 상수는 ALL_CAPS처럼 모든 글자를 대문자로 하고 단어와 단어 사이를 밑줄로 연결한 형태를 사용해야 한다.
- 클래스에 들어있는 인스턴스 메서드는 호출 대상 객체를 가리키는 첫 번째 인자의 이름으로 반드시 self를 사용해야 한다.
- 클래스 메서드는 클래스를 가리키는 첫 번째 인자의 이름으로 반드시 cls를 사용해야 한다.
식과 문 (문제를 해결할 명백한 방법이 하나 있으며, 가급적이면 유일해야 한다.)
- 긍정적인 식을 부정하지 말고 ( if not a is b ) 부정을 내부로 넣어라. ( if a is not b)
- 빈 컨테이너나 시퀀스 ( [] or '' )를 검사할 때는 길이를 0과 비교 (if len(something) == 0)하지 말라.
- 빈 컨테이너나 시퀀스값이 암묵적으로 False로 취급된다는 사실을 활용해 'if not 컨테이너'라는 조건문을 써라.
- 비어 있지 않은 컨테이너나 시퀀스 ([1] or 'hi' 등)를 검사할 때도 길이가 0보다 큰지 비교하지 말라.
- if 컨테이너가 비어 있지 않은 경우 암묵적으로 True로 평가된다는 사실을 활용하라.
- 한 줄짜리 if 문이나 한 줄짜리 for, while 루프, 한 줄짜리 except 복합문을 사용하지 말라. 각 부분을 여러 줄에 나눠 배치하라.
- 식을 한 줄 안에 다 쓸 수 없는 경우, 식을 괄호로 둘러싸고 줄 바꿈과 들여쓰기를 추가해서 읽기 쉽게 만들라.
- 여러 줄에 걸쳐 식을 쓸 때는 줄이 계속된다는 표시를 하는 \ 문자보다는 괄호를 사용하라.
임포트 (import)
- import 문 (from x import y도 포함)을 항상 파일 맨 앞에 위치시켜라.
- 모듈을 임포트할 때는 절대적인 이름을 사용하고, 현 모듈의 경로에 상대적인 이름은 사용하지 말라.
- bar 패키지로부터 foo 모듈을 임포트 한다면 from bar import foo라고 해야 하며, 단지 import foo라고 하면 안 된다.
- 반드시 상대적인 경로로 임포트해야 하는 경우에는 from . import foo처럼 명시적인 구문을 사용하라.
- 임포트를 정의할 때는 표준 라이브러리, 서드 파티, Custom 순서로 섹션을 나눠라. 각 세션은 알파벳 순서로 임포트하라.
Pylint (파이린트)
- 파이썬 소스 코드를 분석해 PEP 8 스타일 가이드를 자동으로 실행해주고, 오류를 감지해준다.
기억해야 할 내용
- Python 코드를 작성할 때는 항상 PEP 8 스타일 가이드를 따르라.
- 큰 Python 커뮤니티와 공통된 스타일을 공유하면 다른 개발자와 협력할 때 도움이 된다.
- 일관성 있는 스타일을 사용하면 나중에 자신이 작성한 코드를 직접 수정할 때도 수월해진다.
BETTER WAY 3 bytes와 str의 차이를 알아두라
bytes
- 부호가 없는 8 byte 데이터가 그대로 들어간다.
- 직접 대응하는 텍스트 인코딩이 존재하지 않는다.str
- 사람이 사용하는 언어의 문자를 표현하는 유니코드 코드 포인트(code point)가 들어 있다.
- 직접 대응하는 이진 인코딩이 존재하지 않는다.
str.encode : 유니코드 데이터를 이진 데이터로 변환
bytes.decode : 이진 데이터를 유니코드 데이터로 변환
repr() : repr메서드를 호출하며, 시스템이 해당 객체를 인식할 수 있는 공식적인 문자열을 출력할 때 사용.
- Str함수와 차이점 : Str으로 변환된 값은 eval의 입력값이 될 수 없는 경우가 존재한다.
일반적인 Default 시스템 인코딩 속성 : UTF-8
Python 프로그램을 작성할 때 유니코드 데이터를 인코딩하거나 디코딩하는 부분을 인터페이스의 가장 먼 지점에 위치시켜라.
- 유니코드 샌드위치
- 프로그램의 핵심 부분은 유니코드 데이터가 들어있는 str을 사용해야 한다.
- 문자 인코딩에 대해 어떠한 가정도 해서는 안 된다.
문자를 표현하는 타입을 어떤 것을 사용해야 할지 고민
- UTF-8(또는 다른 인코딩 방식)로 인코딩된 8bit 시퀀스를 그대로 사용하고 싶다.
- 특정 인코딩을 지정하지 않은 유니코드 문자열을 사용하고 싶다.
8bit 값과 유니코드 문자열을 Python에서 다룰 때 가장 중요한 점
- Bytes와 Str이 똑같이 작동하는 것처럼 보이지만, 각각의 인스턴스는 서로 호환되지 않는다.
- 전달 중인 문자 시퀀스가 어떤 타입인지를 항상 잘 알고 있어야 한다.
- + 연산자를 사용하면 bytes를 bytes에 더하거나 str을 str에 더할 수 있다.
- str 인스턴스를 bytes 인스턴스에 더할 수 없다.
- bytes 인스턴스를 str 인스턴스에 더할 수 없다.
- 이항 연산자를 사용하면 bytes를 bytes와 비교하거나 str을 str과 비교할 수 있다.
- str 인스턴스와 bytes 인스턴스를 비교할 수 없다.
- bytes 인스턴스와 str 인스턴스를 비교할 수 없다.
- 내부에 똑같은 문자들이 들어있더라도 bytes와 str 인스턴스가 같은지 비교하면 항상 False가 나온다.
- % 연산자는 각 타입의 형식화 문자열(format string)에 해당한다.
- Python이 어떤 이진 텍스트 인코딩을 사용할지 알 수 없으므로 str 인스턴스를 bytes 형식화 문자열에 넘길 수 없다.
- str 형식화 문자열에 bytes 인스턴스를 넘길 수는 있지만, 이 경우에는 예상과 다르게 작동한다.
- 파일 핸들과 관련된 연산들이 Default로 유니코드 문자열을 요구하고 이진 Byte 문자열을 요구하지 않는다.
- 이진 파일을 'r' 옵션으로 읽으려고 시도할 때 오류가 발생한다.
- open 함수의 encoding 피라미터를 명시하면 플랫폼에 따라 동작이 달라져 에러가 발생하는 것을 막을 수 있다.
- Default 인코딩이 의심스러운 경우에는 명시적으로 open에 encoding 파라미터를 전달해야 한다.
with open('w') : 텍스트 쓰기 모드, write 연산은 유니코드 데이터가 들어 있는 str 인스턴스를 요구한다.
with open('wb') : 이진 쓰기 모드
with open('r') : 텍스트 읽기 모드, 시스템의 Default 텍스트 인코딩을 bytes.encode를 이용해 이진 데이터를 해석한다.
with open('rb') : 이진 읽기 모드,
기억해야 할 내용
- bytes에는 8bit 값의 시퀀스가 들어 있고, str에는 유니코드 코드 포인트의 시퀀스가 들어 있다.
- 처리할 입력이 원하는 문자 시퀀스(8bit, UTF-8, 유니코드 코드 포인트들) 인지 확실히 하려면 도우미 함수를 사용하라.
- bytes와 str 인스턴스를 (>, ==, +, %와 같은) 연산자에 섞어서 사용할 수 없다.
- 이진 데이터를 파일에서 읽거나 파일에 쓰고 싶으면 항상 이진 모드('rb', 'wb')로 파일을 열어라.
- 유니코드 데이터를 파일에서 읽거나 파일에 쓰고 싶을 때는 Default 인코딩에 주의하라.
- 인코딩 차이로 놀라고 싶지 않으면 open에 encoding 파라미터를 명시적으로 전달하라.
BETTER WAY 4 C 스타일 형식 문자열을 str.format과 쓰기보다는 f-String을 통한 인터폴레이션을 사용하라.
형식화 (formatting) : 미리 정의된 문자열에 데이터값을 끼워 넣어서 사람이 보기 좋은 문자열로 저장하는 과정.
형식 문자열
- 연산자 왼쪽에 있는 값을 끼워 넣을 자리를 표현하기 위해 %d 같은 형식 지정자(format specifer)를 사용한다.
- C언어의 printf에 사용할 수 있는 대부분의 형식 지정자를 지원한다.
형식 문자열 문제점
- 형식화 식에서 오른쪽에 있는 tuple 내 데이터값의 순서를 바꾸거나 값의 타입을 바꾸면 타입 변환이 불가능
- 형식화를 하기 전에 값을 변경해야 한다면 식을 읽기가 매우 어려워진다.
- 형식화 문자열에서 같은 값을 여러 번 사용하고 싶다면 튜플에서 같은 값을 여러 번 반복해야 한다
- 형식화 식에 Dictionary를 사용하면 문장이 번잡스러워진다.
내장 함수 format과 str.format
- format 내장 함수 : 오래된 C 스타일 형식화 문자열보다 더 표현력이 좋은 고급 문자열 형식화 기능
- str.format : %d와 같은 C 스타일 형식화 지정자를 사용하는 대신 위치 지정자 {}를 사용할 수 있다.
인터폴레이션을 통한 형식 문자열
- 표현력을 극대화하고, 형식화 문자열에서 키와 값을 불필요하게 중복 지정해야 하는 경우를 없애준다.
- C 스타일 형식화 문자열에 % 연산자를 사용하거나 str.format 메서드를 사용하는 경우보다 더 짧다.
- 위치 지정자 중괄호 안에 완전한 파이썬 식을 넣을 수 있다.
- 형식 지정자 옵션을 변수로 사용해 하드코딩 하지 않고 깔끔하게 적용할 수 있다.
기억해야 할 내용
- % 연산자를 사용하는 C 스타일 형식화 문자열은 여러 가지 단점과 번잡성이라는 문제가 있다.
- str.format 메서드는 C 스타일 형식 문자열의 문제점을 그대로 가지고 있으므로, 가능하면 str.format 사용을 피해야 한다.
- f-String은 값을 문자열 안에 넣는 새로운 구문으로, C 스타일 형식화 문자열의 가장 큰 문제점을 해결해준다.
- f-String은 간결하지만, 위치 지정자 안에 임의의 Python 식을 직접 포함시킬 수 있으므로 매우 강력하다. ☆
BETTER WAY 5 복잡한 식을 쓰는 대신 도우미 함수를 작성하라
dictionary.get() : dictionary의 Key가 존재하지 않더라도 KeyError를 발생시키지 않는다.
도우미 함수
- 작성한 코드를 복잡한 버전이나, 두 줄짜리 if/else 식 버전보다 명확하게 표현할 수 있다.
- 식이 복잡해지기 시작하면 더 작은 조각으로 나눠서 로직을 도우미 함수로 옮길지 고려해야 한다.
- 짧게 줄여 쓰는 것 보다, 가독성을 좋게 하는것에 가치를 두기 위해 사용한다.
기억해야 할 내용
- Python 문법을 사용하면 복잡하고 읽기 어려운 코드라도 한 줄짜리 식으로 쉽게 작성할 수 있다.
- 복잡한 식을 도우미 함수로 옮겨라. 같은 로직을 반복해 사용할 때는 도우미 함수를 꼭 사용하라.
- Boolean 연산자에 or이나 and를 식에 사용하는 것보다 if/else 식을 쓰는 편이 더 가독성이 좋다.
BETTER WAY 6 인덱스를 사용하는 대신 대입을 사용해 데이터를 언패킹하라
Unpacking(언패킹)
- 한 문장 안에서 여러 값을 대입할 수 있다.
- 튜플 인덱스를 사용하는 것보다 시각적으로 이해하기 쉽다.
- Unpacking을 사용하면 한 줄로 여러 인덱스가 가리키는 원소를 서로 맞바꿀 수 있다.
- Comprehension이나 Generator의 대상인 List의 원소를 Unpacking 할 수 있다. ☆
- List, 함수 인자, 키워드 인자, 다중 반환 값 등에 대한 Unpacking 기능도 제공한다.
기억해야 할 내용
- Python은 한 문장 안에서 여러 값을 대입할 수 있는 Unpacking이라는 특별한 문법을 제공한다.
- Python Unpacking은 일반화되어 있으므로 모든 iterable에 적용할 수 있다.
- Python Unpacking은 iterable이 여러 계층으로 내포된 경우에도 Unpacking을 적용할 수 있다. ☆
- Index를 사용해 Sequence 내부에 접근하는 대신 Unpacking을 사용해 코드를 더 명확하게 만들어라.
BETTER WAY 7 range보다는 enumerate를 사용하라
range
- 정수 집합을 이터레이션하는 루프가 필요할 때 사용한다.
enumerate
- 이터레이터를 lazy generator로 감싼다.
- 루트 인덱스와 이터레이터의 다음 값으로 이뤄진 쌍을 넘겨준다. (yield)
next() : iterator의 다음 원소를 가져온다.
기억해야 할 내용
- enumerate를 사용하면 이터레이터에 대해 루프를 돌면서 가져오는 원소의 인덱스까지 얻는 코드를 간결하게 작성할 수 있다.
- range에 대해 루프를 돌면서 Sequence의 원소를 인덱스로 가져오기보다는 enumerate를 사용하는 것이 효율적이다.
- enumerate의 두 번째 파라미터로 index의 시작 위치를 지정할 수 있다. (Default = 0)
BETTER WAY 8 여러 이터레이터에 대해 나란히 루프를 수행하려면 zip을 사용하라
range( len() ) : 입력받은 인자의 길이만큼 iterator를 생성
zip() 내장 함수
- 둘 이상의 이터레이터를 지연 게산 제너레이터를 사용해 묶어준다.
- 각 이터레이터의 다음 값이 들어 있는 튜플을 반환한다.
- 감싼 이터레이터의 원소를 하나씩 소비하므로 메모리가 소모되어 프로그램이 중단되는 위험이 없다.
- 입력받은 이터레이터의 길이 중 가장 짧은 길이만큼 tuple을 생성한다.
itertools.zip_longest() ☆
- zip과는 다르게 존재하지 않는 값을 자신에게 전달된 fillvalue로 대신한다. (Default = None)
기억해야 할 내용
- zip 내장 함수를 사용해 여러 이터레이터를 나란히 이터레이션할 수 있다.
- zip은 tuple을 지연 계산하는 제너레이터를 만든다. 따라서 무한히 긴 입력에도 zip을 사용할 수 있다.
- 입력 이터레이터의 길이가 서로 다르면 zip은 아무런 경고 없이 가장 짧은 이터레이터의 길이까지만 생성한다.
- itertools.zip_longest는 서로 다른 이터레이터에 대해 루프를 수행하기 위해 사용할 수 있다.
BETTER WAY 9 for나 while 루프 뒤에 else 블록을 사용하지 말라
while & for / else
- 루프 안에서 break 문을 사용하면 else 블록이 실행되지 않는다.
- 빈 Sequence에 대한 루프를 실행하면 else 블록이 실행된다.
- while 루프의 조건이 처음부터 False인 경우 else 블록이 바로 실행된다.
while & for / else 단점
- '루프가 정상적으로 완료되지 않으면 실행하라'라는 뜻이 아니다. ☆
- 도우미 함수를 사용해 표현하는 것 보다 직관적이지 않다.
- 파이썬은 루프와 같은 간단한 구성 요소는 의미가 명확해야 하지만, for / else는 코드를 이해하기 힘들다.
기억해야 할 내용
- 파이썬은 for나 while 루프에 속한 블록 바로 뒤에 else 블록을 허용하는 특별한 문법을 제공한다.
- 루프 뒤에 오는 else 블록은 루프가 반복되고 도중에 break를 만나지 않은 경우에만 실행된다. ☆
- 동작이 직관적이지 않고 혼동을 야기할 수 있으므로 루프 뒤에 else 블록을 사용하지 말라.
BETTER WAY 10 대입식을 사용해 반복을 피하라
assignment expression (대입식)
- 일반 대입문 : a = b, ' a 이퀄(equal) b'
walrus operator (왈러스 연산자) ☆☆
- 왈러스 연산자 : a := b, ' a 왈러스(walrus) b'
- if 문에서는 왈러스 연산자 왼쪽에 있는 식별자에 대입된 값으로 평가한다.
walrus operator (왈러스 연산자) 장점
- 코드를 읽거나 변수 정의를 찾아내기 쉽다.
- if 문의 두 부분으로 나눠서 정의하는 코드의 가독성이 좋아진다.
- 들여쓰기와 내포가 줄어서 가독성이 좋아진다.
- while 루프에서 매번 변수에 대입하고 조건을 검사할 수 있으므로 무한 루프-중간에서 끝내기 관용어의 필요성이 줄어든다.
기억해야 할 내용
- 대입식에서는 왈러스 연산자(:=)를 사용해 변수 이름에 값을 대입하면서 평가 할 수 있고, 중복을 줄일 수 있다.
- 대입식이 더 큰 식의 일부분으로 쓰일 때는 괄호로 둘러싸야 한다.
- 파이썬에선 switch/case, do/while 문을 쓸 수 없지만, 대입식을 사용하면 이런 기능을 더 깔끔하게 흉내 낼 수 있다.
match/case
- Python 3.10 버전에서 추가된 switch/case를 대체하는 문법
'항해99 > 수료 후 필기노트' 카테고리의 다른 글
[Python 코딩의 기술] Chapter 3 함수 (0) | 2021.10.23 |
---|---|
[Python 코딩의 기술] Chapter 2 리스트와 딕셔너리 (0) | 2021.10.16 |
[Javascript 코딩의 기술] Chapter 4 조건문을 깔끔하게 작성하라 (0) | 2021.10.04 |
[Javascript 코딩의 기술] Chapter 3 특수한 컬렉션을 이용해 코드 명료성을 극대화하라 (0) | 2021.10.04 |
[필기노트] Event -Driven, Event Loop, Task Queue (0) | 2021.09.29 |