diff --git a/Google Python Style Guide kor.md b/Google Python Style Guide kor.md index 7983c56..68e036b 100644 --- a/Google Python Style Guide kor.md +++ b/Google Python Style Guide kor.md @@ -23,7 +23,7 @@ * [2.17 함수와 메서드 Decorators](#s2.17-function-and-method-decorators) * [2.18 스레드](#s2.18-threading) * [2.19 강한 기능](#s2.19-power-features) - * [2.20 Modern Python : Python 3 그리고 from, \_\_future\_\_, imports](#s2.20-modern-python) + * [2.20 Modern Python : from, \_\_future\_\_, imports](#s2.20-modern-python) * [2.21 Type 주석](#s2.21-typed-code) - [3. Python 스타일 규칙](#s3) * [3.1 Semicolons](#s3.1-semicolons) @@ -48,7 +48,7 @@ * [3.12 TODO Comments](#s3.12-todo-comments) * [3.13 import 형식](#s3.13-imports-formatting) * [3.14 Statements](#s3.14-statements) - * [3.15 접근 제어](#s3.15-access-control) + * [3.15 접근 제어](#getters-and-setters) * [3.16 네이밍](#s3.16-naming) + [3.16.1 피해야 할 이름](#s3.16.1-names-to-avoid) + [3.16.2 Naming Conventions](#s3.16.2-naming-conventions) @@ -173,11 +173,7 @@ ### 2.2 Imports -- `import`문을 사용할때 package와 module을 대상으로만 사용해야하고 각각의 클래스나 함수에 대해 사용하면 안됩니다. 다만 - [typing 모듈](#s3.19.12-imports), - [typing_extensions module](https://github.com/python/typing/tree/master/typing_extensions), - 그리고 [six.moves module](https://six.readthedocs.io/#module-six.moves) - 을 사용할때는 예외입니다. +- `import`문을 사용할때 package와 module에 사용하고 개별 클래스나 함수에 대해 사용하면 안됩니다. 다만 [typing 모듈](#s3.19.12-imports), [typing_extensions module](https://github.com/python/typing/tree/master/typing_extensions)에서 가져온 클래스 및 [six.moves module](https://six.readthedocs.io/#module-six.moves)에서의 리디렉션은 이 규칙에서 제외됩니다. @@ -216,7 +212,8 @@ - import된것들과 관련있는 이름을 사용하지마세요. - 모듈이 같은 패키지에 있더라도 전체 패키지 이름을 사용하세요. -- 이는 무심코 패키지를 두번 import 하는것을 예방하는 것에 도움이 됩니다. +- 이는 무심코 패키지를 두번 import 하는것을 예방하는 것에 도움이 됩니다. + --- @@ -262,7 +259,7 @@ FLAGS = flags.FLAGS ``` - - 부적절한 예 (이 파일은 `doctor/who/` 에 있다고 가정하고 `jodie.py`또한 존재한다고 가정합니다.) + - 부적절한 예 _(이 파일은 `doctor/who/` 에 있다고 가정하고 `jodie.py`또한 존재한다고 가정합니다.)_ ```python # Unclear what module the author wanted and what will be imported. The actual @@ -356,7 +353,7 @@ - 라이브러리나 패키지는 고유의 예외가 정의되어 있을 것입니다. - 사용하는 동안, 기존에 존재하는 예외 클래스(exception class)로부터 상속을 받아야 합니다. -- 예외 이름은 `Error`로 끝나야 하고 말더듬이(stutter)로 시작하면 안됩니다.(`foo.fooError`). +- 예외 이름은 `Error`로 끝나야 하고 되풀이로 시작하면 안됩니다.(`foo.fooError`). - 예외를 다시 발생시키거나 쓰레드의 가장 바깥 쪽 블록에 있지않으면 절대 포괄적인 `except:`문을 사용하거나 `Exception`, `StandardError`을 사용하지마세요. (그리고 에러메시지를 출력하세요.) Python은 이와 관련해서 매우 관용적이며 `except:` 모든 오탈자를 비롯하여, sys.exit() 호출, Ctrl+C로 인한 인터럽트, 유닛테스트 실패와 마지막으로 당신이 포착을 원하지 않았던 다른 모든 종류의 예외들까지 모두 잡아낼 것입니다. - 코드상에서 `try`/`except` 블록의 수를 최소화시키세요. `try`문의 내부가 커질수록 예외는 당신이 예외가 발생할것이라 예상하지 않았던 코드에 의해 점점 더 발생할 것입니다. 이러한 상황에서, `try`/`except` 블록은 진짜 검출해야 할 에러를 가리게 됩니다. - 예외가 `try` 블록에서 발생하던 안하던 `finally`절은 코드를 실행시킨다. 이건 가끔 깔끔히 하는데 유용합니다. 예를들어, 파일을 닫을 때 가 그 예입니다. @@ -776,80 +773,44 @@ ### 2.13 Properties -- `Properties`을 접근하거나 데이터값을 설정할 때 보통 간단한 방법인 가벼운 접근자나 `setter` 메서드를 사용했을 것입니다. +- `Properties`는 간단한 계산이나 로직이 필요한 attribute을 가져오거나 설정하는 것을 제어하는 데 사용될 수 있습니다. +- `Properties` 구현은 보통의 attribute 접근에 대한 일반적인 기대와 일치되어야 합니다. #### 2.13.1 정의 -- 간단한 계산을 할 때 일반적인 속성을 접근하듯이 속성을 가져오거나 설정하는 메서드 호출을 포장하는 방법입니다. +- 일반적인 속성을 접근하듯이 속성을 가져오거나 설정하는 메서드 호출을 포장하는 방법입니다. #### 2.13.2 장점 -- 간단한 속성 접근에 대해 명시적인 `get`, `set` 메서드 호출을 제거함으로써 가독성이 증가합니다. +- getter, setter method 호출 대신 attribute 접근 및 할당 API를 허용합니다. +- attribute를 읽기 전용으로 만드는 데 사용할 수 있습니다. - [느긋한 계산법](https://ko.wikipedia.org/wiki/느긋한_계산법)을 허용합니다. -- 클래스의 인터페이스를 유지하는 방법으로 [Pythonic](https://github.com/Yosseulsin-JOB/Google-Python-Style-Guide-kor/wiki/2.13-properties#pythonic)을 고려합니다. -- 성능 측면에서, trivial 접근자 메서드는 직접 변수 접근이 합리적일 때 속성 우회를 허용할 필요가 있습니다. 또한, 인터페이스를 파괴하지 않고 미래에 접근자 메서드를 추가할 수 있게 합니다. +- 내부가 class 사용자와 독립적으로 발전할 때 클레스의 public interface를 유지 관리하는 방법을 제공합니다. #### 2.13.3 단점 -- 연산자 오버 로딩(operator overloading)과 같은 부작용을 숨길 수 있습니다. 하위 클래스의 경우 혼란스러울 수 있습니다. +- 연산자 오버 로딩(operator overloading)과 같은 부작용을 숨길 수 있습니다. +- 하위 클래스의 경우 혼란스러울 수 있습니다. #### 2.13.4 결론 -- 새 코드에서 속성을 사용하여 일반적으로 가벼운 접근자 또는 `setter` 메소드를 사용했던 데이터를 접근하거나 설정합니다. -- 속성은 `@property` [decorator](#s2.17-function-and-method-decorators)로 만들어야 합니다. -- 속성 자체가 재정의되지 않은 경우 속성에 대한 상속은 명백하지 않을 수 있습니다. 따라서 하위 클래스에서 재정의 된 메서드가 속성에 의해 호출되도록하려면 접근자 메서드를 간접적으로 호출해야합니다([template method design pattern](https://en.wikipedia.org/wiki/Template_method_pattern)를 사용합니다.). -- 올바른 예 - - ```python - import math - class Square: - """두 가지 속성을 가진 사각형: 쓰기 가능한 면적(area)과 읽기전용인 둘레(perimeter) - - 사용방법: - >>> sq = Square(3) - >>> sq.area - 9 - >>> sq.perimeter - 12 - >>> sq.area = 16 - >>> sq.side - 4 - >>> sq.perimeter - 16 - """ - - def __init__(self, side: float): - self.side = side - - @property - def area(self) -> float: - """사각형의 면적을 가져오거나 설정합니다.""" - return self._get_area() - - @area.setter - def area(self, area: float): - self._set_area(area) - - def _get_area(self) -> float: - """'면적'속성을 계산하기 위한 간접 접근자입니다.""" - return self.side ** 2 - - def _set_area(self, area: float): - """'면적' 속성을 설정하기 위한 간접 설정자입니다.""" - self.side = math.sqrt(area) - - @property - def perimeter(self) -> float: - return self.side * 4 - ``` +- Properties는 허용하지만 연산자 오버로딩과 마찬가지로 필요한 경우에만 사용해야 하며 일반적인 attribute 접근에 대한 기대와 일치해야합니다 + - 그렇지 않은 경우에는 [getters and setters](#getters-and-setters)규칙을 따르세요. +- 예를 들어, 단순히 attribute를 가져오고 설정하기 위해 property를 사용하는 것은 허용되지 않습니다. + - 계산이 발생하지 않으므로 property는 불필요합니다. ([대신 attribute를 public으로 설정합니다.](#getters-and-setters)) +- 이에 비해 attribute 접근을 제어하거나 사소한 파생 값을 계산하기 위해 property를 사용하는 것은 허용됩니다. + - 로직은 간단하고 놀랍지 않습니다. +- Properties는 `@property` [decorator](#s2.17-function-and-method-decorators)를 사용하여 생성해야합니다. +- property descriptor를 수동으로 구현하는 것은 [power feature](#power-features)로 간주됩니다. +- 속성에 대한 상속은 명백하지 않을 수 있습니다. subclass가 재정의하고 확장하기 위한 계산 도구로 properties를 사용하지 마세요. --- @@ -896,9 +857,6 @@ if not users: print('사용자가 없습니다.') - if foo == 0: - self.handle_zero() - if i % 10 == 0: self.handle_multiple_of_ten() @@ -913,9 +871,6 @@ if len(users) == 0: print('사용자가 없습니다.') - if foo is not None and not foo: - self.handle_zero() - if not i % 10: self.handle_multiple_of_ten() @@ -924,6 +879,7 @@ ``` - `'0'`(즉, `0` 문자열)은 참으로 평가한다는 점에 유의해야합니다. +- Numpy 배열은 암시적 boolean 컨텍스트에서 예외를 발생시킬 수 있습니다. `np.array`의 비어 있음을 테스트할 때 `.size` attribute를 선호합니다. (e.g. `if not users.size`) --- @@ -1026,7 +982,9 @@ #### 2.17.3 단점 -- Decorator는 함수의 인자, 반환 값에 대해 임의의 동작을 수행할 수 있으며 결과적으로 놀라운 암묵적 행동을 할 수 있습니다. 게다가, Decorator는 import할 때 실행합니다. 잘못된 Decorator 코드는 회복이 거의 불가능합니다. +- Decorator는 함수의 인자, 반환 값에 대해 임의의 동작을 수행할 수 있으며 결과적으로 놀라운 암묵적 행동을 할 수 있습니다. +- 게다가, Decorator는 object 정의 시 실행합니다. module-level 객체(classes, module functions, ...)의 경우 import할 때 발생합니다. +- Decorator 코드 오류는 복구가 거의 불가능합니다. @@ -1081,28 +1039,30 @@ --- -### 2.20 Modern Python : Python 3 그리고 from, \_\_future\_\_, imports +### 2.20 Modern Python : from, \_\_future\_\_, imports -- Python 3 버전이 나왔습니다! 아직 프로젝트에 Python 3을 사용할 준비가 되어있는 건 아니지만 모든 코드는 호환되도록 작성되어야 합니다. (가능한 경우에 Python 3에 따라 테스트합니다.) +- 새로운 언어 버전 의미 체계 변경 사항은 이전 런타임 내에서 파일 단위로 활성화하기 위해 특별한 향후 가져오기 뒤에 제어될 수 있습니다. + (New language version semantic changes may be gated behind a special future import to enable them on a per-file basis within earlier runtimes.) #### 2.20.1 정의 -- Python 3는 Python언어에서 중요한 변화가 있습니다. 현재 사용하고 있는 코드는 2.7 버전을 염두하여 작성하는 경우가 많습니다. -- Python3에서 수정없이 사용할 수 있도록 잘 준비하기 위해서 코드의 의도를 명확하게 만들 수 있게 하는 몇몇 간단한 것들이 있습니다. +- `from __future__ import`문을 통해 보다 현대적인 기능 중 일부를 활성화할 수 있으면 예상되는 향후 Python 버전의 기능을 조기에 사용할 수 있습니다. #### 2.20.2 장점 -- Python 3를 염두해 두고 작성된 코드는 명확하고 프로젝트의 모든 의존성이 Python 3에서 실행하기가 더 쉬워집니다. +- 이는 호환성을 선언하고 해당 파일 내에서 회귀를 방지하면서 파일별로 변경이 이루어질 수 있으므로 런타임 버전 업그레이드를 더 원활하게 만드는 것으로 입중되었습니다. +- 최신 코드는 향후 런타임 업그레이드 중에 문제가 될 수 있는 기술적 부채가 축적될 가능성이 적기 때문에 유지 관리가 더 쉽습니다. #### 2.20.3 단점 -- 어떤 사람들은 추가된 boilerplate가 추하다고 생각합니다. 사용하지 않는 기능을 import하는 것은 이례적입니다. +- 이러한 코드는 필요한 feature 문을 도입하기 전에는 매우 오래된 인터프리터 버전에서 동작하지 않을 수 있습니다. +- 일반적으로 다양한 환경을 지원해야하는 프로젝트에서 필요합니다. @@ -1110,7 +1070,16 @@ ##### from \_\_future\_\_ imports -- `from __future__ import` 형태를 사용하는 것이 바람직합니다. 모든 새로운 코드는 다음 사항이 포함되어야 하며 가능한 경우 기존 코드가 호환되도록 업데이트 해야 합니다 +- `from __future__ import`문을 사용하는 것이 좋습니다. +- 주어진 소스파일에서 더욱 현대적인 Python 구문 기능을 사용할 수 있습니다. +- `__future__` import 뒤에 기능이 숨겨져 있는 버전에서 더 이상 실행할 필요가 없다면 해당 줄을 자유롭게 제거하세요. +- 3.7 이상이 아닌 3.5 이전 버전에서 실행될 수 있는 코드에서 가져올 경우 + + ```python + from __future__ import generator_stop + ``` + +- 2.7 버전을 계속 지원해야하는 부담이 있는 레거시 코드의 경우 ```python from __future__ import absolute_import @@ -1118,13 +1087,17 @@ from __future__ import print_function ``` -- `import`에 대한 자세한 내용은 [absolute imports](https://www.python.org/dev/peps/pep-0328/), [`/` division behavior](https://www.python.org/dev/peps/pep-0238/), [the `print` function](https://www.python.org/dev/peps/pep-3105/)을 참조하세요. -- 이러한 import는 현재 모듈에서 사용되지 않더라도 생략하거나 제거하지 마세요. 모든 파일에 항상 향후 import가 있으므로 나중에 이러한 기능을 사용하기 시작할 때 편집하는 동안 잊지 않도록 하는 것이 좋습니다. -- 다른 `from __future__` import 명세도 있으니 알맞게 사용하세요. `unicode_literals`는 파이썬 2.7 내 여러 곳에서 도입되는 암묵적 기본 코덱 변환 결과 때문에 명확하지 않기 때문에 권고사항에 포함시키지 않았습니다. 대부분의 코드는 필요에 따라 `b''`, `u''` 바이트를 명시적으로 사용하고 유니코드 문자열 literal를 사용하면 더 좋습니다. +- 자세한 내용은 [Python future statement definitions](https://docs.python.org/3/library/__future__.html) 문서를 읽어보세요. +- 코드가 충분히 현대적인 환경에서만 사용된다는 확신이 들 때까지 이러한 import를 제거하지 마세요. +- 현재 코드에서 특정 향후 import를 통해 활성화되는 기능을 현재 사용하지 않더라도 파일에 해당 기능을 유지하면 나중에 코드가 이전 동작에 따라 실수로 수정되는 것을 방지할 수 있습니다. +- 적절하다고 생각되는 다른 `from __future__` import 문을 사용하세요. +- 2.7버전 내에 여러 위치에서 도입된 암시적 기본 코덱 변환 결과로 인해 확실하지 않았기 때문에 2.7버전에 대한 권장 사항에 `unicode_literals`를 포함하지 않았습니다. +- 대부분의 이중 버전 2-3 코드는 필요한 경우 `b''` 와 `u''` q바트와 유니코드 문자열 리터럴을 명시적으로 사용하는 것이 더 나았습니다. ##### six, future 그리고 past 라이브러리 -- 프로젝트가 Python 2, 3 모두 지원해야하는 경우에 라이브러리를 적합하게 사용하는 것을 권장합니다. 코드를 더 깨끗하고 삶을 더 쉽게 만들기 위해 존재합니다. +- 프로젝트가 여전히 Python 2, 3 모두에서 사용을 지원해야하는 경우 적합하다고 판단되는 대로 [six](https://pypi.org/project/six/), [future](https://pypi.org/project/future/), 및 [past](https://pypi.org/project/past/) 라이브러리를 사용하세요. +- 코드를 더 깨끗하고 삶을 더 쉽게 만들기 위해 존재합니다. --- @@ -1417,6 +1390,10 @@ - `def` 줄 이후에는 빈 줄이 없어야 합니다. - 함수와 메소드 사이에 개발자의 판단하에 적절하게 한 개의 빈 줄을 사용하세요. +- 빈 줄을 정의에 고정할 필요는 없습니다. +- 예를 들어, 함수와 클래스 및 메서드 정의 바로 앞에 있는 관련 주석이 의미가 있을 수 있습니다. +- comment가 Docstring의 일부로 더 유용할 수 있는 지 고려해야합니다. + --- @@ -1620,6 +1597,10 @@ - 반환값의 자료형과 의미를 기록합니다. 만약 함수가 None만을 반환한다면 이 섹션은 필요없습니다. - 또한 만약 docstring이 Returns 나 Yields로 시작하거나(e.g. `"""Returns row from Bigtable as a tuple of strings."""`) 충분한 설명이 제공된다면 생략 될 수 있습니다. +- Tuple 반환 값을 개별 이름이 있는 여러 반환 값인 것처럼 자주 문서화하는 'NumPy style' ([example](http://numpy.org/doc/stable/reference/generated/numpy.linalg.qr.html))을 모방하지 마세요. (Tuple를 언급하지 않습니다.) +- 대신, 다음과 같은 반환값으로 기술하세요. + - "Returns a tuple (mat_a, mat_b), where mat_a is ..., and ...". +- Docstring의 보조 이름은 함수 본문에 사용된 내부 이름과 반드시 일치할 필요는 없습니다. (해당 이름은 API의 일부가 아니기 때문입니다.) @@ -1633,7 +1614,7 @@ def fetch_smalltable_rows(table_handle: smalltable.Table, keys: Sequence[Union[bytes, str]], require_all_keys: bool = False, - ) -> Mapping[bytes, Tuple[str]]: + ) -> Mapping[bytes, Tuple[str, ...]]: """Fetches rows from a Smalltable. Retrieves rows pertaining to the given keys from the Table instance @@ -1643,8 +1624,8 @@ table_handle: An open smalltable.Table instance. keys: A sequence of strings representing the key of each table row to fetch. String keys will be UTF-8 encoded. - require_all_keys: Optional; If require_all_keys is True only - rows with values set for all keys will be returned. + require_all_keys: If True only rows with values set for all keys will be + returned. Returns: A dict mapping keys to the corresponding table row data @@ -1670,7 +1651,7 @@ def fetch_smalltable_rows(table_handle: smalltable.Table, keys: Sequence[Union[bytes, str]], require_all_keys: bool = False, - ) -> Mapping[bytes, Tuple[str]]: + ) -> Mapping[bytes, Tuple[str, ...]]: """Fetches rows from a Smalltable. Retrieves rows pertaining to the given keys from the Table instance @@ -1683,8 +1664,7 @@ A sequence of strings representing the key of each table row to fetch. String keys will be UTF-8 encoded. require_all_keys: - Optional; If require_all_keys is True only rows with values set - for all keys will be returned. + If True only rows with values set for all keys will be returned. Returns: A dict mapping keys to the corresponding table row data @@ -1830,7 +1810,7 @@ if i & (i-1) == 0: # True if i is 0 or a power of 2. ``` - 하나의 파일에는 따옴표를 일관되게 사용하세요. `'` 또는 `"` 중 하나를 선택하고 그것만 사용하세요. -- 다만 `\\` 사용을 피하기 위해 같은 파일이더라도 다른 따옴표를 사용하는 것은 괜찮습니다. `gpylint` 가 이를 검사합니다. +- 다만 backslash-escape 따음표 문자 사용을 피하기 위해 같은 파일이더라도 다른 따옴표를 사용하는 것은 괜찮습니다. - 올바른 예 @@ -2155,15 +2135,19 @@ if i & (i-1) == 0: # True if i is 0 or a power of 2. --- + ### 3.15 접근 제어 -- 만약 접근제어자 함수를 무시할 경우 파이썬에서는 함수에 대해 추가적인 비용을 피하기 위해 접근제어자 함수 대신에 public 변수로 사용해야 합니다. -- 더 많은 기능이 추가된다면 `property`를 사용하여 문법을 일관적으로 유지 할 수 있습니다. - -- 반면에 접근이 복잡하거나 변수의 접근에 대한 비용이 큰 경우, `get_foo()` 와 `set_foo()`와 같은 함수 호출([네이밍](#s3.16-naming) 가이드 라인을 참고하라)을 사용해야 합니다. -- 만약 전에 했던 행동이 property를 통해 접근을 허락했다면 새로운 접근제어자 함수를 property와 묶지마세요. -- 어떤 코드가 여전히 변수에 오래된 메서드를 통해 접근하려 시도한다면 반드시 눈에 보이게 부수어 복잡성의 변화를 인식하게 만들어야 합니다. +- Getter/Setter 함수(접근자 및 변경자라고도함)는 변수 값을 가져오거나 설정하기 위한 의미 있는 역할이나 동작을 제공하는 경우 사용해야 합니다. +- 특히 현재 또는 합리적인 미래에 변수를 가져오거나 설정하는 것이 복잡하거나 비용이 상당할 때 사용해야 합니다. +- 예를 들어 한 쌍의 getter/setter가 단순히 내부 속성을 읽고 쓰는 경우 내부 속성은 대신 공개되어야 합니다. +- 이에 비해 변수를 설정하면 일부 상태가 무효화되거나 다시 작성됨을 의미하는 경우 이는 setter 함수여야 합니다. +- 함수 호출은 잠재적으로 사소하지 않은 작업이 발생하고 있음을 암시합니다. +- 또한 간단한 논리가 필요하거나 더 이상 getter/setter가 필요하지 않도록 리팩토링할 때 [properties](#properties) 옵션이 될 수 있습니다. +- Getter/Setter는 `get_foo()`, `set_foo()`와 같은 [Naming](#s3.16-naming) 지침을 따라야 합니다. +- 이전 동작에서 property을 통한 엑세스가 허용된 경우 새 getter/setter함수를 property에 바인딩하지 마세요. +- 여전히 이전 방법으로 변수에 액세스하려고 시도하는 코드는 눈에 띄게 중단되어 복잡성의 변화를 인식할 수 있습니다. --- @@ -2425,13 +2409,15 @@ if __name__ == '__main__': #### 3.19.3 전방선언 -- 아직 정의되지 않은 동일한 모듈의 클래스 이름을 사용해야 하는 경우(예, 클래스 선언 내에 클래스가 필요한 경우 또는 아래에 정의된 클래스를 사용하는 경우) 클래스 이름을 문자열로 사용하세요. +- 아직 정의되지 않은 동일한 모듈의 클래스 이름을 사용해야 하는 경우(예, 클래스 선언 내에 클래스가 필요한 경우 또는 아래에 정의된 클래스를 사용하는 경우) `from __future__ import annotations`를 사용하세요. +- 간단한 경우에는 주석을 사용하거나 클래스 이름에 문자열을 사용하세요. ```python +from __future__ import annotations + class MyClass: - def __init__(self, - stack: List["MyClass"]) -> None: + def __init__(self, stack: Sequence[MyClass]) -> None: ``` @@ -2583,54 +2569,41 @@ c = (1, "2", 3.5) # type: Tuple[int, str, float] - String 주석에 대한 적절한 Type은 코드의 용도에 따라 달라집니다. -- Python 3 호환 코드일 경우 `str`를 사용하세요. - - - `Text`도 가능합니다. - - 하나를 사용하더라도 일관성을 유지하여 사용해야 합니다. - -- Python 2 호환 코드의 경우 `Text`를 사용하세요. - - - 드믄 경우에 `str`은 적절할 수 있습니다. - - 일반적으로 두 Python 버전 간에 반환 유형이 동일하지 않을 때 호환성을 돕습니다. Python 3에 존재하지 않는 `unicode`를 사용하지 마세요. - -- 이런 불일치가 존재하는 이유는 `str`은 Python 버전에 따라 다른 것을 의미하기 때문입니다. +- `str`을 사용하는 것을 선호하지만 `Text`도 허용됩니다. 둘 중 하나를 일관성 있게 사용하세요. +- 바이너리 데이터를 다루는 코드의 경우 `bytes`를 사용하세요. +- 텍스트 데이터(Python 2에서는 `str` 또는 `unicode`, Python3에서는 `str`)를 처리하는 Python 2 호환 코드의 경우 `Text`를 사용하세요. -- 부적절한 예 - - ```python - def py2_code(x: str) -> unicode: +```python +def deals_with_text_data_in_py3(x: str) -> str: ... - ``` - -- 이진 데이터를 처리하는 경우라면 `bytes`를 사용하세요. - - ```python - def deals_with_binary_data(x: bytes) -> bytes: +def deals_with_binary_data(x: bytes) -> bytes: ... - ``` +def py2_compatible_text_data_processor(x: Text) -> Text: + ... +``` -- Python 2에서 Text 데이터(`str`, `unicode`는 python 2, `str`은 python 3)는 `Text`를 사용합니다. -- Python 3에서만 Text 데이터를 처리하는 경우 `str`를 선택하세요. +- 일부 흔하지 않은 Python2 호환성 사례에서는 `Text` 대신 `str`이 의미가 있을 수 있으며 일반적으로 Python2와 Python3 간에 반환 유형이 동일하지 않을 때 호환성을 돕기 위해 사용됩니다. +- Python3에는 `unicode`가 없으므로 절대 사용하지 마세요. +- 이러한 불일치가 존재하는 이유는 `str`이 Python3와 Python2에서 다른 의미를 갖기 때문입니다. - ```python - from typing import Text - ... - def py2_compatible(x: Text) -> Text: - ... - def py3_only(x: str) -> str: +- 부적절한 예 + +```python +def py2_code(x: str) -> unicode: ... - ``` +``` -- Type이 byte 또는 Text 일 수 있는 경우 적절한 Text Type과 함께 `Union`을 사용하세요. +If the type can be either bytes or text, use `Union`, with the appropriate text +type. - ```python - from typing import Text, Union - ... - def py2_compatible(x: Union[bytes, Text]) -> Union[bytes, Text]: +```python +from typing import Text, Union +... +def py3_only(x: Union[bytes, str]) -> Union[bytes, str]: ... - def py3_only(x: Union[bytes, str]) -> Union[bytes, str]: +def py2_compatible(x: Union[bytes, Text]) -> Union[bytes, Text]: ... - ``` +``` - 함수의 모든 string Type이 항상 동일한 경우(예, 반환 Type이 위의 코드에서 인자 Type과 동일한 경우) [AnyStr](#s3.19.10-type-var)를 사용하세요. diff --git "a/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.13 Properties.md" "b/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.13 Properties.md" index 9664837..c525770 100644 --- "a/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.13 Properties.md" +++ "b/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.13 Properties.md" @@ -2,77 +2,41 @@ ### 2.13 Properties -- `Properties`을 접근하거나 데이터값을 설정할 때 보통 간단한 방법인 가벼운 접근자나 `setter` 메서드를 사용했을 것입니다. +- `Properties`는 간단한 계산이나 로직이 필요한 attribute을 가져오거나 설정하는 것을 제어하는 데 사용될 수 있습니다. +- `Properties` 구현은 보통의 attribute 접근에 대한 일반적인 기대와 일치되어야 합니다. #### 2.13.1 정의 -- 간단한 계산을 할 때 일반적인 속성을 접근하듯이 속성을 가져오거나 설정하는 메서드 호출을 포장하는 방법입니다. +- 일반적인 속성을 접근하듯이 속성을 가져오거나 설정하는 메서드 호출을 포장하는 방법입니다. #### 2.13.2 장점 -- 간단한 속성 접근에 대해 명시적인 `get`, `set` 메서드 호출을 제거함으로써 가독성이 증가합니다. +- getter, setter method 호출 대신 attribute 접근 및 할당 API를 허용합니다. +- attribute를 읽기 전용으로 만드는 데 사용할 수 있습니다. - [느긋한 계산법](https://ko.wikipedia.org/wiki/느긋한_계산법)을 허용합니다. -- 클래스의 인터페이스를 유지하는 방법으로 [Pythonic](https://github.com/Yosseulsin-JOB/Google-Python-Style-Guide-kor/wiki/2.13-properties#pythonic)을 고려합니다. -- 성능 측면에서, trivial 접근자 메서드는 직접 변수 접근이 합리적일 때 속성 우회를 허용할 필요가 있습니다. 또한, 인터페이스를 파괴하지 않고 미래에 접근자 메서드를 추가할 수 있게 합니다. +- 내부가 class 사용자와 독립적으로 발전할 때 클레스의 public interface를 유지 관리하는 방법을 제공합니다. #### 2.13.3 단점 -- 연산자 오버 로딩(operator overloading)과 같은 부작용을 숨길 수 있습니다. 하위 클래스의 경우 혼란스러울 수 있습니다. +- 연산자 오버 로딩(operator overloading)과 같은 부작용을 숨길 수 있습니다. +- 하위 클래스의 경우 혼란스러울 수 있습니다. #### 2.13.4 결론 -- 새 코드에서 속성을 사용하여 일반적으로 가벼운 접근자 또는 `setter` 메소드를 사용했던 데이터를 접근하거나 설정합니다. -- 속성은 `@property` [decorator](#s2.17-function-and-method-decorators)로 만들어야 합니다. -- 속성 자체가 재정의되지 않은 경우 속성에 대한 상속은 명백하지 않을 수 있습니다. 따라서 하위 클래스에서 재정의 된 메서드가 속성에 의해 호출되도록하려면 접근자 메서드를 간접적으로 호출해야합니다([template method design pattern](https://en.wikipedia.org/wiki/Template_method_pattern)를 사용합니다.). -- 올바른 예 - - ```python - import math - class Square: - """두 가지 속성을 가진 사각형: 쓰기 가능한 면적(area)과 읽기전용인 둘레(perimeter) - - 사용방법: - >>> sq = Square(3) - >>> sq.area - 9 - >>> sq.perimeter - 12 - >>> sq.area = 16 - >>> sq.side - 4 - >>> sq.perimeter - 16 - """ - - def __init__(self, side: float): - self.side = side - - @property - def area(self) -> float: - """사각형의 면적을 가져오거나 설정합니다.""" - return self._get_area() - - @area.setter - def area(self, area: float): - self._set_area(area) - - def _get_area(self) -> float: - """'면적'속성을 계산하기 위한 간접 접근자입니다.""" - return self.side ** 2 - - def _set_area(self, area: float): - """'면적' 속성을 설정하기 위한 간접 설정자입니다.""" - self.side = math.sqrt(area) - - @property - def perimeter(self) -> float: - return self.side * 4 - ``` +- Properties는 허용하지만 연산자 오버로딩과 마찬가지로 필요한 경우에만 사용해야 하며 일반적인 attribute 접근에 대한 기대와 일치해야합니다 + - 그렇지 않은 경우에는 [getters and setters](#getters-and-setters)규칙을 따르세요. +- 예를 들어, 단순히 attribute를 가져오고 설정하기 위해 property를 사용하는 것은 허용되지 않습니다. + - 계산이 발생하지 않으므로 property는 불필요합니다. ([대신 attribute를 public으로 설정합니다.](#getters-and-setters)) +- 이에 비해 attribute 접근을 제어하거나 사소한 파생 값을 계산하기 위해 property를 사용하는 것은 허용됩니다. + - 로직은 간단하고 놀랍지 않습니다. +- Properties는 `@property` [decorator](#s2.17-function-and-method-decorators)를 사용하여 생성해야합니다. +- property descriptor를 수동으로 구현하는 것은 [power feature](#power-features)로 간주됩니다. +- 속성에 대한 상속은 명백하지 않을 수 있습니다. subclass가 재정의하고 확장하기 위한 계산 도구로 properties를 사용하지 마세요. diff --git "a/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.14 True, False \355\217\211\352\260\200.md" "b/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.14 True, False \355\217\211\352\260\200.md" index cbd7080..6679926 100644 --- "a/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.14 True, False \355\217\211\352\260\200.md" +++ "b/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.14 True, False \355\217\211\352\260\200.md" @@ -42,9 +42,6 @@ if not users: print('사용자가 없습니다.') - if foo == 0: - self.handle_zero() - if i % 10 == 0: self.handle_multiple_of_ten() @@ -59,9 +56,6 @@ if len(users) == 0: print('사용자가 없습니다.') - if foo is not None and not foo: - self.handle_zero() - if not i % 10: self.handle_multiple_of_ten() @@ -70,3 +64,4 @@ ``` - `'0'`(즉, `0` 문자열)은 참으로 평가한다는 점에 유의해야합니다. +- Numpy 배열은 암시적 boolean 컨텍스트에서 예외를 발생시킬 수 있습니다. `np.array`의 비어 있음을 테스트할 때 `.size` attribute를 선호합니다. (e.g. `if not users.size`) diff --git "a/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.17 \355\225\250\354\210\230\354\231\200 \353\251\224\354\204\234\353\223\234 Decorators.md" "b/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.17 \355\225\250\354\210\230\354\231\200 \353\251\224\354\204\234\353\223\234 Decorators.md" index dbdd0c2..1dd350f 100644 --- "a/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.17 \355\225\250\354\210\230\354\231\200 \353\251\224\354\204\234\353\223\234 Decorators.md" +++ "b/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.17 \355\225\250\354\210\230\354\231\200 \353\251\224\354\204\234\353\223\234 Decorators.md" @@ -39,7 +39,9 @@ #### 2.17.3 단점 -- Decorator는 함수의 인자, 반환 값에 대해 임의의 동작을 수행할 수 있으며 결과적으로 놀라운 암묵적 행동을 할 수 있습니다. 게다가, Decorator는 import할 때 실행합니다. 잘못된 Decorator 코드는 회복이 거의 불가능합니다. +- Decorator는 함수의 인자, 반환 값에 대해 임의의 동작을 수행할 수 있으며 결과적으로 놀라운 암묵적 행동을 할 수 있습니다. +- 게다가, Decorator는 object 정의 시 실행합니다. module-level 객체(classes, module functions, ...)의 경우 import할 때 발생합니다. +- Decorator 코드 오류는 복구가 거의 불가능합니다. diff --git "a/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.2 import.md" "b/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.2 import.md" index 867d44b..540bedb 100644 --- "a/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.2 import.md" +++ "b/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.2 import.md" @@ -2,11 +2,7 @@ ### 2.2 Imports -- `import`문을 사용할때 package와 module을 대상으로만 사용해야하고 각각의 클래스나 함수에 대해 사용하면 안됩니다. 다만 - [typing 모듈](#s3.19.12-imports), - [typing_extensions module](https://github.com/python/typing/tree/master/typing_extensions), - 그리고 [six.moves module](https://six.readthedocs.io/#module-six.moves) - 을 사용할때는 예외입니다. +- `import`문을 사용할때 package와 module에 사용하고 개별 클래스나 함수에 대해 사용하면 안됩니다. 다만 [typing 모듈](#s3.19.12-imports), [typing_extensions module](https://github.com/python/typing/tree/master/typing_extensions)에서 가져온 클래스 및 [six.moves module](https://six.readthedocs.io/#module-six.moves)에서의 리디렉션은 이 규칙에서 제외됩니다. @@ -45,4 +41,4 @@ - import된것들과 관련있는 이름을 사용하지마세요. - 모듈이 같은 패키지에 있더라도 전체 패키지 이름을 사용하세요. -- 이는 무심코 패키지를 두번 import 하는것을 예방하는 것에 도움이 됩니다. \ No newline at end of file +- 이는 무심코 패키지를 두번 import 하는것을 예방하는 것에 도움이 됩니다. diff --git "a/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.20 \355\230\204\353\214\200\354\235\230 \355\214\214\354\235\264\354\215\254.md" "b/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.20 \355\230\204\353\214\200\354\235\230 \355\214\214\354\235\264\354\215\254.md" index 474b872..26c355b 100644 --- "a/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.20 \355\230\204\353\214\200\354\235\230 \355\214\214\354\235\264\354\215\254.md" +++ "b/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.20 \355\230\204\353\214\200\354\235\230 \355\214\214\354\235\264\354\215\254.md" @@ -1,27 +1,29 @@ -### 2.20 Modern Python : Python 3 그리고 from, \_\_future\_\_, imports +### 2.20 Modern Python : from, \_\_future\_\_, imports -- Python 3 버전이 나왔습니다! 아직 프로젝트에 Python 3을 사용할 준비가 되어있는 건 아니지만 모든 코드는 호환되도록 작성되어야 합니다. (가능한 경우에 Python 3에 따라 테스트합니다.) +- 새로운 언어 버전 의미 체계 변경 사항은 이전 런타임 내에서 파일 단위로 활성화하기 위해 특별한 향후 가져오기 뒤에 제어될 수 있습니다. + (New language version semantic changes may be gated behind a special future import to enable them on a per-file basis within earlier runtimes.) #### 2.20.1 정의 -- Python 3는 Python언어에서 중요한 변화가 있습니다. 현재 사용하고 있는 코드는 2.7 버전을 염두하여 작성하는 경우가 많습니다. -- Python3에서 수정없이 사용할 수 있도록 잘 준비하기 위해서 코드의 의도를 명확하게 만들 수 있게 하는 몇몇 간단한 것들이 있습니다. +- `from __future__ import`문을 통해 보다 현대적인 기능 중 일부를 활성화할 수 있으면 예상되는 향후 Python 버전의 기능을 조기에 사용할 수 있습니다. #### 2.20.2 장점 -- Python 3를 염두해 두고 작성된 코드는 명확하고 프로젝트의 모든 의존성이 Python 3에서 실행하기가 더 쉬워집니다. +- 이는 호환성을 선언하고 해당 파일 내에서 회귀를 방지하면서 파일별로 변경이 이루어질 수 있으므로 런타임 버전 업그레이드를 더 원활하게 만드는 것으로 입중되었습니다. +- 최신 코드는 향후 런타임 업그레이드 중에 문제가 될 수 있는 기술적 부채가 축적될 가능성이 적기 때문에 유지 관리가 더 쉽습니다. #### 2.20.3 단점 -- 어떤 사람들은 추가된 boilerplate가 추하다고 생각합니다. 사용하지 않는 기능을 import하는 것은 이례적입니다. +- 이러한 코드는 필요한 feature 문을 도입하기 전에는 매우 오래된 인터프리터 버전에서 동작하지 않을 수 있습니다. +- 일반적으로 다양한 환경을 지원해야하는 프로젝트에서 필요합니다. @@ -29,7 +31,16 @@ ##### from \_\_future\_\_ imports -- `from __future__ import` 형태를 사용하는 것이 바람직합니다. 모든 새로운 코드는 다음 사항이 포함되어야 하며 가능한 경우 기존 코드가 호환되도록 업데이트 해야 합니다 +- `from __future__ import`문을 사용하는 것이 좋습니다. +- 주어진 소스파일에서 더욱 현대적인 Python 구문 기능을 사용할 수 있습니다. +- `__future__` import 뒤에 기능이 숨겨져 있는 버전에서 더 이상 실행할 필요가 없다면 해당 줄을 자유롭게 제거하세요. +- 3.7 이상이 아닌 3.5 이전 버전에서 실행될 수 있는 코드에서 가져올 경우 + + ```python + from __future__ import generator_stop + ``` + +- 2.7 버전을 계속 지원해야하는 부담이 있는 레거시 코드의 경우 ```python from __future__ import absolute_import @@ -37,10 +48,14 @@ from __future__ import print_function ``` -- `import`에 대한 자세한 내용은 [absolute imports](https://www.python.org/dev/peps/pep-0328/), [`/` division behavior](https://www.python.org/dev/peps/pep-0238/), [the `print` function](https://www.python.org/dev/peps/pep-3105/)을 참조하세요. -- 이러한 import는 현재 모듈에서 사용되지 않더라도 생략하거나 제거하지 마세요. 모든 파일에 항상 향후 import가 있으므로 나중에 이러한 기능을 사용하기 시작할 때 편집하는 동안 잊지 않도록 하는 것이 좋습니다. -- 다른 `from __future__` import 명세도 있으니 알맞게 사용하세요. `unicode_literals`는 파이썬 2.7 내 여러 곳에서 도입되는 암묵적 기본 코덱 변환 결과 때문에 명확하지 않기 때문에 권고사항에 포함시키지 않았습니다. 대부분의 코드는 필요에 따라 `b''`, `u''` 바이트를 명시적으로 사용하고 유니코드 문자열 literal를 사용하면 더 좋습니다. +- 자세한 내용은 [Python future statement definitions](https://docs.python.org/3/library/__future__.html) 문서를 읽어보세요. +- 코드가 충분히 현대적인 환경에서만 사용된다는 확신이 들 때까지 이러한 import를 제거하지 마세요. +- 현재 코드에서 특정 향후 import를 통해 활성화되는 기능을 현재 사용하지 않더라도 파일에 해당 기능을 유지하면 나중에 코드가 이전 동작에 따라 실수로 수정되는 것을 방지할 수 있습니다. +- 적절하다고 생각되는 다른 `from __future__` import 문을 사용하세요. +- 2.7버전 내에 여러 위치에서 도입된 암시적 기본 코덱 변환 결과로 인해 확실하지 않았기 때문에 2.7버전에 대한 권장 사항에 `unicode_literals`를 포함하지 않았습니다. +- 대부분의 이중 버전 2-3 코드는 필요한 경우 `b''` 와 `u''` q바트와 유니코드 문자열 리터럴을 명시적으로 사용하는 것이 더 나았습니다. ##### six, future 그리고 past 라이브러리 -- 프로젝트가 Python 2, 3 모두 지원해야하는 경우에 라이브러리를 적합하게 사용하는 것을 권장합니다. 코드를 더 깨끗하고 삶을 더 쉽게 만들기 위해 존재합니다. +- 프로젝트가 여전히 Python 2, 3 모두에서 사용을 지원해야하는 경우 적합하다고 판단되는 대로 [six](https://pypi.org/project/six/), [future](https://pypi.org/project/future/), 및 [past](https://pypi.org/project/past/) 라이브러리를 사용하세요. +- 코드를 더 깨끗하고 삶을 더 쉽게 만들기 위해 존재합니다. diff --git "a/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.3 package.md" "b/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.3 package.md" index 4ccf263..844e3bc 100644 --- "a/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.3 package.md" +++ "b/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.3 package.md" @@ -42,7 +42,7 @@ FLAGS = flags.FLAGS ``` - - 부적절한 예 (이 파일은 `doctor/who/` 에 있다고 가정하고 `jodie.py`또한 존재한다고 가정합니다.) + - 부적절한 예 _(이 파일은 `doctor/who/` 에 있다고 가정하고 `jodie.py`또한 존재한다고 가정합니다.)_ ```python # Unclear what module the author wanted and what will be imported. The actual diff --git "a/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.4 \354\230\210\354\231\270\354\262\230\353\246\254.md" "b/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.4 \354\230\210\354\231\270\354\262\230\353\246\254.md" index 9ba0890..48dbd10 100644 --- "a/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.4 \354\230\210\354\231\270\354\262\230\353\246\254.md" +++ "b/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/2.4 \354\230\210\354\231\270\354\262\230\353\246\254.md" @@ -79,7 +79,7 @@ - 라이브러리나 패키지는 고유의 예외가 정의되어 있을 것입니다. - 사용하는 동안, 기존에 존재하는 예외 클래스(exception class)로부터 상속을 받아야 합니다. -- 예외 이름은 `Error`로 끝나야 하고 말더듬이(stutter)로 시작하면 안됩니다.(`foo.fooError`). +- 예외 이름은 `Error`로 끝나야 하고 되풀이로 시작하면 안됩니다.(`foo.fooError`). - 예외를 다시 발생시키거나 쓰레드의 가장 바깥 쪽 블록에 있지않으면 절대 포괄적인 `except:`문을 사용하거나 `Exception`, `StandardError`을 사용하지마세요. (그리고 에러메시지를 출력하세요.) Python은 이와 관련해서 매우 관용적이며 `except:` 모든 오탈자를 비롯하여, sys.exit() 호출, Ctrl+C로 인한 인터럽트, 유닛테스트 실패와 마지막으로 당신이 포착을 원하지 않았던 다른 모든 종류의 예외들까지 모두 잡아낼 것입니다. - 코드상에서 `try`/`except` 블록의 수를 최소화시키세요. `try`문의 내부가 커질수록 예외는 당신이 예외가 발생할것이라 예상하지 않았던 코드에 의해 점점 더 발생할 것입니다. 이러한 상황에서, `try`/`except` 블록은 진짜 검출해야 할 에러를 가리게 됩니다. - 예외가 `try` 블록에서 발생하던 안하던 `finally`절은 코드를 실행시킨다. 이건 가끔 깔끔히 하는데 유용합니다. 예를들어, 파일을 닫을 때 가 그 예입니다. diff --git "a/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/ReadMe.md" "b/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/ReadMe.md" index 7d80fa8..cedd157 100644 --- "a/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/ReadMe.md" +++ "b/Google Python Style Guide/2. Python \354\226\270\354\226\264 \352\267\234\354\271\231/ReadMe.md" @@ -74,11 +74,7 @@ ### 2.2 Imports -- `import`문을 사용할때 package와 module을 대상으로만 사용해야하고 각각의 클래스나 함수에 대해 사용하면 안됩니다. 다만 - [typing 모듈](#s3.19.12-imports), - [typing_extensions module](https://github.com/python/typing/tree/master/typing_extensions), - 그리고 [six.moves module](https://six.readthedocs.io/#module-six.moves) - 을 사용할때는 예외입니다. +- `import`문을 사용할때 package와 module에 사용하고 개별 클래스나 함수에 대해 사용하면 안됩니다. 다만 [typing 모듈](#s3.19.12-imports), [typing_extensions module](https://github.com/python/typing/tree/master/typing_extensions)에서 가져온 클래스 및 [six.moves module](https://six.readthedocs.io/#module-six.moves)에서의 리디렉션은 이 규칙에서 제외됩니다. @@ -117,7 +113,8 @@ - import된것들과 관련있는 이름을 사용하지마세요. - 모듈이 같은 패키지에 있더라도 전체 패키지 이름을 사용하세요. -- 이는 무심코 패키지를 두번 import 하는것을 예방하는 것에 도움이 됩니다. +- 이는 무심코 패키지를 두번 import 하는것을 예방하는 것에 도움이 됩니다. + --- @@ -163,7 +160,7 @@ FLAGS = flags.FLAGS ``` - - 부적절한 예 (이 파일은 `doctor/who/` 에 있다고 가정하고 `jodie.py`또한 존재한다고 가정합니다.) + - 부적절한 예 _(이 파일은 `doctor/who/` 에 있다고 가정하고 `jodie.py`또한 존재한다고 가정합니다.)_ ```python # Unclear what module the author wanted and what will be imported. The actual @@ -257,7 +254,7 @@ - 라이브러리나 패키지는 고유의 예외가 정의되어 있을 것입니다. - 사용하는 동안, 기존에 존재하는 예외 클래스(exception class)로부터 상속을 받아야 합니다. -- 예외 이름은 `Error`로 끝나야 하고 말더듬이(stutter)로 시작하면 안됩니다.(`foo.fooError`). +- 예외 이름은 `Error`로 끝나야 하고 되풀이로 시작하면 안됩니다.(`foo.fooError`). - 예외를 다시 발생시키거나 쓰레드의 가장 바깥 쪽 블록에 있지않으면 절대 포괄적인 `except:`문을 사용하거나 `Exception`, `StandardError`을 사용하지마세요. (그리고 에러메시지를 출력하세요.) Python은 이와 관련해서 매우 관용적이며 `except:` 모든 오탈자를 비롯하여, sys.exit() 호출, Ctrl+C로 인한 인터럽트, 유닛테스트 실패와 마지막으로 당신이 포착을 원하지 않았던 다른 모든 종류의 예외들까지 모두 잡아낼 것입니다. - 코드상에서 `try`/`except` 블록의 수를 최소화시키세요. `try`문의 내부가 커질수록 예외는 당신이 예외가 발생할것이라 예상하지 않았던 코드에 의해 점점 더 발생할 것입니다. 이러한 상황에서, `try`/`except` 블록은 진짜 검출해야 할 에러를 가리게 됩니다. - 예외가 `try` 블록에서 발생하던 안하던 `finally`절은 코드를 실행시킨다. 이건 가끔 깔끔히 하는데 유용합니다. 예를들어, 파일을 닫을 때 가 그 예입니다. @@ -677,80 +674,44 @@ ### 2.13 Properties -- `Properties`을 접근하거나 데이터값을 설정할 때 보통 간단한 방법인 가벼운 접근자나 `setter` 메서드를 사용했을 것입니다. +- `Properties`는 간단한 계산이나 로직이 필요한 attribute을 가져오거나 설정하는 것을 제어하는 데 사용될 수 있습니다. +- `Properties` 구현은 보통의 attribute 접근에 대한 일반적인 기대와 일치되어야 합니다. #### 2.13.1 정의 -- 간단한 계산을 할 때 일반적인 속성을 접근하듯이 속성을 가져오거나 설정하는 메서드 호출을 포장하는 방법입니다. +- 일반적인 속성을 접근하듯이 속성을 가져오거나 설정하는 메서드 호출을 포장하는 방법입니다. #### 2.13.2 장점 -- 간단한 속성 접근에 대해 명시적인 `get`, `set` 메서드 호출을 제거함으로써 가독성이 증가합니다. +- getter, setter method 호출 대신 attribute 접근 및 할당 API를 허용합니다. +- attribute를 읽기 전용으로 만드는 데 사용할 수 있습니다. - [느긋한 계산법](https://ko.wikipedia.org/wiki/느긋한_계산법)을 허용합니다. -- 클래스의 인터페이스를 유지하는 방법으로 [Pythonic](https://github.com/Yosseulsin-JOB/Google-Python-Style-Guide-kor/wiki/2.13-properties#pythonic)을 고려합니다. -- 성능 측면에서, trivial 접근자 메서드는 직접 변수 접근이 합리적일 때 속성 우회를 허용할 필요가 있습니다. 또한, 인터페이스를 파괴하지 않고 미래에 접근자 메서드를 추가할 수 있게 합니다. +- 내부가 class 사용자와 독립적으로 발전할 때 클레스의 public interface를 유지 관리하는 방법을 제공합니다. #### 2.13.3 단점 -- 연산자 오버 로딩(operator overloading)과 같은 부작용을 숨길 수 있습니다. 하위 클래스의 경우 혼란스러울 수 있습니다. +- 연산자 오버 로딩(operator overloading)과 같은 부작용을 숨길 수 있습니다. +- 하위 클래스의 경우 혼란스러울 수 있습니다. #### 2.13.4 결론 -- 새 코드에서 속성을 사용하여 일반적으로 가벼운 접근자 또는 `setter` 메소드를 사용했던 데이터를 접근하거나 설정합니다. -- 속성은 `@property` [decorator](#s2.17-function-and-method-decorators)로 만들어야 합니다. -- 속성 자체가 재정의되지 않은 경우 속성에 대한 상속은 명백하지 않을 수 있습니다. 따라서 하위 클래스에서 재정의 된 메서드가 속성에 의해 호출되도록하려면 접근자 메서드를 간접적으로 호출해야합니다([template method design pattern](https://en.wikipedia.org/wiki/Template_method_pattern)를 사용합니다.). -- 올바른 예 - - ```python - import math - class Square: - """두 가지 속성을 가진 사각형: 쓰기 가능한 면적(area)과 읽기전용인 둘레(perimeter) - - 사용방법: - >>> sq = Square(3) - >>> sq.area - 9 - >>> sq.perimeter - 12 - >>> sq.area = 16 - >>> sq.side - 4 - >>> sq.perimeter - 16 - """ - - def __init__(self, side: float): - self.side = side - - @property - def area(self) -> float: - """사각형의 면적을 가져오거나 설정합니다.""" - return self._get_area() - - @area.setter - def area(self, area: float): - self._set_area(area) - - def _get_area(self) -> float: - """'면적'속성을 계산하기 위한 간접 접근자입니다.""" - return self.side ** 2 - - def _set_area(self, area: float): - """'면적' 속성을 설정하기 위한 간접 설정자입니다.""" - self.side = math.sqrt(area) - - @property - def perimeter(self) -> float: - return self.side * 4 - ``` +- Properties는 허용하지만 연산자 오버로딩과 마찬가지로 필요한 경우에만 사용해야 하며 일반적인 attribute 접근에 대한 기대와 일치해야합니다 + - 그렇지 않은 경우에는 [getters and setters](#getters-and-setters)규칙을 따르세요. +- 예를 들어, 단순히 attribute를 가져오고 설정하기 위해 property를 사용하는 것은 허용되지 않습니다. + - 계산이 발생하지 않으므로 property는 불필요합니다. ([대신 attribute를 public으로 설정합니다.](#getters-and-setters)) +- 이에 비해 attribute 접근을 제어하거나 사소한 파생 값을 계산하기 위해 property를 사용하는 것은 허용됩니다. + - 로직은 간단하고 놀랍지 않습니다. +- Properties는 `@property` [decorator](#s2.17-function-and-method-decorators)를 사용하여 생성해야합니다. +- property descriptor를 수동으로 구현하는 것은 [power feature](#power-features)로 간주됩니다. +- 속성에 대한 상속은 명백하지 않을 수 있습니다. subclass가 재정의하고 확장하기 위한 계산 도구로 properties를 사용하지 마세요. --- @@ -797,9 +758,6 @@ if not users: print('사용자가 없습니다.') - if foo == 0: - self.handle_zero() - if i % 10 == 0: self.handle_multiple_of_ten() @@ -814,9 +772,6 @@ if len(users) == 0: print('사용자가 없습니다.') - if foo is not None and not foo: - self.handle_zero() - if not i % 10: self.handle_multiple_of_ten() @@ -825,6 +780,7 @@ ``` - `'0'`(즉, `0` 문자열)은 참으로 평가한다는 점에 유의해야합니다. +- Numpy 배열은 암시적 boolean 컨텍스트에서 예외를 발생시킬 수 있습니다. `np.array`의 비어 있음을 테스트할 때 `.size` attribute를 선호합니다. (e.g. `if not users.size`) --- @@ -927,7 +883,9 @@ #### 2.17.3 단점 -- Decorator는 함수의 인자, 반환 값에 대해 임의의 동작을 수행할 수 있으며 결과적으로 놀라운 암묵적 행동을 할 수 있습니다. 게다가, Decorator는 import할 때 실행합니다. 잘못된 Decorator 코드는 회복이 거의 불가능합니다. +- Decorator는 함수의 인자, 반환 값에 대해 임의의 동작을 수행할 수 있으며 결과적으로 놀라운 암묵적 행동을 할 수 있습니다. +- 게다가, Decorator는 object 정의 시 실행합니다. module-level 객체(classes, module functions, ...)의 경우 import할 때 발생합니다. +- Decorator 코드 오류는 복구가 거의 불가능합니다. @@ -982,28 +940,30 @@ --- -### 2.20 Modern Python : Python 3 그리고 from, \_\_future\_\_, imports +### 2.20 Modern Python : from, \_\_future\_\_, imports -- Python 3 버전이 나왔습니다! 아직 프로젝트에 Python 3을 사용할 준비가 되어있는 건 아니지만 모든 코드는 호환되도록 작성되어야 합니다. (가능한 경우에 Python 3에 따라 테스트합니다.) +- 새로운 언어 버전 의미 체계 변경 사항은 이전 런타임 내에서 파일 단위로 활성화하기 위해 특별한 향후 가져오기 뒤에 제어될 수 있습니다. + (New language version semantic changes may be gated behind a special future import to enable them on a per-file basis within earlier runtimes.) #### 2.20.1 정의 -- Python 3는 Python언어에서 중요한 변화가 있습니다. 현재 사용하고 있는 코드는 2.7 버전을 염두하여 작성하는 경우가 많습니다. -- Python3에서 수정없이 사용할 수 있도록 잘 준비하기 위해서 코드의 의도를 명확하게 만들 수 있게 하는 몇몇 간단한 것들이 있습니다. +- `from __future__ import`문을 통해 보다 현대적인 기능 중 일부를 활성화할 수 있으면 예상되는 향후 Python 버전의 기능을 조기에 사용할 수 있습니다. #### 2.20.2 장점 -- Python 3를 염두해 두고 작성된 코드는 명확하고 프로젝트의 모든 의존성이 Python 3에서 실행하기가 더 쉬워집니다. +- 이는 호환성을 선언하고 해당 파일 내에서 회귀를 방지하면서 파일별로 변경이 이루어질 수 있으므로 런타임 버전 업그레이드를 더 원활하게 만드는 것으로 입중되었습니다. +- 최신 코드는 향후 런타임 업그레이드 중에 문제가 될 수 있는 기술적 부채가 축적될 가능성이 적기 때문에 유지 관리가 더 쉽습니다. #### 2.20.3 단점 -- 어떤 사람들은 추가된 boilerplate가 추하다고 생각합니다. 사용하지 않는 기능을 import하는 것은 이례적입니다. +- 이러한 코드는 필요한 feature 문을 도입하기 전에는 매우 오래된 인터프리터 버전에서 동작하지 않을 수 있습니다. +- 일반적으로 다양한 환경을 지원해야하는 프로젝트에서 필요합니다. @@ -1011,7 +971,16 @@ ##### from \_\_future\_\_ imports -- `from __future__ import` 형태를 사용하는 것이 바람직합니다. 모든 새로운 코드는 다음 사항이 포함되어야 하며 가능한 경우 기존 코드가 호환되도록 업데이트 해야 합니다 +- `from __future__ import`문을 사용하는 것이 좋습니다. +- 주어진 소스파일에서 더욱 현대적인 Python 구문 기능을 사용할 수 있습니다. +- `__future__` import 뒤에 기능이 숨겨져 있는 버전에서 더 이상 실행할 필요가 없다면 해당 줄을 자유롭게 제거하세요. +- 3.7 이상이 아닌 3.5 이전 버전에서 실행될 수 있는 코드에서 가져올 경우 + + ```python + from __future__ import generator_stop + ``` + +- 2.7 버전을 계속 지원해야하는 부담이 있는 레거시 코드의 경우 ```python from __future__ import absolute_import @@ -1019,13 +988,17 @@ from __future__ import print_function ``` -- `import`에 대한 자세한 내용은 [absolute imports](https://www.python.org/dev/peps/pep-0328/), [`/` division behavior](https://www.python.org/dev/peps/pep-0238/), [the `print` function](https://www.python.org/dev/peps/pep-3105/)을 참조하세요. -- 이러한 import는 현재 모듈에서 사용되지 않더라도 생략하거나 제거하지 마세요. 모든 파일에 항상 향후 import가 있으므로 나중에 이러한 기능을 사용하기 시작할 때 편집하는 동안 잊지 않도록 하는 것이 좋습니다. -- 다른 `from __future__` import 명세도 있으니 알맞게 사용하세요. `unicode_literals`는 파이썬 2.7 내 여러 곳에서 도입되는 암묵적 기본 코덱 변환 결과 때문에 명확하지 않기 때문에 권고사항에 포함시키지 않았습니다. 대부분의 코드는 필요에 따라 `b''`, `u''` 바이트를 명시적으로 사용하고 유니코드 문자열 literal를 사용하면 더 좋습니다. +- 자세한 내용은 [Python future statement definitions](https://docs.python.org/3/library/__future__.html) 문서를 읽어보세요. +- 코드가 충분히 현대적인 환경에서만 사용된다는 확신이 들 때까지 이러한 import를 제거하지 마세요. +- 현재 코드에서 특정 향후 import를 통해 활성화되는 기능을 현재 사용하지 않더라도 파일에 해당 기능을 유지하면 나중에 코드가 이전 동작에 따라 실수로 수정되는 것을 방지할 수 있습니다. +- 적절하다고 생각되는 다른 `from __future__` import 문을 사용하세요. +- 2.7버전 내에 여러 위치에서 도입된 암시적 기본 코덱 변환 결과로 인해 확실하지 않았기 때문에 2.7버전에 대한 권장 사항에 `unicode_literals`를 포함하지 않았습니다. +- 대부분의 이중 버전 2-3 코드는 필요한 경우 `b''` 와 `u''` q바트와 유니코드 문자열 리터럴을 명시적으로 사용하는 것이 더 나았습니다. ##### six, future 그리고 past 라이브러리 -- 프로젝트가 Python 2, 3 모두 지원해야하는 경우에 라이브러리를 적합하게 사용하는 것을 권장합니다. 코드를 더 깨끗하고 삶을 더 쉽게 만들기 위해 존재합니다. +- 프로젝트가 여전히 Python 2, 3 모두에서 사용을 지원해야하는 경우 적합하다고 판단되는 대로 [six](https://pypi.org/project/six/), [future](https://pypi.org/project/future/), 및 [past](https://pypi.org/project/past/) 라이브러리를 사용하세요. +- 코드를 더 깨끗하고 삶을 더 쉽게 만들기 위해 존재합니다. --- diff --git "a/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.10 \353\254\270\354\236\220\354\227\264.md" "b/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.10 \353\254\270\354\236\220\354\227\264.md" index bc9e1f9..b54023b 100644 --- "a/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.10 \353\254\270\354\236\220\354\227\264.md" +++ "b/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.10 \353\254\270\354\236\220\354\227\264.md" @@ -51,7 +51,7 @@ ``` - 하나의 파일에는 따옴표를 일관되게 사용하세요. `'` 또는 `"` 중 하나를 선택하고 그것만 사용하세요. -- 다만 `\\` 사용을 피하기 위해 같은 파일이더라도 다른 따옴표를 사용하는 것은 괜찮습니다. `gpylint` 가 이를 검사합니다. +- 다만 backslash-escape 따음표 문자 사용을 피하기 위해 같은 파일이더라도 다른 따옴표를 사용하는 것은 괜찮습니다. - 올바른 예 diff --git "a/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.15 \354\240\221\352\267\274 \354\240\234\354\226\264.md" "b/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.15 \354\240\221\352\267\274 \354\240\234\354\226\264.md" index 2020f94..bb0ffae 100644 --- "a/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.15 \354\240\221\352\267\274 \354\240\234\354\226\264.md" +++ "b/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.15 \354\240\221\352\267\274 \354\240\234\354\226\264.md" @@ -1,10 +1,14 @@ + ### 3.15 접근 제어 -- 만약 접근제어자 함수를 무시할 경우 파이썬에서는 함수에 대해 추가적인 비용을 피하기 위해 접근제어자 함수 대신에 public 변수로 사용해야 합니다. -- 더 많은 기능이 추가된다면 `property`를 사용하여 문법을 일관적으로 유지 할 수 있습니다. - -- 반면에 접근이 복잡하거나 변수의 접근에 대한 비용이 큰 경우, `get_foo()` 와 `set_foo()`와 같은 함수 호출([네이밍](#s3.16-naming) 가이드 라인을 참고하라)을 사용해야 합니다. -- 만약 전에 했던 행동이 property를 통해 접근을 허락했다면 새로운 접근제어자 함수를 property와 묶지마세요. -- 어떤 코드가 여전히 변수에 오래된 메서드를 통해 접근하려 시도한다면 반드시 눈에 보이게 부수어 복잡성의 변화를 인식하게 만들어야 합니다. +- Getter/Setter 함수(접근자 및 변경자라고도함)는 변수 값을 가져오거나 설정하기 위한 의미 있는 역할이나 동작을 제공하는 경우 사용해야 합니다. +- 특히 현재 또는 합리적인 미래에 변수를 가져오거나 설정하는 것이 복잡하거나 비용이 상당할 때 사용해야 합니다. +- 예를 들어 한 쌍의 getter/setter가 단순히 내부 속성을 읽고 쓰는 경우 내부 속성은 대신 공개되어야 합니다. +- 이에 비해 변수를 설정하면 일부 상태가 무효화되거나 다시 작성됨을 의미하는 경우 이는 setter 함수여야 합니다. +- 함수 호출은 잠재적으로 사소하지 않은 작업이 발생하고 있음을 암시합니다. +- 또한 간단한 논리가 필요하거나 더 이상 getter/setter가 필요하지 않도록 리팩토링할 때 [properties](#properties) 옵션이 될 수 있습니다. +- Getter/Setter는 `get_foo()`, `set_foo()`와 같은 [Naming](#s3.16-naming) 지침을 따라야 합니다. +- 이전 동작에서 property을 통한 엑세스가 허용된 경우 새 getter/setter함수를 property에 바인딩하지 마세요. +- 여전히 이전 방법으로 변수에 액세스하려고 시도하는 코드는 눈에 띄게 중단되어 복잡성의 변화를 인식할 수 있습니다. diff --git "a/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.19 Type \354\243\274\354\204\235 \353\260\251\353\262\225.md" "b/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.19 Type \354\243\274\354\204\235 \353\260\251\353\262\225.md" index e4bf4a3..2502927 100644 --- "a/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.19 Type \354\243\274\354\204\235 \353\260\251\353\262\225.md" +++ "b/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.19 Type \354\243\274\354\204\235 \353\260\251\353\262\225.md" @@ -111,13 +111,15 @@ #### 3.19.3 전방선언 -- 아직 정의되지 않은 동일한 모듈의 클래스 이름을 사용해야 하는 경우(예, 클래스 선언 내에 클래스가 필요한 경우 또는 아래에 정의된 클래스를 사용하는 경우) 클래스 이름을 문자열로 사용하세요. +- 아직 정의되지 않은 동일한 모듈의 클래스 이름을 사용해야 하는 경우(예, 클래스 선언 내에 클래스가 필요한 경우 또는 아래에 정의된 클래스를 사용하는 경우) `from __future__ import annotations`를 사용하세요. +- 간단한 경우에는 주석을 사용하거나 클래스 이름에 문자열을 사용하세요. ```python +from __future__ import annotations + class MyClass: - def __init__(self, - stack: List["MyClass"]) -> None: + def __init__(self, stack: Sequence[MyClass]) -> None: ``` @@ -269,54 +271,41 @@ c = (1, "2", 3.5) # type: Tuple[int, str, float] - String 주석에 대한 적절한 Type은 코드의 용도에 따라 달라집니다. -- Python 3 호환 코드일 경우 `str`를 사용하세요. - - - `Text`도 가능합니다. - - 하나를 사용하더라도 일관성을 유지하여 사용해야 합니다. - -- Python 2 호환 코드의 경우 `Text`를 사용하세요. - - - 드믄 경우에 `str`은 적절할 수 있습니다. - - 일반적으로 두 Python 버전 간에 반환 유형이 동일하지 않을 때 호환성을 돕습니다. Python 3에 존재하지 않는 `unicode`를 사용하지 마세요. +- `str`을 사용하는 것을 선호하지만 `Text`도 허용됩니다. 둘 중 하나를 일관성 있게 사용하세요. +- 바이너리 데이터를 다루는 코드의 경우 `bytes`를 사용하세요. +- 텍스트 데이터(Python 2에서는 `str` 또는 `unicode`, Python3에서는 `str`)를 처리하는 Python 2 호환 코드의 경우 `Text`를 사용하세요. -- 이런 불일치가 존재하는 이유는 `str`은 Python 버전에 따라 다른 것을 의미하기 때문입니다. - -- 부적절한 예 - - ```python - def py2_code(x: str) -> unicode: +```python +def deals_with_text_data_in_py3(x: str) -> str: ... - ``` - -- 이진 데이터를 처리하는 경우라면 `bytes`를 사용하세요. - - ```python - def deals_with_binary_data(x: bytes) -> bytes: +def deals_with_binary_data(x: bytes) -> bytes: ... - ``` +def py2_compatible_text_data_processor(x: Text) -> Text: + ... +``` -- Python 2에서 Text 데이터(`str`, `unicode`는 python 2, `str`은 python 3)는 `Text`를 사용합니다. -- Python 3에서만 Text 데이터를 처리하는 경우 `str`를 선택하세요. +- 일부 흔하지 않은 Python2 호환성 사례에서는 `Text` 대신 `str`이 의미가 있을 수 있으며 일반적으로 Python2와 Python3 간에 반환 유형이 동일하지 않을 때 호환성을 돕기 위해 사용됩니다. +- Python3에는 `unicode`가 없으므로 절대 사용하지 마세요. +- 이러한 불일치가 존재하는 이유는 `str`이 Python3와 Python2에서 다른 의미를 갖기 때문입니다. - ```python - from typing import Text - ... - def py2_compatible(x: Text) -> Text: - ... - def py3_only(x: str) -> str: +- 부적절한 예 + +```python +def py2_code(x: str) -> unicode: ... - ``` +``` -- Type이 byte 또는 Text 일 수 있는 경우 적절한 Text Type과 함께 `Union`을 사용하세요. +If the type can be either bytes or text, use `Union`, with the appropriate text +type. - ```python - from typing import Text, Union - ... - def py2_compatible(x: Union[bytes, Text]) -> Union[bytes, Text]: +```python +from typing import Text, Union +... +def py3_only(x: Union[bytes, str]) -> Union[bytes, str]: ... - def py3_only(x: Union[bytes, str]) -> Union[bytes, str]: +def py2_compatible(x: Union[bytes, Text]) -> Union[bytes, Text]: ... - ``` +``` - 함수의 모든 string Type이 항상 동일한 경우(예, 반환 Type이 위의 코드에서 인자 Type과 동일한 경우) [AnyStr](#s3.19.10-type-var)를 사용하세요. diff --git "a/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.5 \353\271\210 \354\244\204.md" "b/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.5 \353\271\210 \354\244\204.md" index 8a34c90..7097185 100644 --- "a/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.5 \353\271\210 \354\244\204.md" +++ "b/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.5 \353\271\210 \354\244\204.md" @@ -6,3 +6,7 @@ - 각 메소드 선언 또는 `class` 줄과 젓 번째 메소드 선언 시 그 사이에는 한 개의 빈 줄이 있어야 합니다. - `def` 줄 이후에는 빈 줄이 없어야 합니다. - 함수와 메소드 사이에 개발자의 판단하에 적절하게 한 개의 빈 줄을 사용하세요. + +- 빈 줄을 정의에 고정할 필요는 없습니다. +- 예를 들어, 함수와 클래스 및 메서드 정의 바로 앞에 있는 관련 주석이 의미가 있을 수 있습니다. +- comment가 Docstring의 일부로 더 유용할 수 있는 지 고려해야합니다. diff --git "a/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.8 \354\243\274\354\204\235\352\263\274 docstring.md" "b/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.8 \354\243\274\354\204\235\352\263\274 docstring.md" index c690825..480875d 100644 --- "a/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.8 \354\243\274\354\204\235\352\263\274 docstring.md" +++ "b/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/3.8 \354\243\274\354\204\235\352\263\274 docstring.md" @@ -65,6 +65,10 @@ - 반환값의 자료형과 의미를 기록합니다. 만약 함수가 None만을 반환한다면 이 섹션은 필요없습니다. - 또한 만약 docstring이 Returns 나 Yields로 시작하거나(e.g. `"""Returns row from Bigtable as a tuple of strings."""`) 충분한 설명이 제공된다면 생략 될 수 있습니다. +- Tuple 반환 값을 개별 이름이 있는 여러 반환 값인 것처럼 자주 문서화하는 'NumPy style' ([example](http://numpy.org/doc/stable/reference/generated/numpy.linalg.qr.html))을 모방하지 마세요. (Tuple를 언급하지 않습니다.) +- 대신, 다음과 같은 반환값으로 기술하세요. + - "Returns a tuple (mat_a, mat_b), where mat_a is ..., and ...". +- Docstring의 보조 이름은 함수 본문에 사용된 내부 이름과 반드시 일치할 필요는 없습니다. (해당 이름은 API의 일부가 아니기 때문입니다.) @@ -78,7 +82,7 @@ def fetch_smalltable_rows(table_handle: smalltable.Table, keys: Sequence[Union[bytes, str]], require_all_keys: bool = False, - ) -> Mapping[bytes, Tuple[str]]: + ) -> Mapping[bytes, Tuple[str, ...]]: """Fetches rows from a Smalltable. Retrieves rows pertaining to the given keys from the Table instance @@ -88,8 +92,8 @@ table_handle: An open smalltable.Table instance. keys: A sequence of strings representing the key of each table row to fetch. String keys will be UTF-8 encoded. - require_all_keys: Optional; If require_all_keys is True only - rows with values set for all keys will be returned. + require_all_keys: If True only rows with values set for all keys will be + returned. Returns: A dict mapping keys to the corresponding table row data @@ -115,7 +119,7 @@ def fetch_smalltable_rows(table_handle: smalltable.Table, keys: Sequence[Union[bytes, str]], require_all_keys: bool = False, - ) -> Mapping[bytes, Tuple[str]]: + ) -> Mapping[bytes, Tuple[str, ...]]: """Fetches rows from a Smalltable. Retrieves rows pertaining to the given keys from the Table instance @@ -128,8 +132,7 @@ A sequence of strings representing the key of each table row to fetch. String keys will be UTF-8 encoded. require_all_keys: - Optional; If require_all_keys is True only rows with values set - for all keys will be returned. + If True only rows with values set for all keys will be returned. Returns: A dict mapping keys to the corresponding table row data diff --git "a/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/ReadMe.md" "b/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/ReadMe.md" index 3e9239f..41c38b2 100644 --- "a/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/ReadMe.md" +++ "b/Google Python Style Guide/3. Python \354\212\244\355\203\200\354\235\274 \352\267\234\354\271\231/ReadMe.md" @@ -232,6 +232,10 @@ - `def` 줄 이후에는 빈 줄이 없어야 합니다. - 함수와 메소드 사이에 개발자의 판단하에 적절하게 한 개의 빈 줄을 사용하세요. +- 빈 줄을 정의에 고정할 필요는 없습니다. +- 예를 들어, 함수와 클래스 및 메서드 정의 바로 앞에 있는 관련 주석이 의미가 있을 수 있습니다. +- comment가 Docstring의 일부로 더 유용할 수 있는 지 고려해야합니다. + --- @@ -435,6 +439,10 @@ - 반환값의 자료형과 의미를 기록합니다. 만약 함수가 None만을 반환한다면 이 섹션은 필요없습니다. - 또한 만약 docstring이 Returns 나 Yields로 시작하거나(e.g. `"""Returns row from Bigtable as a tuple of strings."""`) 충분한 설명이 제공된다면 생략 될 수 있습니다. +- Tuple 반환 값을 개별 이름이 있는 여러 반환 값인 것처럼 자주 문서화하는 'NumPy style' ([example](http://numpy.org/doc/stable/reference/generated/numpy.linalg.qr.html))을 모방하지 마세요. (Tuple를 언급하지 않습니다.) +- 대신, 다음과 같은 반환값으로 기술하세요. + - "Returns a tuple (mat_a, mat_b), where mat_a is ..., and ...". +- Docstring의 보조 이름은 함수 본문에 사용된 내부 이름과 반드시 일치할 필요는 없습니다. (해당 이름은 API의 일부가 아니기 때문입니다.) @@ -448,7 +456,7 @@ def fetch_smalltable_rows(table_handle: smalltable.Table, keys: Sequence[Union[bytes, str]], require_all_keys: bool = False, - ) -> Mapping[bytes, Tuple[str]]: + ) -> Mapping[bytes, Tuple[str, ...]]: """Fetches rows from a Smalltable. Retrieves rows pertaining to the given keys from the Table instance @@ -458,8 +466,8 @@ table_handle: An open smalltable.Table instance. keys: A sequence of strings representing the key of each table row to fetch. String keys will be UTF-8 encoded. - require_all_keys: Optional; If require_all_keys is True only - rows with values set for all keys will be returned. + require_all_keys: If True only rows with values set for all keys will be + returned. Returns: A dict mapping keys to the corresponding table row data @@ -485,7 +493,7 @@ def fetch_smalltable_rows(table_handle: smalltable.Table, keys: Sequence[Union[bytes, str]], require_all_keys: bool = False, - ) -> Mapping[bytes, Tuple[str]]: + ) -> Mapping[bytes, Tuple[str, ...]]: """Fetches rows from a Smalltable. Retrieves rows pertaining to the given keys from the Table instance @@ -498,8 +506,7 @@ A sequence of strings representing the key of each table row to fetch. String keys will be UTF-8 encoded. require_all_keys: - Optional; If require_all_keys is True only rows with values set - for all keys will be returned. + If True only rows with values set for all keys will be returned. Returns: A dict mapping keys to the corresponding table row data @@ -645,7 +652,7 @@ if i & (i-1) == 0: # True if i is 0 or a power of 2. ``` - 하나의 파일에는 따옴표를 일관되게 사용하세요. `'` 또는 `"` 중 하나를 선택하고 그것만 사용하세요. -- 다만 `\\` 사용을 피하기 위해 같은 파일이더라도 다른 따옴표를 사용하는 것은 괜찮습니다. `gpylint` 가 이를 검사합니다. +- 다만 backslash-escape 따음표 문자 사용을 피하기 위해 같은 파일이더라도 다른 따옴표를 사용하는 것은 괜찮습니다. - 올바른 예 @@ -970,15 +977,19 @@ if i & (i-1) == 0: # True if i is 0 or a power of 2. --- + ### 3.15 접근 제어 -- 만약 접근제어자 함수를 무시할 경우 파이썬에서는 함수에 대해 추가적인 비용을 피하기 위해 접근제어자 함수 대신에 public 변수로 사용해야 합니다. -- 더 많은 기능이 추가된다면 `property`를 사용하여 문법을 일관적으로 유지 할 수 있습니다. - -- 반면에 접근이 복잡하거나 변수의 접근에 대한 비용이 큰 경우, `get_foo()` 와 `set_foo()`와 같은 함수 호출([네이밍](#s3.16-naming) 가이드 라인을 참고하라)을 사용해야 합니다. -- 만약 전에 했던 행동이 property를 통해 접근을 허락했다면 새로운 접근제어자 함수를 property와 묶지마세요. -- 어떤 코드가 여전히 변수에 오래된 메서드를 통해 접근하려 시도한다면 반드시 눈에 보이게 부수어 복잡성의 변화를 인식하게 만들어야 합니다. +- Getter/Setter 함수(접근자 및 변경자라고도함)는 변수 값을 가져오거나 설정하기 위한 의미 있는 역할이나 동작을 제공하는 경우 사용해야 합니다. +- 특히 현재 또는 합리적인 미래에 변수를 가져오거나 설정하는 것이 복잡하거나 비용이 상당할 때 사용해야 합니다. +- 예를 들어 한 쌍의 getter/setter가 단순히 내부 속성을 읽고 쓰는 경우 내부 속성은 대신 공개되어야 합니다. +- 이에 비해 변수를 설정하면 일부 상태가 무효화되거나 다시 작성됨을 의미하는 경우 이는 setter 함수여야 합니다. +- 함수 호출은 잠재적으로 사소하지 않은 작업이 발생하고 있음을 암시합니다. +- 또한 간단한 논리가 필요하거나 더 이상 getter/setter가 필요하지 않도록 리팩토링할 때 [properties](#properties) 옵션이 될 수 있습니다. +- Getter/Setter는 `get_foo()`, `set_foo()`와 같은 [Naming](#s3.16-naming) 지침을 따라야 합니다. +- 이전 동작에서 property을 통한 엑세스가 허용된 경우 새 getter/setter함수를 property에 바인딩하지 마세요. +- 여전히 이전 방법으로 변수에 액세스하려고 시도하는 코드는 눈에 띄게 중단되어 복잡성의 변화를 인식할 수 있습니다. --- @@ -1240,13 +1251,15 @@ if __name__ == '__main__': #### 3.19.3 전방선언 -- 아직 정의되지 않은 동일한 모듈의 클래스 이름을 사용해야 하는 경우(예, 클래스 선언 내에 클래스가 필요한 경우 또는 아래에 정의된 클래스를 사용하는 경우) 클래스 이름을 문자열로 사용하세요. +- 아직 정의되지 않은 동일한 모듈의 클래스 이름을 사용해야 하는 경우(예, 클래스 선언 내에 클래스가 필요한 경우 또는 아래에 정의된 클래스를 사용하는 경우) `from __future__ import annotations`를 사용하세요. +- 간단한 경우에는 주석을 사용하거나 클래스 이름에 문자열을 사용하세요. ```python +from __future__ import annotations + class MyClass: - def __init__(self, - stack: List["MyClass"]) -> None: + def __init__(self, stack: Sequence[MyClass]) -> None: ``` @@ -1398,54 +1411,41 @@ c = (1, "2", 3.5) # type: Tuple[int, str, float] - String 주석에 대한 적절한 Type은 코드의 용도에 따라 달라집니다. -- Python 3 호환 코드일 경우 `str`를 사용하세요. - - - `Text`도 가능합니다. - - 하나를 사용하더라도 일관성을 유지하여 사용해야 합니다. - -- Python 2 호환 코드의 경우 `Text`를 사용하세요. - - - 드믄 경우에 `str`은 적절할 수 있습니다. - - 일반적으로 두 Python 버전 간에 반환 유형이 동일하지 않을 때 호환성을 돕습니다. Python 3에 존재하지 않는 `unicode`를 사용하지 마세요. - -- 이런 불일치가 존재하는 이유는 `str`은 Python 버전에 따라 다른 것을 의미하기 때문입니다. - -- 부적절한 예 +- `str`을 사용하는 것을 선호하지만 `Text`도 허용됩니다. 둘 중 하나를 일관성 있게 사용하세요. +- 바이너리 데이터를 다루는 코드의 경우 `bytes`를 사용하세요. +- 텍스트 데이터(Python 2에서는 `str` 또는 `unicode`, Python3에서는 `str`)를 처리하는 Python 2 호환 코드의 경우 `Text`를 사용하세요. - ```python - def py2_code(x: str) -> unicode: +```python +def deals_with_text_data_in_py3(x: str) -> str: ... - ``` - -- 이진 데이터를 처리하는 경우라면 `bytes`를 사용하세요. - - ```python - def deals_with_binary_data(x: bytes) -> bytes: +def deals_with_binary_data(x: bytes) -> bytes: ... - ``` +def py2_compatible_text_data_processor(x: Text) -> Text: + ... +``` -- Python 2에서 Text 데이터(`str`, `unicode`는 python 2, `str`은 python 3)는 `Text`를 사용합니다. -- Python 3에서만 Text 데이터를 처리하는 경우 `str`를 선택하세요. +- 일부 흔하지 않은 Python2 호환성 사례에서는 `Text` 대신 `str`이 의미가 있을 수 있으며 일반적으로 Python2와 Python3 간에 반환 유형이 동일하지 않을 때 호환성을 돕기 위해 사용됩니다. +- Python3에는 `unicode`가 없으므로 절대 사용하지 마세요. +- 이러한 불일치가 존재하는 이유는 `str`이 Python3와 Python2에서 다른 의미를 갖기 때문입니다. - ```python - from typing import Text - ... - def py2_compatible(x: Text) -> Text: - ... - def py3_only(x: str) -> str: +- 부적절한 예 + +```python +def py2_code(x: str) -> unicode: ... - ``` +``` -- Type이 byte 또는 Text 일 수 있는 경우 적절한 Text Type과 함께 `Union`을 사용하세요. +If the type can be either bytes or text, use `Union`, with the appropriate text +type. - ```python - from typing import Text, Union - ... - def py2_compatible(x: Union[bytes, Text]) -> Union[bytes, Text]: +```python +from typing import Text, Union +... +def py3_only(x: Union[bytes, str]) -> Union[bytes, str]: ... - def py3_only(x: Union[bytes, str]) -> Union[bytes, str]: +def py2_compatible(x: Union[bytes, Text]) -> Union[bytes, Text]: ... - ``` +``` - 함수의 모든 string Type이 항상 동일한 경우(예, 반환 Type이 위의 코드에서 인자 Type과 동일한 경우) [AnyStr](#s3.19.10-type-var)를 사용하세요. diff --git a/Original.md b/Original.md index 67d38b2..09df969 100644 --- a/Original.md +++ b/Original.md @@ -11,155 +11,77 @@ See README.md for details.
Table of Contents -- [Google Python Style Guide](#google-python-style-guide) - - [1 Background](#1-background) - - [2 Python Language Rules](#2-python-language-rules) - - [2.1 Lint](#21-lint) - - [2.1.1 Definition](#211-definition) - - [2.1.2 Pros](#212-pros) - - [2.1.3 Cons](#213-cons) - - [2.1.4 Decision](#214-decision) - - [2.2 Imports](#22-imports) - - [2.2.1 Definition](#221-definition) - - [2.2.2 Pros](#222-pros) - - [2.2.3 Cons](#223-cons) - - [2.2.4 Decision](#224-decision) - - [2.3 Packages](#23-packages) - - [2.3.1 Pros](#231-pros) - - [2.3.2 Cons](#232-cons) - - [2.3.3 Decision](#233-decision) - - [2.4 Exceptions](#24-exceptions) - - [2.4.1 Definition](#241-definition) - - [2.4.2 Pros](#242-pros) - - [2.4.3 Cons](#243-cons) - - [2.4.4 Decision](#244-decision) - - [2.5 Global variables](#25-global-variables) - - [2.5.1 Definition](#251-definition) - - [2.5.2 Pros](#252-pros) - - [2.5.3 Cons](#253-cons) - - [2.5.4 Decision](#254-decision) - - [2.6 Nested/Local/Inner Classes and Functions](#26-nestedlocalinner-classes-and-functions) - - [2.6.1 Definition](#261-definition) - - [2.6.2 Pros](#262-pros) - - [2.6.3 Cons](#263-cons) - - [2.6.4 Decision](#264-decision) - - [2.7 Comprehensions & Generator Expressions](#27-comprehensions--generator-expressions) - - [2.7.1 Definition](#271-definition) - - [2.7.2 Pros](#272-pros) - - [2.7.3 Cons](#273-cons) - - [2.7.4 Decision](#274-decision) - - [2.8 Default Iterators and Operators](#28-default-iterators-and-operators) - - [2.8.1 Definition](#281-definition) - - [2.8.2 Pros](#282-pros) - - [2.8.3 Cons](#283-cons) - - [2.8.4 Decision](#284-decision) - - [2.9 Generators](#29-generators) - - [2.9 Definition](#29-definition) - - [2.9.2 Pros](#292-pros) - - [2.9.3 Cons](#293-cons) - - [2.9.4 Decision](#294-decision) - - [2.10 Lambda Functions](#210-lambda-functions) - - [2.10.1 Definition](#2101-definition) - - [2.10.2 Pros](#2102-pros) - - [2.10.3 Cons](#2103-cons) - - [2.10.4 Decision](#2104-decision) - - [2.11 Conditional Expressions](#211-conditional-expressions) - - [2.11.1 Definition](#2111-definition) - - [2.11.2 Pros](#2112-pros) - - [2.11.3 Cons](#2113-cons) - - [2.11.4 Decision](#2114-decision) - - [2.12 Default Argument Values](#212-default-argument-values) - - [2.12.1 Definition](#2121-definition) - - [2.12.2 Pros](#2122-pros) - - [2.12.3 Cons](#2123-cons) - - [2.12.4 Decision](#2124-decision) - - [2.13 Properties](#213-properties) - - [2.13.1 Definition](#2131-definition) - - [2.13.2 Pros](#2132-pros) - - [2.13.3 Cons](#2133-cons) - - [2.13.4 Decision](#2134-decision) - - [2.14 True/False Evaluations](#214-truefalse-evaluations) - - [2.14.1 Definition](#2141-definition) - - [2.14.2 Pros](#2142-pros) - - [2.14.3 Cons](#2143-cons) - - [2.14.4 Decision](#2144-decision) - - [2.16 Lexical Scoping](#216-lexical-scoping) - - [2.16.1 Definition](#2161-definition) - - [2.16.2 Pros](#2162-pros) - - [2.16.3 Cons](#2163-cons) - - [2.16.4 Decision](#2164-decision) - - [2.17 Function and Method Decorators](#217-function-and-method-decorators) - - [2.17.1 Definition](#2171-definition) - - [2.17.2 Pros](#2172-pros) - - [2.17.3 Cons](#2173-cons) - - [2.17.4 Decision](#2174-decision) - - [2.18 Threading](#218-threading) - - [2.19 Power Features](#219-power-features) - - [2.19.1 Definition](#2191-definition) - - [2.19.2 Pros](#2192-pros) - - [2.19.3 Cons](#2193-cons) - - [2.19.4 Decision](#2194-decision) - - [2.20 Modern Python: Python 3 and from \_\_future\_\_ imports](#220-modern-python-python-3-and-from-__future__-imports) - - [2.20.1 Definition](#2201-definition) - - [2.20.2 Pros](#2202-pros) - - [2.20.3 Cons](#2203-cons) - - [2.20.4 Decision](#2204-decision) - - [from \_\_future\_\_ imports](#from-__future__-imports) - - [The six, future, and past libraries](#the-six-future-and-past-libraries) - - [2.21 Type Annotated Code](#221-type-annotated-code) - - [2.21.1 Definition](#2211-definition) - - [2.21.2 Pros](#2212-pros) - - [2.21.3 Cons](#2213-cons) - - [2.21.4 Decision](#2214-decision) - - [3 Python Style Rules](#3-python-style-rules) - - [3.1 Semicolons](#31-semicolons) - - [3.2 Line length](#32-line-length) - - [3.3 Parentheses](#33-parentheses) - - [3.4 Indentation](#34-indentation) - - [3.4.1 Trailing commas in sequences of items?](#341-trailing-commas-in-sequences-of-items) - - [3.5 Blank Lines](#35-blank-lines) - - [3.6 Whitespace](#36-whitespace) - - [3.7 Shebang Line](#37-shebang-line) - - [3.8 Comments and Docstrings](#38-comments-and-docstrings) - - [3.8.1 Docstrings](#381-docstrings) - - [3.8.2 Modules](#382-modules) - - [3.8.3 Functions and Methods](#383-functions-and-methods) - - [3.8.4 Classes](#384-classes) - - [3.8.5 Block and Inline Comments](#385-block-and-inline-comments) - - [3.8.6 Punctuation, Spelling, and Grammar](#386-punctuation-spelling-and-grammar) - - [3.10 Strings](#310-strings) - - [3.10.1 Logging](#3101-logging) - - [3.10.2 Error Messages](#3102-error-messages) - - [3.11 Files, Sockets, and similar Stateful Resources](#311-files-sockets-and-similar-stateful-resources) - - [3.12 TODO Comments](#312-todo-comments) - - [3.13 Imports formatting](#313-imports-formatting) - - [3.14 Statements](#314-statements) - - [3.15 Accessors](#315-accessors) - - [3.16 Naming](#316-naming) - - [3.16.1 Names to Avoid](#3161-names-to-avoid) - - [3.16.2 Naming Conventions](#3162-naming-conventions) - - [3.16.3 File Naming](#3163-file-naming) - - [3.16.4 Guidelines derived from Guido's Recommendations](#3164-guidelines-derived-from-guidos-recommendations) - - [3.16.5 Mathematical Notation](#3165-mathematical-notation) - - [3.17 Main](#317-main) - - [3.18 Function length](#318-function-length) - - [3.19 Type Annotations](#319-type-annotations) - - [3.19.1 General Rules](#3191-general-rules) - - [3.19.2 Line Breaking](#3192-line-breaking) - - [3.19.3 Forward Declarations](#3193-forward-declarations) - - [3.19.4 Default Values](#3194-default-values) - - [3.19.5 NoneType](#3195-nonetype) - - [3.19.6 Type Aliases](#3196-type-aliases) - - [3.19.7 Ignoring Types](#3197-ignoring-types) - - [3.19.8 Typing Variables](#3198-typing-variables) - - [3.19.9 Tuples vs Lists](#3199-tuples-vs-lists) - - [3.19.10 TypeVars](#31910-typevars) - - [3.19.11 String types](#31911-string-types) - - [3.19.12 Imports For Typing](#31912-imports-for-typing) - - [3.19.13 Conditional Imports](#31913-conditional-imports) - - [3.19.14 Circular Dependencies](#31914-circular-dependencies) - - [3.19.15 Generics](#31915-generics) - - [4 Parting Words](#4-parting-words) +- [1 Background](#s1-background) +- [2 Python Language Rules](#s2-python-language-rules) + * [2.1 Lint](#s2.1-lint) + * [2.2 Imports](#s2.2-imports) + * [2.3 Packages](#s2.3-packages) + * [2.4 Exceptions](#s2.4-exceptions) + * [2.5 Global variables](#s2.5-global-variables) + * [2.6 Nested/Local/Inner Classes and Functions](#s2.6-nested) + * [2.7 Comprehensions & Generator Expressions](#s2.7-comprehensions) + * [2.8 Default Iterators and Operators](#s2.8-default-iterators-and-operators) + * [2.9 Generators](#s2.9-generators) + * [2.10 Lambda Functions](#s2.10-lambda-functions) + * [2.11 Conditional Expressions](#s2.11-conditional-expressions) + * [2.12 Default Argument Values](#s2.12-default-argument-values) + * [2.13 Properties](#s2.13-properties) + * [2.14 True/False Evaluations](#s2.14-truefalse-evaluations) + * [2.16 Lexical Scoping](#s2.16-lexical-scoping) + * [2.17 Function and Method Decorators](#s2.17-function-and-method-decorators) + * [2.18 Threading](#s2.18-threading) + * [2.19 Power Features](#s2.19-power-features) + * [2.20 Modern Python: from \_\_future\_\_ imports](#s2.20-modern-python) + * [2.21 Type Annotated Code](#s2.21-type-annotated-code) +- [3 Python Style Rules](#s3-python-style-rules) + * [3.1 Semicolons](#s3.1-semicolons) + * [3.2 Line length](#s3.2-line-length) + * [3.3 Parentheses](#s3.3-parentheses) + * [3.4 Indentation](#s3.4-indentation) + + [3.4.1 Trailing commas in sequences of items?](#s3.4.1-trailing-commas) + * [3.5 Blank Lines](#s3.5-blank-lines) + * [3.6 Whitespace](#s3.6-whitespace) + * [3.7 Shebang Line](#s3.7-shebang-line) + * [3.8 Comments and Docstrings](#s3.8-comments-and-docstrings) + + [3.8.1 Docstrings](#s3.8.1-comments-in-doc-strings) + + [3.8.2 Modules](#s3.8.2-comments-in-modules) + + [3.8.3 Functions and Methods](#s3.8.3-functions-and-methods) + + [3.8.4 Classes](#s3.8.4-comments-in-classes) + + [3.8.5 Block and Inline Comments](#s3.8.5-block-and-inline-comments) + + [3.8.6 Punctuation, Spelling, and Grammar](#s3.8.6-punctuation-spelling-and-grammar) + * [3.10 Strings](#s3.10-strings) + + [3.10.1 Logging](#s3.10.1-logging) + + [3.10.2 Error Messages](#s3.10.2-error-messages) + * [3.11 Files, Sockets, and similar Stateful Resources](#s3.11-files-sockets-closeables) + * [3.12 TODO Comments](#s3.12-todo-comments) + * [3.13 Imports formatting](#s3.13-imports-formatting) + * [3.14 Statements](#s3.14-statements) + * [3.15 Accessors](#s3.15-accessors) + * [3.16 Naming](#s3.16-naming) + + [3.16.1 Names to Avoid](#s3.16.1-names-to-avoid) + + [3.16.2 Naming Conventions](#s3.16.2-naming-conventions) + + [3.16.3 File Naming](#s3.16.3-file-naming) + + [3.16.4 Guidelines derived from Guido's Recommendations](#s3.16.4-guidelines-derived-from-guidos-recommendations) + * [3.17 Main](#s3.17-main) + * [3.18 Function length](#s3.18-function-length) + * [3.19 Type Annotations](#s3.19-type-annotations) + + [3.19.1 General Rules](#s3.19.1-general-rules) + + [3.19.2 Line Breaking](#s3.19.2-line-breaking) + + [3.19.3 Forward Declarations](#s3.19.3-forward-declarations) + + [3.19.4 Default Values](#s3.19.4-default-values) + + [3.19.5 NoneType](#s3.19.5-nonetype) + + [3.19.6 Type Aliases](#s3.19.6-type-aliases) + + [3.19.7 Ignoring Types](#s3.19.7-ignoring-types) + + [3.19.8 Typing Variables](#s3.19.8-typing-variables) + + [3.19.9 Tuples vs Lists](#s3.19.9-tuples-vs-lists) + + [3.19.10 TypeVars](#s3.19.10-typevars) + + [3.19.11 String types](#s3.19.11-string-types) + + [3.19.12 Imports For Typing](#s3.19.12-imports-for-typing) + + [3.19.13 Conditional Imports](#s3.19.13-conditional-imports) + + [3.19.14 Circular Dependencies](#s3.19.14-circular-dependencies) + + [3.19.15 Generics](#s3.19.15-generics) + + [3.19.16 Build Dependencies](#s3.19.16-build-dependencies) +- [4 Parting Words](#4-parting-words)
@@ -290,9 +212,10 @@ that the arguments are actually unused. ### 2.2 Imports Use `import` statements for packages and modules only, not for individual -classes or functions. Imports from the [typing module](#typing-imports), +classes or functions. Classes imported from the +[typing module](#typing-imports), [typing_extensions module](https://github.com/python/typing/tree/master/typing_extensions), -and the +and redirects from the [six.moves module](https://six.readthedocs.io/#module-six.moves) are exempt from this rule. @@ -384,31 +307,32 @@ All new code should import each module by its full package name. Imports should be as follows: -Yes: - ```python -# Reference absl.flags in code with the complete name (verbose). -import absl.flags -from doctor.who import jodie +Yes: + # Reference absl.flags in code with the complete name (verbose). + import absl.flags + from doctor.who import jodie -FLAGS = absl.flags.FLAGS + FLAGS = absl.flags.FLAGS ``` ```python -# Reference flags in code with just the module name (common). -from absl import flags -from doctor.who import jodie +Yes: + # Reference flags in code with just the module name (common). + from absl import flags + from doctor.who import jodie -FLAGS = flags.FLAGS + FLAGS = flags.FLAGS ``` -No: _(assume this file lives in `doctor/who/` where `jodie.py` also exists)_ +*(assume this file lives in `doctor/who/` where `jodie.py` also exists)* ```python -# Unclear what module the author wanted and what will be imported. The actual -# import behavior depends on external factors controlling sys.path. -# Which possible jodie module did the author intend to import? -import jodie +No: + # Unclear what module the author wanted and what will be imported. The actual + # import behavior depends on external factors controlling sys.path. + # Which possible jodie module did the author intend to import? + import jodie ``` The directory the main binary is located in should not be assumed to be in @@ -517,9 +441,10 @@ Exceptions must follow certain conditions: return port ``` + - Libraries or packages may define their own exceptions. When doing so they must inherit from an existing exception class. Exception names should end in - `Error` and should not introduce stutter (`foo.FooError`). + `Error` and should not introduce repetition (`foo.FooError`). - Never use catch-all `except:` statements, or catch `Exception` or `StandardError`, unless you are @@ -1046,8 +971,10 @@ No: def foo(a, b: Mapping = {}): # Could still get passed to unchecked code ### 2.13 Properties -Use properties for accessing or setting data where you would normally have used -simple, lightweight accessor or setter methods. +Properties may be used to control getting or setting attributes that require +trivial computations or logic. Property implementations must match the general +expectations of regular attribute access: that they are cheap, straightforward, +and unsurprising. @@ -1056,7 +983,7 @@ simple, lightweight accessor or setter methods. #### 2.13.1 Definition A way to wrap method calls for getting and setting an attribute as a standard -attribute access when the computation is lightweight. +attribute access. @@ -1064,12 +991,12 @@ attribute access when the computation is lightweight. #### 2.13.2 Pros -Readability is increased by eliminating explicit get and set method calls for -simple attribute access. Allows calculations to be lazy. Considered the Pythonic -way to maintain the interface of a class. In terms of performance, allowing -properties bypasses needing trivial accessor methods when a direct variable -access is reasonable. This also allows accessor methods to be added in the -future without breaking the interface. +* Allows for an attribute access and assignment API rather than + [getter and setter](#getters-and-setters) method calls. +* Can be used to make an attribute read-only. +* Allows calculations to be lazy. +* Provides a way to maintain the public interface of a class when the + internals evolve independently of class users. @@ -1077,8 +1004,8 @@ future without breaking the interface. #### 2.13.3 Cons -Can hide side-effects much like operator overloading. Can be confusing for -subclasses. +* Can hide side-effects much like operator overloading. +* Can be confusing for subclasses. @@ -1086,58 +1013,22 @@ subclasses. #### 2.13.4 Decision -Use properties in new code to access or set data where you would normally have -used lightweight accessor or setter methods. Properties should be created with -the `@property` [decorator](#s2.17-function-and-method-decorators). - -Inheritance with properties can be non-obvious if the property itself is not -overridden. Thus one must make sure that accessor methods are called indirectly -to ensure methods overridden in subclasses are called by the property (using the -[template method design pattern](https://en.wikipedia.org/wiki/Template_method_pattern)). - -```python -Yes: import math - - class Square: - """A square with two properties: a writable area and a read-only perimeter. - - To use: - >>> sq = Square(3) - >>> sq.area - 9 - >>> sq.perimeter - 12 - >>> sq.area = 16 - >>> sq.side - 4 - >>> sq.perimeter - 16 - """ - - def __init__(self, side: float): - self.side = side +Properties are allowed, but, like operator overloading, should only be used when +necessary and match the expectations of typical attribute access; follow the +[getters and setters](#getters-and-setters) rules otherwise. - @property - def area(self) -> float: - """Area of the square.""" - return self._get_area() +For example, using a property to simply both get and set an internal attribute +isn't allowed: there is no computation occurring, so the property is unnecessary +([make the attribute public instead](#getters-and-setters)). In comparison, +using a property to control attribute access or to calculate a *trivially* +derived value is allowed: the logic is simple and unsurprising. - @area.setter - def area(self, area: float): - self._set_area(area) +Properties should be created with the `@property` +[decorator](#s2.17-function-and-method-decorators). Manually implementing a +property descriptor is considered a [power feature](#power-features). - def _get_area(self) -> float: - """Indirect accessor to calculate the 'area' property.""" - return self.side ** 2 - - def _set_area(self, area: float): - """Indirect setter to set the 'area' property.""" - self.side = math.sqrt(area) - - @property - def perimeter(self) -> float: - return self.side * 4 -``` +Inheritance with properties can be non-obvious. Do not use properties to +implement computations a subclass may ever want to override and extend. @@ -1205,9 +1096,6 @@ Use the "implicit" false if possible, e.g., `if foo:` rather than `if foo != Yes: if not users: print('no users') - if foo == 0: - self.handle_zero() - if i % 10 == 0: self.handle_multiple_of_ten() @@ -1220,9 +1108,6 @@ Use the "implicit" false if possible, e.g., `if foo:` rather than `if foo != No: if len(users) == 0: print('no users') - if foo is not None and not foo: - self.handle_zero() - if not i % 10: self.handle_multiple_of_ten() @@ -1232,6 +1117,10 @@ Use the "implicit" false if possible, e.g., `if foo:` rather than `if foo != - Note that `'0'` (i.e., `0` as string) evaluates to true. +- Note that Numpy arrays may raise an exception in an implicit boolean + context. Prefer the `.size` attribute when testing emptiness of a `np.array` + (e.g. `if not users.size`). + @@ -1361,8 +1250,9 @@ eliminate some repetitive code, enforce invariants, etc. Decorators can perform arbitrary operations on a function's arguments or return values, resulting in surprising implicit behavior. Additionally, decorators -execute at import time. Failures in decorator code are pretty much impossible to -recover from. +execute at object definition time. For module-level objects (classes, module +functions, ...) this happens at import time. Failures in decorator code are +pretty much impossible to recover from. @@ -1464,11 +1354,10 @@ to use (for example, `abc.ABCMeta`, `dataclasses`, and `enum`). -### 2.20 Modern Python: Python 3 and from \_\_future\_\_ imports +### 2.20 Modern Python: from \_\_future\_\_ imports -Python 3 is here! While not every project is ready to use it yet, -all code should be written to be 3 compatible (and tested under 3 when -possible). +New language version semantic changes may be gated behind a special future +import to enable them on a per-file basis within earlier runtimes. @@ -1476,10 +1365,9 @@ possible). #### 2.20.1 Definition -Python 3 is a significant change in the Python language. While existing code is -often written with 2.7 in mind, there are some simple things to do to make code -more explicit about its intentions and thus better prepared for use under Python -3 without modification. +Being able to turn on some of the more modern features via `from __future__ +import` statements allows early use of features from expected future Python +versions. @@ -1487,8 +1375,11 @@ more explicit about its intentions and thus better prepared for use under Python #### 2.20.2 Pros -Code written with Python 3 in mind is more explicit and easier to get running -under Python 3 once all of the dependencies of your project are ready. +This has proven to make runtime version upgrades smoother as changes can be made +on a per-file basis while declaring compatibility and preventing regressions +within those files. Modern code is more maintainable as it is less likely to +accumulate technical debt that will be problematic during future runtime +upgrades. @@ -1496,9 +1387,9 @@ under Python 3 once all of the dependencies of your project are ready. #### 2.20.3 Cons -Some people find the additional boilerplate to be ugly. It's unusual to add -imports to a module that doesn't actually require the features added by the -import. +Such code may not work on very old interpreter versions prior to the +introduction of the needed future statement. The need for this is more common in +projects supporting an extremely wide variety of environments. @@ -1508,9 +1399,18 @@ import. ##### from \_\_future\_\_ imports -Use of `from __future__ import` statements is encouraged. All new code should -contain the following and existing code should be updated to be compatible when -possible: +Use of `from __future__ import` statements is encouraged. It allows a given +source file to start using more modern Python syntax features today. Once you no +longer need to run on a version where the features are hidden behind a +`__future__` import, feel free to remove those lines. + +In code that may execute on versions as old as 3.5 rather than >= 3.7, import: + +```python +from __future__ import generator_stop +``` + +For legacy code with the burden of continuing to support 2.7, import: ```python from __future__ import absolute_import @@ -1518,27 +1418,26 @@ from __future__ import division from __future__ import print_function ``` -For more information on these imports, see -[absolute imports](https://www.python.org/dev/peps/pep-0328/), -[`/` division behavior](https://www.python.org/dev/peps/pep-0238/), and -[the `print` function](https://www.python.org/dev/peps/pep-3105/). - +For more information read the +[Python future statement definitions](https://docs.python.org/3/library/__future__.html) +documentation. -Please don't omit or remove these imports, even if they're not currently used in -the module, unless the code is Python 3 only. It is better to always have the -future imports in all files so that they are not forgotten during later edits -when someone starts using such a feature. +Please don't remove these imports until you are confident the code is only ever +used in a sufficiently modern environment. Even if you do not currently use the +feature a specific future import enables in your code today, keeping it in place +in the file prevents later modifications of the code from inadvertently +depending on the older behavior. -There are other `from __future__` import statements. Use them as you see fit. We -do not include `unicode_literals` in our recommendations as it is not a clear -win due to implicit default codec conversion consequences it introduces in many -places within Python 2.7. Most code is better off with explicit use of `b''` and -`u''` bytes and unicode string literals as necessary. +Use other `from __future__` import statements as you see fit. We did not include +`unicode_literals` in our recommendations for 2.7 as it was not a clear win due +to implicit default codec conversion consequences it introduced in many places +within 2.7. Most dual-version 2-and-3 code was better off with explicit use of +`b''` and `u''` bytes and unicode string literals where necessary. ##### The six, future, and past libraries -When your project needs to actively support use under both Python 2 and 3, use -the [six](https://pypi.org/project/six/), +When your project still needs to support use under both Python 2 and 3, use the +[six](https://pypi.org/project/six/), [future](https://pypi.org/project/future/), and [past](https://pypi.org/project/past/) libraries as you see fit. They exist to make your code cleaner and life easier. @@ -1874,6 +1773,10 @@ definitions. One blank line between method definitions and between the `class` line and the first method. No blank line following a `def` line. Use single blank lines as you judge appropriate within functions or methods. +Blank lines need not be anchored to the definition. For example, related +comments immediately preceding function, class, and method definitions can make +sense. Consider if your comment might be more useful as part of the docstring. + @@ -1943,7 +1846,7 @@ No: x<1 Never use spaces around `=` when passing keyword arguments or defining a default parameter value, with one exception: -[when a type annotation is present](#typing-default-values), _do_ use spaces +[when a type annotation is present](#typing-default-values), *do* use spaces around the `=` for the default parameter value. ```python @@ -2013,7 +1916,7 @@ inline comments. #### 3.8.1 Docstrings -Python uses _docstrings_ to document code. A docstring is a string that is the +Python uses *docstrings* to document code. A docstring is a string that is the first statement in a package, module, class or function. These strings can be extracted automatically through the `__doc__` member of the object and are used by `pydoc`. @@ -2119,7 +2022,14 @@ aptly described using a one-line docstring. returns None, this section is not required. It may also be omitted if the docstring starts with Returns or Yields (e.g. `"""Returns row from Bigtable as a tuple of strings."""`) and the opening sentence is sufficient to - describe return value. + describe the return value. Do not imitate 'NumPy style' + ([example](http://numpy.org/doc/stable/reference/generated/numpy.linalg.qr.html)), + which frequently documents a tuple return value as if it were multiple + return values with individual names (never mentioning the tuple). Instead, + describe such a return value as: "Returns a tuple (mat_a, mat_b), where + mat_a is ..., and ...". The auxiliary names in the docstring need not + necessarily correspond to any internal names used in the function body (as + those are not part of the API). [*Raises:*](#doc-function-raises) @@ -2134,7 +2044,7 @@ aptly described using a one-line docstring. def fetch_smalltable_rows(table_handle: smalltable.Table, keys: Sequence[Union[bytes, str]], require_all_keys: bool = False, -) -> Mapping[bytes, Tuple[str]]: +) -> Mapping[bytes, Tuple[str, ...]]: """Fetches rows from a Smalltable. Retrieves rows pertaining to the given keys from the Table instance @@ -2144,8 +2054,8 @@ def fetch_smalltable_rows(table_handle: smalltable.Table, table_handle: An open smalltable.Table instance. keys: A sequence of strings representing the key of each table row to fetch. String keys will be UTF-8 encoded. - require_all_keys: Optional; If require_all_keys is True only - rows with values set for all keys will be returned. + require_all_keys: If True only rows with values set for all keys will be + returned. Returns: A dict mapping keys to the corresponding table row data @@ -2171,7 +2081,7 @@ Similarly, this variation on `Args:` with a line break is also allowed: def fetch_smalltable_rows(table_handle: smalltable.Table, keys: Sequence[Union[bytes, str]], require_all_keys: bool = False, -) -> Mapping[bytes, Tuple[str]]: +) -> Mapping[bytes, Tuple[str, ...]]: """Fetches rows from a Smalltable. Retrieves rows pertaining to the given keys from the Table instance @@ -2184,8 +2094,7 @@ def fetch_smalltable_rows(table_handle: smalltable.Table, A sequence of strings representing the key of each table row to fetch. String keys will be UTF-8 encoded. require_all_keys: - Optional; If require_all_keys is True only rows with values set - for all keys will be returned. + If True only rows with values set for all keys will be returned. Returns: A dict mapping keys to the corresponding table row data @@ -2352,7 +2261,7 @@ No: employee_table = '' Be consistent with your choice of string quote character within a file. Pick `'` or `"` and stick with it. It is okay to use the other quote character on a -string to avoid the need to `\\ ` escape within the string. +string to avoid the need to backslash-escape quote characters within the string. ```python Yes: @@ -2747,22 +2656,33 @@ No: - -### 3.15 Accessors -If an accessor function would be trivial, you should use public variables -instead of accessor functions to avoid the extra cost of function calls in -Python. When more functionality is added you can use `property` to keep the -syntax consistent. + +### 3.15 Getters and Setters + +Getter and setter functions (also called accessors and mutators) should be used +when they provide a meaningful role or behavior for getting or setting a +variable's value. + +In particular, they should be used when getting or setting the variable is +complex or the cost is significant, either currently or in a reasonable future. + +If, for example, a pair of getters/setters simply read and write an internal +attribute, the internal attribute should be made public instead. By comparison, +if setting a variable means some state is invalidated or rebuilt, it should be a +setter function. The function invocation hints that a potentially non-trivial +operation is occurring. Alternatively, [properties](#properties) may be an +option when simple logic is needed, or refactoring to no longer need getters and +setters. -On the other hand, if access is more complex, or the cost of accessing the -variable is significant, you should use function calls (following the -[Naming](#s3.16-naming) guidelines) such as `get_foo()` and `set_foo()`. If the -past behavior allowed access through a property, do not bind the new accessor -functions to the property. Any code still attempting to access the variable by -the old method should break visibly so they are made aware of the change in -complexity. +Getters and setters should follow the [Naming](#s3.16-naming) guidelines, such +as `get_foo()` and `set_foo()`. + +If the past behavior allowed access through a property, do not bind the new +getter/setter functions to the property. Any code still attempting to access the +variable by the old method should break visibly so they are made aware of the +change in complexity. @@ -3144,13 +3064,15 @@ def my_function( If you need to use a class name from the same module that is not yet defined -- for example, if you need the class inside the class declaration, or if you use a -class that is defined below -- use a string for the class name. +class that is defined below -- either use `from __future__ import annotations` +for simple cases or use a string for the class name. ```python +from __future__ import annotations + class MyClass: - def __init__(self, - stack: List["MyClass"]) -> None: + def __init__(self, stack: Sequence[MyClass]) -> None: ``` @@ -3161,7 +3083,7 @@ class MyClass: As per [PEP-008](https://www.python.org/dev/peps/pep-0008/#other-recommendations), use -spaces around the `=` _only_ for arguments that have both a type annotation and +spaces around the `=` *only* for arguments that have both a type annotation and a default value. ```python @@ -3342,40 +3264,30 @@ def check_length(x: AnyStr) -> AnyStr: The proper type for annotating strings depends on what versions of Python the code is intended for. -For Python 3 only code, prefer to use `str`. `Text` is also acceptable. Be -consistent in using one or the other. - -For Python 2 compatible code, use `Text`. In some rare cases, `str` may make -sense; typically to aid compatibility when the return types aren't the same -between the two Python versions. Avoid using `unicode`: it doesn't exist in -Python 3. - -The reason this discrepancy exists is because `str` means different things -depending on the Python version. +Prefer to use `str`, though `Text` is also acceptable. Be consistent in using +one or the other. For code that deals with binary data, use `bytes`. For Python +2 compatible code that processes text data (`str` or `unicode` in Python 2, +`str` in Python 3), use `Text`. ```python -No: -def py2_code(x: str) -> unicode: +def deals_with_text_data_in_py3(x: str) -> str: ... -``` - -For code that deals with binary data, use `bytes`. - -```python def deals_with_binary_data(x: bytes) -> bytes: ... +def py2_compatible_text_data_processor(x: Text) -> Text: + ... ``` -For Python 2 compatible code that processes text data (`str` or `unicode` in -Python 2, `str` in Python 3), use `Text`. For Python 3 only code that process -text data, prefer `str`. +In some uncommon Python 2 compatibility cases, `str` may make sense instead of +`Text`, typically to aid compatibility when the return types aren't the same +between Python 2 and Python 3. Never use `unicode` as it doesn't exist in Python +3. The reason this discrepancy exists is because `str` means something different +in Python 2 than in Python 3. + +No: ```python -from typing import Text -... -def py2_compatible(x: Text) -> Text: - ... -def py3_only(x: str) -> str: +def py2_code(x: str) -> unicode: ... ``` @@ -3385,18 +3297,16 @@ type. ```python from typing import Text, Union ... -def py2_compatible(x: Union[bytes, Text]) -> Union[bytes, Text]: - ... def py3_only(x: Union[bytes, str]) -> Union[bytes, str]: ... +def py2_compatible(x: Union[bytes, Text]) -> Union[bytes, Text]: + ... ``` If all the string types of a function are always the same, for example if the return type is the same as the argument type in the code above, use [AnyStr](#typing-type-var). -Writing it like this will simplify the process of porting the code to Python 3. -