├── .github
├── ISSUE_TEMPLATE
│ ├── guide_update.md
│ ├── incorrect_translation.md
│ ├── structural_improvement.md
│ └── system_improvement.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── python-app.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Google Python Style Guide kor.md
├── Google Python Style Guide
├── 1. 배경
│ ├── 1.1 배경.md
│ └── ReadMe.md
├── 2. Python 언어 규칙
│ ├── 2.1 Lint.md
│ ├── 2.10 람다.md
│ ├── 2.11 조건문 표현.md
│ ├── 2.12 기본 인자 값.md
│ ├── 2.13 Properties.md
│ ├── 2.14 True, False 평가.md
│ ├── 2.16 렉시컬 스코핑(Lexical Scoping).md
│ ├── 2.17 함수와 메서드 Decorators.md
│ ├── 2.18 스레드.md
│ ├── 2.19 강한 기능.md
│ ├── 2.2 import.md
│ ├── 2.20 Modern Python.md
│ ├── 2.21 Type 주석.md
│ ├── 2.3 package.md
│ ├── 2.4 예외처리.md
│ ├── 2.5 변경 가능한 전역 상태.md
│ ├── 2.6 중첩.md
│ ├── 2.7 list_comprehensions.md
│ ├── 2.8 기본 반복자와 연산자.md
│ ├── 2.9 제너레이터.md
│ └── ReadMe.md
├── 3. Python 스타일 규칙
│ ├── 3.1 세미콜론.md
│ ├── 3.10 문자열.md
│ ├── 3.11 파일과 소켓.md
│ ├── 3.12 TODO 주석.md
│ ├── 3.13 import형식.md
│ ├── 3.14 statements.md
│ ├── 3.15 접근 제어.md
│ ├── 3.16 네이밍.md
│ ├── 3.17 Main.md
│ ├── 3.18 함수 길이.md
│ ├── 3.19 Type 주석 방법.md
│ ├── 3.2 줄 길이.md
│ ├── 3.3 괄호.md
│ ├── 3.4 들여쓰기.md
│ ├── 3.5 빈 줄.md
│ ├── 3.6 Whitespace.md
│ ├── 3.7 Shebang_Line.md
│ ├── 3.8 주석과 docstring.md
│ └── ReadMe.md
└── 4. 맺음말
│ ├── 4.1 맺음말.md
│ └── ReadMe.md
├── LICENSE
├── Original.md
├── README.md
└── script
├── build.py
├── update_original.py
└── update_original_requirements.txt
/.github/ISSUE_TEMPLATE/guide_update.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Google Python Style Guide 갱신
3 | about: Google Python Style Guide 원본이 갱신되었다면 작성해주세요!
4 | title: ""
5 | labels: "Guide 업데이트"
6 | assignees: "sotaneum, 0113bernoyoun"
7 | ---
8 |
9 | > **아래는 작성 방법입니다**
10 |
11 | ## Commit ID
12 |
13 | - [f87ee84](https://github.com/google/styleguide/commit/f87ee8407a2447c8fd9ccf2b1d83c56b572585f4)
14 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/incorrect_translation.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 오역/더 나은 번역
3 | about: 번역 내용 중 오역이나 더 나은 번역이 있다면 작성해 주세요!
4 | title: ""
5 | labels: "오역/더 나은 번역"
6 | assignees: "sotaneum, 0113bernoyoun"
7 | ---
8 |
9 | > **아래는 작성 방법입니다**
10 |
11 | | 위치 | 기존 문장 | 개선 문장 |
12 | | ------ | --------------------------- | -------------------------------- |
13 | | 3.19.2 | 기존의 들여쓰기 규칙입니다. | 기존의 들여쓰기 규칙을 따르세요. |
14 |
15 | - 이유 : 강제성이 부여되어야 합니다.
16 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/structural_improvement.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 번역 구조 개선
3 | about: 번역의 구조에 대해 개선점이 있다면 작성해주세요!
4 | title: ""
5 | labels: "번역 구조 개선"
6 | assignees: "sotaneum, 0113bernoyoun"
7 | ---
8 |
9 | > **아래는 작성 방법입니다**
10 |
11 | ## 구조 개선 방안
12 |
13 | 가독성 개선을 위해 `챕터`마다 `
`를 추가합니다.
14 |
15 | ## 상세 설명
16 |
17 | ```md
18 | # 1장. 배경
19 |
20 | ...
21 |
22 |
23 |
24 | ...
25 |
26 | # 2장. Python 언어 규칙
27 |
28 | ...
29 | ```
30 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/system_improvement.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 번역 시스템 개선
3 | about: 빌드/웹페이지/변역 방식 등 번역 외에 시스템에서 개선해야 할 사항이 있다면 알려주세요!
4 | title: ""
5 | labels: "시스템 개선"
6 | assignees: "sotaneum"
7 | ---
8 |
9 | > **아래는 작성 방법입니다**
10 |
11 | ## 원인
12 |
13 | ## 해결
14 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | > **아래는 작성 방법입니다**
2 |
3 | ## ISSUE ID
4 |
5 | - #12
6 |
7 | ## 요약
8 |
9 | - PR 내용을 요약합니다.
10 |
11 | ## 상세
12 |
13 | - PR 내용을 상세하게 작성합니다.
14 |
15 | ## TODO LIST
16 |
17 | - 작업 현황을 작성합니다.
18 | - [ ] Root
19 | - [ ] Node
20 | - [ ] Node
21 |
--------------------------------------------------------------------------------
/.github/workflows/python-app.yml:
--------------------------------------------------------------------------------
1 | name: Python-Style-Guide-Get-Original
2 |
3 | on:
4 | schedule:
5 | # 1, 4, 7, 10월 첫 금요일에 실행합니다. (UTC +09:00)
6 | - cron: "0 0 1-7 1,4,7,10 5"
7 | workflow_dispatch:
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v4
14 | - name: Set up Python
15 | uses: actions/setup-python@v5
16 | with:
17 | python-version: 3.9
18 | - name: Install Dependencies
19 | run: |
20 | python -m pip install --upgrade pip
21 | if [ -f ./script/update_original_requirements.txt ]; then pip install -r ./script/update_original_requirements.txt; fi
22 | - name: Crawler
23 | run: |
24 | python ./script/update_original.py
25 | env:
26 | # Settings > sercets > ACCESS_TOKEN
27 | ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at gnyontu39@gmail.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | When contributing to this repository, please first discuss the change you wish to make via issue,
4 | email, or any other method with the owners of this repository before making a change.
5 |
6 | Please note we have a code of conduct, please follow it in all your interactions with the project.
7 |
8 | ## Pull Request Process
9 |
10 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a
11 | build.
12 | 2. Update the README.md with details of changes to the interface, this includes new environment
13 | variables, exposed ports, useful file locations and container parameters.
14 | 3. Increase the version numbers in any examples files and the README.md to the new version that this
15 | Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).
16 | 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
17 | do not have permission to do that, you may request the second reviewer to merge it for you.
18 |
19 | ## Code of Conduct
20 |
21 | ### Our Pledge
22 |
23 | In the interest of fostering an open and welcoming environment, we as
24 | contributors and maintainers pledge to making participation in our project and
25 | our community a harassment-free experience for everyone, regardless of age, body
26 | size, disability, ethnicity, gender identity and expression, level of experience,
27 | nationality, personal appearance, race, religion, or sexual identity and
28 | orientation.
29 |
30 | ### Our Standards
31 |
32 | Examples of behavior that contributes to creating a positive environment
33 | include:
34 |
35 | * Using welcoming and inclusive language
36 | * Being respectful of differing viewpoints and experiences
37 | * Gracefully accepting constructive criticism
38 | * Focusing on what is best for the community
39 | * Showing empathy towards other community members
40 |
41 | Examples of unacceptable behavior by participants include:
42 |
43 | * The use of sexualized language or imagery and unwelcome sexual attention or
44 | advances
45 | * Trolling, insulting/derogatory comments, and personal or political attacks
46 | * Public or private harassment
47 | * Publishing others' private information, such as a physical or electronic
48 | address, without explicit permission
49 | * Other conduct which could reasonably be considered inappropriate in a
50 | professional setting
51 |
52 | ### Our Responsibilities
53 |
54 | Project maintainers are responsible for clarifying the standards of acceptable
55 | behavior and are expected to take appropriate and fair corrective action in
56 | response to any instances of unacceptable behavior.
57 |
58 | Project maintainers have the right and responsibility to remove, edit, or
59 | reject comments, commits, code, wiki edits, issues, and other contributions
60 | that are not aligned to this Code of Conduct, or to ban temporarily or
61 | permanently any contributor for other behaviors that they deem inappropriate,
62 | threatening, offensive, or harmful.
63 |
64 | ### Scope
65 |
66 | This Code of Conduct applies both within project spaces and in public spaces
67 | when an individual is representing the project or its community. Examples of
68 | representing a project or community include using an official project e-mail
69 | address, posting via an official social media account, or acting as an appointed
70 | representative at an online or offline event. Representation of a project may be
71 | further defined and clarified by project maintainers.
72 |
73 | ### Enforcement
74 |
75 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
76 | reported by contacting the project team at gnyontu39@gmail.com. All
77 | complaints will be reviewed and investigated and will result in a response that
78 | is deemed necessary and appropriate to the circumstances. The project team is
79 | obligated to maintain confidentiality with regard to the reporter of an incident.
80 | Further details of specific enforcement policies may be posted separately.
81 |
82 | Project maintainers who do not follow or enforce the Code of Conduct in good
83 | faith may face temporary or permanent repercussions as determined by other
84 | members of the project's leadership.
85 |
86 | ### Attribution
87 |
88 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
89 | available at [http://contributor-covenant.org/version/1/4][version]
90 |
91 | [homepage]: http://contributor-covenant.org
92 | [version]: http://contributor-covenant.org/version/1/4/
93 |
--------------------------------------------------------------------------------
/Google Python Style Guide/1. 배경/1.1 배경.md:
--------------------------------------------------------------------------------
1 | - Python은 구글에서 메인으로 사용하는 동적 언어입니다.
2 | - 이 스타일 가이드는 Python 프로그램에서 _해야 할 것들과 하지 말아야 할 것_ 들을 적어놓았습니다.
3 | - 코드 형식을 정확하게 하는 것들 돕기 위해, 우리는 [settings file for Vim](google_python_style.vim)을 만들었습니다.
4 | - Emacs 편집기에서는 기본 설정값으로 사용하면 됩니다.
5 | - 많은 팀에서 형식에 대한 논쟁을 피하기 위해 [Black](https://github.com/psf/black) 혹은 [Pyink](https://github.com/google/pyink) auto-formatter 을 사용합니다.
6 |
--------------------------------------------------------------------------------
/Google Python Style Guide/1. 배경/ReadMe.md:
--------------------------------------------------------------------------------
1 | - Python은 구글에서 메인으로 사용하는 동적 언어입니다.
2 | - 이 스타일 가이드는 Python 프로그램에서 _해야 할 것들과 하지 말아야 할 것_ 들을 적어놓았습니다.
3 | - 코드 형식을 정확하게 하는 것들 돕기 위해, 우리는 [settings file for Vim](google_python_style.vim)을 만들었습니다.
4 | - Emacs 편집기에서는 기본 설정값으로 사용하면 됩니다.
5 | - 많은 팀에서 형식에 대한 논쟁을 피하기 위해 [Black](https://github.com/psf/black) 혹은 [Pyink](https://github.com/google/pyink) auto-formatter 을 사용합니다.
6 |
7 | ---
8 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.1 Lint.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.1 Lint
4 |
5 | - 이 [pylintrc](https://google.github.io/styleguide/pylintrc)를 사용하여 코드에서 `pylint`를 실행합니다.
6 |
7 |
8 |
9 | #### 2.1.1 정의
10 |
11 | - `pylint`는 파이썬 소스코드에서 버그와 스타일 문제를 찾기 위한 툴입니다. (`pylint`는 빌나 컴파일 시 에러 외에 `추가`로 오류검사를 할 수 있는 도구라고 생각하면 될 것 같습니다.)
12 | - 일반적으로 C나 C++와 같은 비동적 프로그래밍 언어에서의 컴파일러를 통해 잡히는 문제를 찾아냅니다.
13 | - 파이썬의 동적인 특성때문에 몇몇 경고들은 정확하지 않을 수 있지만 드물게 발생합니다.
14 |
15 |
16 |
17 | #### 2.1.2 장점
18 |
19 | - 오타와 같은 놓치기 쉬운 에러나 할당이 되지 않은 변수 사용 등의 에러를 쉽게 잡을 수 있습니다.
20 |
21 |
22 |
23 | #### 2.1.3 단점
24 |
25 | - `pylint`는 완벽하지 않습니다.
26 | - `pylint`를 이용하기 위해 다음과 같은 사항들을 따라야 합니다.
27 | - 주위에 작성한다.
28 | - 경고를 억제한다.
29 | - 그것을 개선한다.
30 |
31 |
32 |
33 | #### 2.1.4 결론
34 |
35 | - 코드에 `pylint`를 실행시키세요.
36 |
37 | - 다른 문제가 가려지지 않도록 경고가 부적절할 경우 경고를 띄우지 마세요.
38 | - 경고를 띄우지 않기 위해, 코드에 라인 단위로 주석을 달아야 합니다.
39 |
40 | ```python
41 | def do_PUT(self): # WSGI name, so pylint: disable=invalid-name
42 | ...
43 | ```
44 |
45 | - `pylint`의 경고는 각각 symbolic name(`empty-docstring`)으로 구별됩니다.
46 | - Google-specific 경고는 `g-`로 시작합니다.
47 | - symbolic name에서 경고를 억제한 이유가 명확하지 않으면 설명을 추가해야 합니다.
48 | - 이러한 방식으로 경고를 억제하면 쉽게 경고를 억제한 것들을 찾을 수 있는 이점이 있습니다.
49 | - `pylint`의 경고 리스트를 다음과 같은 방법으로 볼 수 있습니다.
50 |
51 | ```shell
52 | pylint --list-msgs
53 | ```
54 |
55 | - 각 메시지에 대해 자세한 정보를 얻고자 하는 경우 다음과 같은 방법으로 볼 수 있습니다.
56 |
57 | ```shell
58 | pylint --help-msg=invalid-name
59 | ```
60 |
61 | - `pyling: disable-msg`는 이전에 사용했던 방식으로 이제는 사용되지 않으며 `pylint: disable`를 사용합니다.
62 | - 사용되지 않는 인자에 대한 경고는 함수를 시작할 때 그 변수를 지움으로써 억제할 수 있습니다. 다만 그 변수를 왜 지웠는지에 대해 항상 주석으로 설명을 추가해야 합니다. 이러한 경우는 "Unused."라고 작성하면 충분합니다.
63 | - 아래 예시를 참고하세요.
64 |
65 | ```python
66 | def viking_cafe_order(spam: str, beans: str, eggs: str | None = None) -> str:
67 | del beans, eggs # Unused by vikings.
68 | return spam + spam + spam
69 | ```
70 |
71 | - 경고를 없애는 방법은 일반적인 형태로 사용되지 않은 인자의 이름으로 `_`를 사용하거나 이름에 `unused_`를 붙이거나 `_`으로 할당하는 것입니다. 이러한 형태는 허용되지만 권장하지 않습니다. break caller는 이름으로 인수를 전달하고 인수가 실제로 사용되지 않도록 강제하지 않습니다.
72 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.10 람다.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.10 람다 함수
4 |
5 | - 한 줄 작성에 사용하세요.
6 | - `lambda`에는 `map()` 또는 `filter()` 보다 제너레이터 구문이 더 적합합니다
7 |
8 |
9 |
10 | #### 2.10.1 정의
11 |
12 | - 람다는 표현에 있어 다른 `문` 과는 달리 익명 함수들을 정의합니다.
13 |
14 |
15 |
16 | #### 2.10.2 장점
17 |
18 | - 편리합니다.
19 |
20 |
21 |
22 | #### 2.10.3 단점
23 |
24 | - 로컬 함수에 비해 읽기 어렵고 디버깅이 힘듭니다. 이름이 없다는 것은 stack trace를 이해하기 어렵다는 것입니다.
25 | - 함수에는 오직 표현식만 담을 수 있어 표현이 제한됩니다.
26 |
27 |
28 |
29 | #### 2.10.4 결론
30 |
31 | - 람다 함수는 허용하지만, 람다 함수 내부의 코드가 여러 줄에 걸치거나 60-80자를 넘는 경우, 일반적인 [중첩 함수](#s2.16-lexical-scoping)로 정의하는 것이 더 나을 수 있습니다.
32 | - 곱셈 같은 일반 연산자에서는 `operator`모듈 대신에 람다 함수를 사용하세요.
33 | - 예를 들어, `operator.mul`을 `lambda x,y : x * y` 처럼 사용하시면 됩니다.
34 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.11 조건문 표현.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.11 조건문 표현
4 |
5 | - 간단한 상황에 좋습니다.
6 |
7 |
8 |
9 | #### 2.11.1 정의
10 |
11 | - 조건식(삼항 연산자)은 if 문을 더 짧은 구문으로 사용하는 방법입니다. (e.g, `x = 1 if cond else 2`)
12 |
13 |
14 |
15 | #### 2.11.2 장점
16 |
17 | - if 문보다 짧고 편리합니다.
18 |
19 |
20 |
21 | #### 2.11.3 단점
22 |
23 | - if 문보다 읽기가 어려울 수 있습니다. 표현이 길어지면 조건을 찾기가 어려울 수 있습니다.
24 |
25 |
26 |
27 | #### 2.11.4 결론
28 |
29 | - 간단한 상황에 좋습니다. 그 외의 경우에는 if 문을 사용하는 것이 좋습니다.
30 | - `true-false`, `if-else` 표현 등 각각의 코드가 반드시 한 줄에 표현되어야 합니다.
31 | - 보다 복잡한 구문이 필요하다면 `lambda`가 아닌 완전한 `if` 구문을 사용하세요.
32 |
33 | ```python
34 |
35 | 올바른 예:
36 | one_line = 'yes' if predicate(value) else 'no'
37 | slightly_split = ('yes' if predicate(value)
38 | else 'no, nein, nyet')
39 | the_longest_ternary_style_that_can_be_done = (
40 | 'yes, true, affirmative, confirmed, correct'
41 | if predicate(value)
42 | else 'no, false, negative, nay')
43 |
44 | 잘못된 예:
45 | bad_line_breaking = ('yes' if predicate(value) else
46 | 'no')
47 | portion_too_long = ('yes'
48 | if some_long_module.some_long_predicate_function(
49 | really_long_variable_name)
50 | else 'no, false, negative, nay')
51 |
52 | ```
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.12 기본 인자 값.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.12 기본 인자 값
4 |
5 | - 대부분은 사용해도 됩니다.
6 |
7 |
8 |
9 | #### 2.12.1 정의
10 |
11 | - 함수의 매개변수 목록 끝에 있는 변수에 대한 값을 지정할 수 있습니다.
12 | - 예) `def foo(a, b=0):` 라는 함수의 경우에 만약 `foo`를 하나의 인자값으로 호출한다면 `b`의 값은 0으로 설정됩니다. 만약에 두 개의 인자값이라면 `b`의 값은 두 번째 인자값을 가지게 됩니다.
13 |
14 |
15 |
16 | #### 2.12.2 장점
17 |
18 | - 기본값을 많이 가지는 함수는 있지만, 기본값을 재정의하는 경우는 거의 없습니다.
19 | - 기본 인자값을 사용하면 드문 예외에 대해 많은 함수를 정의할 필요 없이 쉽게 처리할 수 있습니다.
20 | - 또한, Python은 매서드/함수에 대해 Overloading을 지원하지 않으므로 기본 인자값을 사용하면 쉽게 Overloading를 사용하는 것처럼 할 수 있습니다.
21 |
22 |
23 |
24 | #### 2.12.3 단점
25 |
26 | - 기본 인자값은 모듈이 불러올 때 한번 계산됩니다.
27 | - 인자값이 list나 dictionary 같은 경우 변형이 가능한 Object이면 문제를 일으킬 수 있습니다.
28 | - 만약에 함수가 Object를 수정하는 경우(list에 item을 추가하는 경우) 기본값이 수정됩니다.
29 |
30 | - 예시
31 |
32 | ```python
33 | def foo(b=[]):
34 | b.append(1)
35 | return b
36 | foo() # b = [1]
37 | foo() # b = [1, 1]
38 | print(foo()) # [1, 1, 1]
39 | ```
40 |
41 |
42 |
43 | #### 2.12.4 결론
44 |
45 | - 다음 주의사항과 함께 사용할 수 있습니다.
46 | - 함수 또는 메서드 정의할 때 `변할 수 있는 Object`를 기본값으로 사용하지 마세요.
47 | - 올바른 예
48 |
49 | ```python
50 | def foo(a, b=None):
51 | if b is None:
52 | b = []
53 | def foo(a, b: Sequence | None = None):
54 | if b is None:
55 | b = []
56 | def foo(a, b: Sequence = ()): # tuples은 불변하기 때문에 사용 가능합니다.
57 | ...
58 | ```
59 |
60 | - 부적절한 예
61 |
62 | ```python
63 | from absl import flags
64 | _FOO = flags.DEFINE_string(...)
65 |
66 | def foo(a, b=[]):
67 | ...
68 | def foo(a, b=time.time()): # `b`가 이 모듈이 로드된 시간을 나타내는 것인가요?
69 | ...
70 | def foo(a, b=_FOO.value): # sys.argv는 아직 구문 분석되지 않았습니다...
71 | ...
72 | def foo(a, b: Mapping = {}): # 확인되지 않은 코드로 전달 될 수 있습니다.
73 | ...
74 | ```
75 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.13 Properties.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.13 Properties
4 |
5 | - `Properties`는 간단한 계산이나 로직이 필요한 attribute을 가져오거나 설정하는 것을 제어하는 데 사용될 수 있습니다.
6 | - `Properties` 구현은 보통의 attribute 접근에 대한 일반적인 기대와 일치되어야 합니다.
7 |
8 |
9 |
10 | #### 2.13.1 정의
11 |
12 | - 일반적인 속성을 접근하듯이 속성을 가져오거나 설정하는 메서드 호출을 포장하는 방법입니다.
13 |
14 |
15 |
16 | #### 2.13.2 장점
17 |
18 | - getter, setter method 호출 대신 attribute 접근 및 할당 API를 허용합니다.
19 | - attribute를 읽기 전용으로 만드는 데 사용할 수 있습니다.
20 | - [느긋한 계산법](https://ko.wikipedia.org/wiki/느긋한_계산법)을 허용합니다.
21 | - 내부가 class 사용자와 독립적으로 발전할 때 클레스의 public interface를 유지 관리하는 방법을 제공합니다.
22 |
23 |
24 |
25 | #### 2.13.3 단점
26 |
27 | - 연산자 오버 로딩(operator overloading)과 같은 부작용을 숨길 수 있습니다.
28 | - 하위 클래스의 경우 혼란스러울 수 있습니다.
29 |
30 |
31 |
32 | #### 2.13.4 결론
33 |
34 | - Properties는 허용하지만 연산자 오버로딩과 마찬가지로 필요한 경우에만 사용해야 하며 일반적인 attribute 접근에 대한 기대와 일치해야합니다
35 | - 그렇지 않은 경우에는 [getters and setters](#getters-and-setters)규칙을 따르세요.
36 | - 예를 들어, 단순히 attribute를 가져오고 설정하기 위해 property를 사용하는 것은 허용되지 않습니다.
37 | - 계산이 발생하지 않으므로 property는 불필요합니다. ([대신 attribute를 public으로 설정합니다.](#getters-and-setters))
38 | - 이에 비해 attribute 접근을 제어하거나 사소한 파생 값을 계산하기 위해 property를 사용하는 것은 허용됩니다.
39 | - 로직은 간단하고 놀랍지 않습니다.
40 | - Properties는 `@property` [decorator](#s2.17-function-and-method-decorators)를 사용하여 생성해야합니다.
41 | - property descriptor를 수동으로 구현하는 것은 [power feature](#power-features)로 간주됩니다.
42 | - 속성에 대한 상속은 명백하지 않을 수 있습니다. subclass가 재정의하고 확장하기 위한 계산 도구로 properties를 사용하지 마세요.
43 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.14 True, False 평가.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.14 True/False 평가
4 |
5 | - 가능한 경우 "암묵적(implicit)" `false`를 사용하세요. (몇 가지 주의사항이 있지만)
6 |
7 |
8 |
9 | #### 2.14.1 정의
10 |
11 | - Python은 boolean문에서 특정 값을 `False`으로 평가합니다.
12 | - 빠른 "거짓의 법칙"은 모든 "비어있는" 값을 `False`으로 간주되므로 `0, None, [], {}, ''`은 boolean문에서는 `False`으로 평가합니다.
13 |
14 |
15 |
16 | #### 2.14.2 장점
17 |
18 | - Python boolean을 사용하면 읽기 쉽고 오류가 적고 대부분의 경우 빠릅니다.
19 |
20 |
21 |
22 | #### 2.14.3 단점
23 |
24 | - C/C++ 개발자들에게는 이상하게 보일 수도 있습니다.
25 |
26 |
27 |
28 | #### 2.14.4 결론
29 |
30 | - 가능하다면 "암묵적(implicit)" `False`를 사용하세요. (e.g. `if foo != []:` 보다는 `if foo:` 가 좋습니다.)
31 | - 그러나 몇가지 주의 사항을 명심해야합니다.
32 |
33 | - 항상 `if foo is None:`(혹은 `is not None`)을 통해 `None` 값을 확인하세요.
34 | - 예를 들어, 기본값이 `None`인 변수나 인자를 어떤 값으로 설정했는지 확인할 때, 어떤 값이 boolean의 `False` 값일 수 있습니다.
35 | - `==`를 사용해서 boolean 변수인 `False`와 비교하지 마세요. 대신 `if not x:`를 사용하세요. `False`와 `None`를 구별해야 할 경우 `if not x and is not None:`와 같은 식으로 연결하세요.
36 | - sequences(strings, lists, tuples)의 경우 빈 sequences는 `False`이므로 `if len(seq):` 혹은 `if not len(seq):` 보다 `if seq:` 혹은 `if not seq:`가 더 바람직합니다.
37 | - 정수(integer)를 처리할때, 암묵적(implicit) `False`는 이점보다 더 많은 위험을 가져올 수 있습니다(즉 `None`을 0으로 잘못 처리합니다.). (`len()`의 결과가 아닌)정수라고 알려진 값을 정수 0과 비교할 수 있습니다.
38 |
39 | - 올바른 예
40 |
41 | ```python
42 | if not users:
43 | print('사용자가 없습니다.')
44 |
45 | if i % 10 == 0:
46 | self.handle_multiple_of_ten()
47 |
48 | def f(x=None):
49 | if x is None:
50 | x = []
51 | ```
52 |
53 | - 부적절한 예
54 |
55 | ```python
56 | if len(users) == 0:
57 | print('사용자가 없습니다.')
58 |
59 | if not i % 10:
60 | self.handle_multiple_of_ten()
61 |
62 | def f(x=None):
63 | x = x or []
64 | ```
65 |
66 | - `'0'`(즉, `0` 문자열)은 참으로 평가한다는 점에 유의해야합니다.
67 | - Numpy 배열은 암시적 boolean 컨텍스트에서 예외를 발생시킬 수 있습니다. `np.array`의 비어 있음을 테스트할 때 `.size` attribute를 선호합니다. (e.g. `if not users.size`)
68 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.16 렉시컬 스코핑(Lexical Scoping).md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.16 렉시컬 스코핑(Lexical Scoping)
4 |
5 | - 사용해도 좋습니다.
6 |
7 |
8 |
9 | #### 2.16.1 정의
10 |
11 | - 중첩된 Python 함수는 주변 함수에 정의된 변수를 참조할 수 있지만 할당할 수 없습니다.
12 | - 변수 바인딩은 렉시컬 스코핑(Lexical Scoping)를 사용하여 해결합니다. 즉, 정적 프로그램 텍스트를 기반으로 합니다.
13 | - 블록 내에 할당된 모든 이름은 Python이 해당 이름에 대한 모든 참조를 할당에 앞서 사용하더라도 로컬 변수로 처리하게 할 것입니다. 만약에 전역 변수가 발생하면 그 이름은 전역 변수로 취급합니다.
14 |
15 | - 이 기능에 대해 사용예는 다음과 같습니다.
16 |
17 | ```python
18 | def get_adder(summand1: float) -> Callable[[float], float]:
19 | """주어진 숫자에 숫자를 더하는 함수를 반환합니다."""
20 | def adder(summand2: float) -> float:
21 | return summand1 + summand2
22 |
23 | return adder
24 | ```
25 |
26 |
27 |
28 | #### 2.16.2 장점
29 |
30 | - 종종 명확하고 우아한 코드를 만들어냅니다. 특히 Lisp와 Scheme(그리고 Haskell, ML ...) 개발자들에게 위안을 줍니다.
31 |
32 |
33 |
34 | #### 2.16.3 단점
35 |
36 | - [PEP-0227](https://peps.python.org/pep-0227)을 기반으로 한 이 예시와 같이 혼란스러운 버그를 초래할 수 있습니다.
37 |
38 | ```python
39 | i = 4
40 | def foo(x: Iterable[int]):
41 | def bar():
42 | print(i, end='') # foo 함수 밖에 있는 i와 동일한 i를 사용합니다.
43 | # ...
44 | # 코드 생략
45 | # ...
46 | for i in x: # foo함수 밖의 i와 동일한 i를 사용합니다. (i 값이 초기화 됩니다.)
47 | print(i, end='')
48 | bar()
49 | ```
50 |
51 | - `foo([1, 2, 3])`은 `1 2 3 4`가 아니라 `1 2 3 3`가 출력됩니다.
52 |
53 |
54 |
55 | #### 2.16.4 결론
56 |
57 | - 사용해도 좋습니다.
58 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.17 함수와 메서드 Decorators.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.17 함수와 메서드 Decorators
4 |
5 | - Decorators는 확실하게 이점이 있을 때에 신중하게 사용하세요. `staticmethod`는 피하고 `classmethod`의 사용은 제한하세요.
6 |
7 |
8 |
9 | #### 2.17.1 정의
10 |
11 | - [함수와 메서드를 위한 Decorators 입니다.](https://docs.python.org/3/glossary.html#term-decorator) ("`@` 표기법"으로 알려져있습니다).
12 | - 일반적인 decorator 중 하나는 메서드를 동적으로 계산한 속성으로 변환하는 데 사용하는 `@property`가 있습니다. 그러나 decorator는 사용자 정의 decorator도 허용하고 있습니다.
13 | - 특히 이 `my_decorator` 함수 처럼 할 수 있습니다
14 |
15 | ```python
16 | class C:
17 | @my_decorator
18 | def method(self):
19 | # 메서드 구현부 ...
20 | ```
21 |
22 | - 위 와 동일한 역할 합니다
23 |
24 | ```python
25 | class C:
26 | def method(self):
27 | # 메서드 구현부 ...
28 | method = my_decorator(method)
29 | ```
30 |
31 |
32 |
33 | #### 2.17.2 장점
34 |
35 | - 메서드에 대해 몇몇 변형을 엄밀하게 명시합니다.
36 | - 변형은 몇 가지 반복적인 코드를 제거하고 불변성을 유지하게 만드는 작업 등을 수행합니다.
37 |
38 |
39 |
40 | #### 2.17.3 단점
41 |
42 | - Decorator는 함수의 인자, 반환 값에 대해 임의의 동작을 수행할 수 있으며 결과적으로 놀라운 암묵적 행동을 할 수 있습니다.
43 | - 게다가, Decorator는 object 정의 시 실행합니다. module-level 객체(classes, module functions, ...)의 경우 import할 때 발생합니다.
44 | - Decorator 코드 오류는 복구가 거의 불가능합니다.
45 |
46 |
47 |
48 | #### 2.17.4 결론
49 |
50 | - Decorator는 분명한 이점이 있더라도 현명하게 사용해야 합니다. Decorator는 import와 명명 지침을 따라야 합니다. Decorator pydoc는 decorator 함수 임을 분명히 명시해야합니다. dcorator를 위한 유닛 테스트(unit test)를 사용해야합니다.
51 | - Decorator(예. 파일, 소켓, 데이터베이스 연결 등) 를 실행할 때 (`pydoc` 혹은 기타 도구를 import 시간에 가져올 때) 사용 못할 수 있으므로 Decorator의 외부 의존성을 피하세요. 유효한 매개변수를 가진 Decorator은 모든 경우에 작동할 수 있도록 보장되어야 합니다.
52 | - Decorator는 "Top-level code"의 특별한 경우일 때에는 [main](#s3.17-main) 항목에 자세한 내용이 있습니다.
53 | - 기존 라이브러리에 정의된 API와 통합하기 위해 강제하지 않는 한 "staticmethod"를 사용하지 마세요. 대신 모듈 레벨 함수를 쓰세요.
54 | - classmethod는 명명된 생성자를 작성하거나 프로세스 전체 캐시와 같은 필수 전역 상태를 수정하는 클래스 특정 루틴을 작성할 때만 사용하세요.
55 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.18 스레드.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.18 스레드
4 |
5 | - 내장된 타입의 원자성에 의존하지 마세요. 딕셔너리와 같은 Python의 내장된 타입은 원자 형태로 조작할 수 있지만 그러지 않은 경우(예: `__hash__`이나 `__eq__`가 Python 함수로 구현되는 경우)도 있으며 원자로 되어있다고 신뢰하면 안 됩니다. 또한, 원자 변수 할당에 의존해서는 안 됩니다. (결국, 딕셔너리에 달려있기 때문입니다) 스레드 간 데이터를 통신하는 데 선호하는 방법으로 `queue` 모듈의 `Queue` 데이터 타입을 사용하세요. 그렇지 않으면 `threading` 모듈이나 locking primitives를 사용하세요. lower-level lock 대신해 Condition variables와 `threading.Condition`를 선호하세요.
6 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.19 강한 기능.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.19 강한 기능
4 |
5 | - 이런 기능들은 피하세요.
6 |
7 |
8 |
9 | #### 2.19.1 정의
10 |
11 | - Python은 매우 유연한 언어로서 당신에게 많은 화려한 기능을 줍니다. (e.g. 사용자 정의 mtaclasses, bytecode 접근, 즉각적인 컴파일, 동적 상속, object reparenting, import hacks, reflection (`getattr()`의 일부 사용), 시스템 내부 수정, 커스텀 Cleanup을 위한 `__del__` 메소드 등.)
12 |
13 |
14 |
15 | #### 2.19.2 장점
16 |
17 | - 이것들은 강력한 언어 기능입니다. 코드를 더 짧게 만들 수 있습니다.
18 |
19 |
20 |
21 | #### 2.19.3 단점
22 |
23 | - 이 "멋진"기능이 반드시 필요한 것은 아니나 사용하는 것이 매우 유혹적입니다. 이러한 흔치 않은 기능들을 사용하면 읽거나 이해하거나 디버그하는데 어렵습니다.
24 | - 처음에는 그렇게 보이지 않지만 (원저자에게) 코드를 다시 보면 코드는 간단하지만 긴 코드보다 어려운 경향이 있습니다.
25 |
26 |
27 |
28 | #### 2.19.4 결론
29 |
30 | - 코드에서 이러한 기능은 피하세요.
31 | - 이러한 기능을 내부적으로 사용하는 표준 라이브러리 모듈과 클래스는 사용할 수 있습니다. (예를 들면, `abc.ABCMeta`, `dataclasses`, `enum`)
32 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.2 import.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.2 Imports
4 |
5 | - `import`문은 개별 타입, 클래스, 함수가 아니라 패키지와 모듈에만 사용하세요. (주: 개별 타입은 기본 자료형, 사용자 정의 클래스를 나타냅니다.)
6 |
7 |
8 |
9 | #### 2.2.1 정의
10 |
11 | - 하나의 모듈에서 다른 모듈로 코드를 공유하는 재사용 매커니즘 입니다.
12 |
13 |
14 |
15 | #### 2.2.2 장점
16 |
17 | - namespace management convention(이름을 짓는 방식)은 간단합니다. 각각 식별된 소스는 하나의 일관된 방식으로 작성됩니다. `x.Obj` 는 모듈 `x` 에 정의된 객체 `Obj` 를 의미합니다.
18 |
19 |
20 |
21 | #### 2.2.3 단점
22 |
23 | - 모듈 이름이 충돌할 수도 있습니다. 몇몇 모듈 이름은 불편할 정도로 깁니다.
24 |
25 |
26 |
27 | #### 2.2.4 결론
28 |
29 | - `import x`를 패키지와 모듈을 import할때 사용하세요.
30 | - `from x import y`를 `x`가 패키지의 접두어이고 `y`가 접두어가 없는 모듈일때 사용하세요.
31 | - 다음과 같은 상황에서는 `from x import y as z` 를 사용하세요.
32 | - `y`라는 이름을 가진 두 개의 모듈을 가져옵니다.
33 | - `y`는 현재 모듈에 정의된 최상위 이름과 충돌합니다.
34 | - `y`는 공개 API의 일부인 공통 매개변수 이름(예: 'features')과 충돌합니다.
35 | - `y`는 불편할 정도로 긴 이름입니다.
36 | - `y`는 코드 컨텍스트에서 너무 일반적입니다(예: `from storage.file_system import options as fs_options`).
37 | - `import y as z`를 `z` 가 공식적인 약어인 경우에만 사용하세요(e.g., `import numpy as np`)
38 |
39 | - 예를들어 `sound.effects.echo`모듈이 import 된다면 아래와 같습니다.
40 |
41 | ```python
42 | from sound.effects import echo
43 | ...
44 | echo.EchoFilter(input, output, delay=0.7, atten=4)
45 | ```
46 |
47 | - import된것들과 관련있는 이름을 사용하지마세요.
48 | - 모듈이 같은 패키지에 있더라도 전체 패키지 이름을 사용하세요.
49 | - 이는 무심코 패키지를 두번 import 하는것을 예방하는 것에 도움이 됩니다.
50 |
51 |
52 |
53 | ##### 2.2.4.1 예외
54 |
55 | - 이 규칙의 예외는 다음과 같습니다.
56 | - 다음 모듈의 심볼은 정적 분석 및 타입 검사를 지원하는 데 사용됩니다.
57 | - [`typing` module](#typing-imports)
58 | - [`collections.abc` module](#typing-imports)
59 | - [`typing_extensions` module](https://github.com/python/typing_extensions/blob/main/README.md)
60 | - [six.moves module](https://six.readthedocs.io/#module-six.moves)의 리다이렉션입니다.
61 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.20 Modern Python.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.20 Modern Python : from, \_\_future\_\_, imports
4 |
5 | - 새로운 언어 버전 의미 체계 변경 사항은 이전 런타임 내에서 파일 단위로 활성화하기 위해 특별한 향후 가져오기 뒤에 제어될 수 있습니다.
6 | (New language version semantic changes may be gated behind a special future import to enable them on a per-file basis within earlier runtimes.)
7 |
8 |
9 |
10 | #### 2.20.1 정의
11 |
12 | - `from __future__ import`문을 통해 보다 현대적인 기능 중 일부를 활성화할 수 있으면 예상되는 향후 Python 버전의 기능을 조기에 사용할 수 있습니다.
13 |
14 |
15 |
16 | #### 2.20.2 장점
17 |
18 | - 이는 호환성을 선언하고 해당 파일 내에서 회귀를 방지하면서 파일별로 변경이 이루어질 수 있으므로 런타임 버전 업그레이드를 더 원활하게 만드는 것으로 입중되었습니다.
19 | - 최신 코드는 향후 런타임 업그레이드 중에 문제가 될 수 있는 기술적 부채가 축적될 가능성이 적기 때문에 유지 관리가 더 쉽습니다.
20 |
21 |
22 |
23 | #### 2.20.3 단점
24 |
25 | - 이러한 코드는 필요한 feature 문을 도입하기 전에는 매우 오래된 인터프리터 버전에서 동작하지 않을 수 있습니다.
26 | - 일반적으로 다양한 환경을 지원해야하는 프로젝트에서 필요합니다.
27 |
28 |
29 |
30 | #### 2.20.4 결론
31 |
32 | ##### from \_\_future\_\_ imports
33 |
34 | - `from __future__ import`문을 사용하는 것이 좋습니다.
35 | - 주어진 소스파일에서 더욱 현대적인 Python 구문 기능을 사용할 수 있습니다.
36 | - `__future__` import 뒤에 기능이 숨겨져 있는 버전에서 더 이상 실행할 필요가 없다면 해당 줄을 자유롭게 제거하세요.
37 | - 3.7 이상이 아닌 3.5 이전 버전에서 실행될 수 있는 코드에서 가져올 경우
38 |
39 | ```python
40 | from __future__ import generator_stop
41 | ```
42 |
43 | - 자세한 내용은 [Python future statement definitions](https://docs.python.org/3/library/__future__.html) 문서를 읽어보세요.
44 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.21 Type 주석.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ### 2.21 Type 주석
5 |
6 | - Python에서 타입의 정보를 [PEP-484](https://www.python.org/dev/peps/pep-0484/)의 참고해서 주석으로 달 수 있습니다. 그리고 빌드 할 때 [pytype](https://github.com/google/pytype)같은 타입검사도구를 사용하세요.
7 | - Type에 대한 주석은 소스 안이나 [stub pyi 파일](https://peps.python.org/pep-0484/#stub-files)에 있을 수 있습니다. 가능하면 주석은 소스안에 있어야 합니다. 타사 또는 확장 모듈에는 pyi 파일을 사용하세요.
8 |
9 |
10 |
11 | #### 2.21.1 정의
12 |
13 | - Type의 주석(혹은 Type 정보)은 함수나 메서드의 인자값이나 반환값입니다
14 |
15 | ```python
16 | def func(a: int) -> list[int]:
17 | ```
18 |
19 | - [PEP-526](https://peps.python.org/pep-0526/)구문 처럼 변수의 type을 선언할 때 사용합니다.
20 |
21 | ```python
22 | a: SomeType = some_func()
23 | ```
24 |
25 |
26 |
27 | #### 2.21.2 장점
28 |
29 | - Type에 대한 주석은 코드의 가독성과 유지관리에 도움을 줍니다. Type 검사기는 많은 런타임 오류를 빌드 타임 오류로 바꿔주고 [강력한 기능들](#s2.19-power-features)의 사용을 줄여줍니다.
30 |
31 |
32 |
33 | #### 2.21.3 단점
34 |
35 | - Type의 명세를 최신으로 유지해야합니다. 올바른 코드라고 생각했던 곳에서 Type 에러를 볼지도 모릅니다. [Type 검사기](https://github.com/google/pytype)를 사용하면 [강력한 기능들](#s2.19-power-features)을 활용하는 능력이 떨어질 수 있습니다.
36 |
37 |
38 |
39 | #### 2.21.4 결론
40 |
41 | - 프로젝트의 복잡성에 크게 좌우됩니다. 한번 해보세요.
42 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.3 package.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.3 Packages
4 |
5 | - 각각의 모듈은 그 모듈의 전체 경로 위치를 사용하여 import합니다.
6 |
7 |
8 |
9 | #### 2.3.1 장점
10 |
11 | - module 이름의 충돌이나 작성자가 예상하지 못한 module search path으로 인한 잘못된 import를 방지합니다.
12 | - 모듈을 쉽게 찾을 수 있도록 해줍니다.
13 |
14 |
15 |
16 | #### 2.3.2 단점
17 |
18 | - 패키지 계층을 복제해야 하므로 코드를 배포하기 어렵습니다. 다만 현대적 배포 매커니즘에서는 문제될게 없습니다.
19 |
20 |
21 |
22 | #### 2.3.3 결론
23 |
24 | - 모든 새로운 코드는 그 코드의 전체 패키지 이름으로 각각의 모듈을 import해야합니다.
25 | - Import는 아래 사항을 따라야 합니다.
26 |
27 | - 올바른 예
28 |
29 | ```python
30 | # Reference absl.flags in code with the complete name (verbose).
31 | import absl.flags
32 | from doctor.who import jodie
33 |
34 | _FOO = absl.flags.DEFINE_string(...)
35 | ```
36 |
37 | ```python
38 | # Reference flags in code with just the module name (common).
39 | from absl import flags
40 | from doctor.who import jodie
41 |
42 | _FOO = flags.DEFINE_string(...)
43 | ```
44 |
45 | - 부적절한 예 _(이 파일은 `doctor/who/` 에 있다고 가정하고 `jodie.py`또한 존재한다고 가정합니다.)_
46 |
47 | ```python
48 | # Unclear what module the author wanted and what will be imported. The actual
49 | # import behavior depends on external factors controlling sys.path.
50 | # Which possible jodie module did the author intend to import?
51 | import jodie
52 | ```
53 |
54 | - 메인 바이너리 디렉토리는 몇몇 환경에서 발생했음에도 불구하고`sys.path`에 있다고 예측하면 안됩니다.
55 | - 이러한 상황에서 코드는 `import jodie`는 파일로 된 `jodie.py`가 아닌 써드파티나 탑 레벨 패키지 이름이 `jodie`라고 참조한다고 가정해야합니다.
56 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.4 예외처리.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.4 예외
4 |
5 | - 예외는 허용하지만 주의하며 사용해야합니다.
6 |
7 |
8 |
9 | #### 2.4.1 정의
10 |
11 | - 예외는 코드블록에서 정상적인 상황에 발생한 에러나 다른 예외적인 상황을 다루기 위해 정상적인 흐름에서 벗어나는것을 의미합니다.
12 |
13 |
14 |
15 | #### 2.4.2 장점
16 |
17 | - 일반적인 연산자에 대한 제어흐름은 에러 핸들링 코드에 의해 난잡해지지 않습니다.
18 | - 특정 조건이 발생했을 때 제어 흐름이 몇몇 프레임들을 생략할 수 있습니다.
19 | - 예를 들어, 에러 코드를 살펴보는 것 대신 한 번에 N개의 중첩 함수로부터 반환합니다.
20 |
21 |
22 |
23 | #### 2.4.3 단점
24 |
25 | - 제어 흐름이 혼란스러워질 수 있습니다. 라이브러리를 호출할때 에러 상황들을 놓치기 쉽습니다.
26 |
27 |
28 |
29 | #### 2.4.4 결론
30 |
31 | ##### 예외는 다음과 같은 조건을 만족해야 합니다
32 |
33 | - 내장 예외 클래스를 사용하는 데에 문제가 없다면 사용합니다. 예를 들어, 함수 인자를 검증할 때와 같은 프로그래밍 오류나 위반된 전제조건을 나타내기 위해 `ValueError`를 발생시키세요.
34 | - `assert` 문을 조건문이나 전제조건 검증 대신 사용하지 마세요. application logic에 중요하지 않아야 합니다. `assert`문을 제거해도 코드가 정상적으로 작동한다면, 그것이 기준이 될 수 있습니다. assert 조건문은 평가될 것이라고 [보장되지 않습니다](https://docs.python.org/3/reference/simple_stmts.html#the-assert-statement). [pytest](https://pytest.org)기반의 테스트에서는 `assert` 문을 사용하여 기대값을 검증하는 것이 적절하고 예상됩니다
35 |
36 | - 올바른 예
37 |
38 | ```python
39 | def connect_to_next_port(self, minimum: int) -> int:
40 | """Connects to the next available port.
41 |
42 | Args:
43 | minimum: A port value greater or equal to 1024.
44 | Raises:
45 | ValueError: If the minimum port specified is less than 1024.
46 | ConnectionError: If no available port is found.
47 | Returns:
48 | The new minimum port.
49 | """
50 | if minimum < 1024:
51 | raise ValueError(f'Min. port must be at least 1024, not {minimum}.')
52 | port = self._find_next_open_port(minimum)
53 | if port is None:
54 | raise ConnectionError(
55 | f'Could not connect to service on port {minimum} or higher.')
56 | # 이 코드의 결과는 이 assert에 의존하지 않습니다.
57 | assert port >= minimum, (
58 | f'Unexpected port {port} when minimum was {minimum}.')
59 | return port
60 | ```
61 |
62 | - 부적절한 예
63 |
64 | ```python
65 | def connect_to_next_port(self, minimum: int) -> int:
66 | """Connects to the next available port.
67 |
68 | Args:
69 | minimum: A port value greater or equal to 1024.
70 | Returns:
71 | The new minimum port.
72 | """
73 | assert minimum >= 1024, 'Minimum port must be at least 1024.'
74 | # 이 코드는 이전 assert에 의존합니다.
75 | port = self._find_next_open_port(minimum)
76 | assert port is not None
77 | # 반환 값에 대한 타입 검사는 assert에 의존합니다.
78 | return port
79 | ```
80 |
81 | - 라이브러리나 패키지는 고유의 예외가 정의되어 있을 것입니다.
82 | - 사용하는 동안, 기존에 존재하는 예외 클래스(exception class)로부터 상속을 받아야 합니다.
83 | - 예외 이름은 `Error`로 끝나야 하고 되풀이로 시작하면 안됩니다.(`foo.fooError`).
84 | - 예외를 다시 발생시키거나 쓰레드의 가장 바깥 쪽 블록에 있지않으면 절대 포괄적인 `except:`문을 사용하거나 `Exception`, `StandardError`을 사용하지마세요. (그리고 에러메시지를 출력하세요.) Python은 이와 관련해서 매우 관용적이며 `except:` 모든 오탈자를 비롯하여, sys.exit() 호출, Ctrl+C로 인한 인터럽트, 유닛테스트 실패와 마지막으로 당신이 포착을 원하지 않았던 다른 모든 종류의 예외들까지 모두 잡아낼 것입니다.
85 | - 코드상에서 `try`/`except` 블록의 수를 최소화시키세요. `try`문의 내부가 커질수록 예외는 당신이 예외가 발생할것이라 예상하지 않았던 코드에 의해 점점 더 발생할 것입니다. 이러한 상황에서, `try`/`except` 블록은 진짜 검출해야 할 에러를 가리게 됩니다.
86 | - 예외가 `try` 블록에서 발생하던 안하던 `finally`절은 코드를 실행시킨다. 이건 가끔 깔끔히 하는데 유용합니다. 예를들어, 파일을 닫을 때 가 그 예입니다.
87 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.5 변경 가능한 전역 상태.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ### 2.5 변경 가능한 전역 상태
7 |
8 | - 변경 가능한 전역 상태를 사용하지 마세요.
9 |
10 |
11 |
12 | #### 2.5.1 정의
13 |
14 | - 프로그램 실행 중 변경될 수 있는 모듈 수준의 값이나 클래스 속성을 말합니다.
15 |
16 |
17 |
18 | #### 2.5.2 장점
19 |
20 | - 가끔 편리합니다.
21 |
22 |
23 |
24 |
25 |
26 | #### 2.5.3 단점
27 |
28 | - 캡슐화가 깨집니다.
29 | - 이러한 설계는 유효한 목표를 달성하기 어렵게 만들 수 있습니다. 예를 들면, 전역 상태를 사용하여 데이터베이스 연결을 관리하는 경우, 두 개의 서로 다른 데이터베이스를 동시에 연결하는 것이 어려워질 수 있습니다(e.g., 마이그레이션 중 차이를 계산할 때). 전역 레지스트리에서도 유사한 문제가 쉽게 발생할 수 있습니다.
30 | - 모듈이 처음 임포트될 때 전역 변수에 대한 할당이 이루어지기 때문에, 모듈의 동작을 임포트 중에 변경할 가능성이 있습니다.
31 |
32 |
33 |
34 |
35 |
36 | #### 2.5.4 결론
37 |
38 | - 변경 가능한 전역 상태를 사용하지 마세요.
39 | - 전역 상태를 사용하는 것이 드물게 필요한 경우, 변경 가능한 전역 엔티티는 모듈 수준이나 클래스 속성으로 선언하고, 이름 앞에 `_`를 붙여 내부적으로 사용해야 합니다. 필요한 경우, 변경 가능한 전역 상태에 대한 외부 접근은 공개 함수나 클래스 메소드를 통해 이루어져야 합니다. [Naming](#s3.16-naming)를 참고하세요. 변경 가능한 전역 상태를 사용하는 설계 이유에 대해서는 주석에 설명하거나 링크된 문서에서 설명해 주세요.
40 | - 모듈 수준의 상수는 허용되며 권장됩니다. 예를 들어, 내부 용도의 상수에는 `_MAX_HOLY_HANDGRENADE_COUNT = 3`를 사용하고, Public API 상수에는 `SIR_LANCELOTS_FAVORITE_COLOR = "blue"`를 사용하세요. 상수는 모두 대문자와 밑줄을 사용하여 명명해야 합니다. [Naming](#s3.16-naming)를 참고하세요.
41 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.6 중첩.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.6 중첩/지역/내부 클래스와 함수
4 |
5 | - 중첩된 지역 함수나 클래스는 지역변수에 접근할 때 사용하면 좋습니다.
6 | - 내부클래스에서는 괜찮습니다.
7 |
8 |
9 |
10 | #### 2.6.1 정의
11 |
12 | - 클래스는 메소드, 함수, 클래스 내에서 정의할 수 있습니다.
13 | - 함수는 메서드나 함수 내에서 정의할 수 있습니다.
14 | - 중첩함수는 해당 스코프에 정의된 변수를 읽기만 가능합니다.
15 |
16 |
17 |
18 | #### 2.6.2 장점
19 |
20 | - 제한된 스코프 내에서 사용하는 유틸리티 클래스와 함수의 정의를 허용합니다.
21 | - [ADT](https://ko.wikipedia.org/wiki/추상_자료형)가 무엇인지 참고하세요.
22 | - 일반적으로 데코레이터를 구현할 때 사용됩니다.
23 |
24 |
25 |
26 | #### 2.6.3 단점
27 |
28 | - 중첩된 함수와 클래스는 직접 테스트할 수 없습니다.
29 | - 중첩은 외부함수를 더 길고 읽기 어렵게 만들 수 있습니다.
30 |
31 |
32 |
33 | #### 2.6.4 결론
34 |
35 | - 몇가지 주의사항을 지키면 사용해도 괜찮습니다.
36 | - `self` 나 `cls`를 제외한 local value을 접근할 때 중첩함수나 중첩 클래스 사용을 피하세요.
37 | - 단순히 모듈 내 함수를 사용자들에게 숨기기 위해 중첩하지마세요. 대신, 모듈 수준에서 이름 앞에 \_을 붙여 test가 접근할 수 있게 하세요.
38 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.7 list_comprehensions.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ### 2.7 Comprehensions & 제너레이터 표현식
5 |
6 | - 복잡하지 않은 상황에서 사용하세요.
7 |
8 |
9 |
10 | #### 2.7.1 정의
11 |
12 | - 리스트와 딕셔너리, Set comprehensions, 제너레이터 표현식은 오래전부터 사용되어 왔던 반복문이나, `map()`, `filter()`, `lambda`를 사용하지 않고도 container 타입과 iterator를 만들때 간결하고 효율적인 방법을 제공합니다.
13 |
14 |
15 |
16 | #### 2.7.2 장점
17 |
18 | - 간단한 comprehension은 다른 딕셔너리나 리스트, set을 만드는 기술보다 명확하고 간단합니다.
19 | - 제너레이터 표현식은 리스트 전체를 만드는 것이 아니여서 매우 효율적입니다.
20 |
21 |
22 |
23 | #### 2.7.3 단점
24 |
25 | - 복잡한 comprehension이나 제너레이터 표현식은 읽기 힘듭니다.
26 |
27 |
28 |
29 | #### 2.7.4 결론
30 |
31 | - 컴프리헨션(comprehension)은 허용되지만, 여러 개의 for 절이나 필터 표현식은 허용되지 않습니다. 간결함보다는 가독성을 우선시하세요.
32 | - 올바른 예
33 |
34 | ```python
35 | result = [mapping_expr for value in iterable if filter_expr]
36 |
37 | result = [
38 | is_valid(metric={'key': value})
39 | for value in interesting_iterable
40 | if a_longer_filter_expression(value)
41 | ]
42 |
43 | descriptive_name = [
44 | transform({'key': key, 'value': value}, color='black')
45 | for key, value in generate_iterable(some_input)
46 | if complicated_condition_is_met(key, value)
47 | ]
48 |
49 | result = []
50 | for x in range(10):
51 | for y in range(5):
52 | if x * y > 10:
53 | result.append((x, y))
54 | return {
55 | x: complicated_transform(x)
56 | for x in long_generator_function(parameter)
57 | if x is not None
58 | }
59 | return (x**2 for x in range(10))
60 |
61 | unique_names = {user.name for user in users if user is not None}
62 | ```
63 |
64 | - 부적절한 예
65 |
66 | ```python
67 | result = [(x, y) for x in range(10) for y in range(5) if x * y > 10]
68 |
69 | return (
70 | (x, y, z)
71 | for x in range(5)
72 | for y in range(5)
73 | if x != y
74 | for z in range(5)
75 | if y != z
76 | )
77 | ```
78 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.8 기본 반복자와 연산자.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.8 기본 반복자와 연산자
4 |
5 | - 리스트나 딕셔너리, 파일등의 타입등에서 기본 반복자와 연산자를 지원하는 경우에 사용하세요.
6 |
7 |
8 |
9 | #### 2.8.1 정의
10 |
11 | - 딕셔너리나 리스트같은 컨테이너 타입은 기본 반복자와 ("in" 과 "not in")같은 멤버 연산자를 정의합니다.
12 |
13 |
14 |
15 | #### 2.8.2 장점
16 |
17 | - 기본 반복자와 연산자는 간단하고 효율적입니다. 추가적인 메소드를 호출하지 않고 연산자를 직접 표현합니다.
18 | - 제네릭은 기본 연산자를 사용한 함수입니다. 연산자를 지원해주는 어떠한 타입에서도 사용할 수 있습니다.
19 |
20 |
21 |
22 | #### 2.8.3 단점
23 |
24 | - 메소드 이름을 읽어도 객체의 타입을 유추할 수 없습니다.(변수에 타입 주석이 없는 경우) 이건 이점이 될 수도 있습니다.
25 |
26 |
27 |
28 | #### 2.8.4 결론
29 |
30 | - 리스트와 딕셔너리, 파일과 같은 연산자를 지원해주는 타입에서 기본 반복자와 연산자를 사용하세요.
31 | - built-in 타입은 iterator 메서드도 정의합니다.
32 | - 컨테이너를 반복하는 동안 컨테이너를 변경해서는 안 된다는 점을 제외하고 list를 반환하는 메서드보다 이러한 메서드를 선호합니다.
33 | - 올바른 예
34 |
35 | ```python
36 | for key in adict: ...
37 | if obj in alist: ...
38 | for line in afile: ...
39 | for k, v in adict.items(): ...
40 | ```
41 |
42 | - 부적절한 예
43 |
44 | ```python
45 | for key in adict.keys(): ...
46 | for line in afile.readlines(): ...
47 | ```
48 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/2.9 제너레이터.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.9 제너레이터
4 |
5 | - 필요에 따라 제너레이터를 사용하세요.
6 |
7 |
8 |
9 | #### 2.9.1 정의
10 |
11 | - 제너레이터 함수는 yield문을 실행할때마다 값을 생성해주는 반복자를 반환합니다.
12 | - 값을 계산한 다음, 제너레이터 함수의 runtime 상태는 다음 값이 필요해질 때 까지 정지됩니다.
13 |
14 |
15 |
16 | #### 2.9.2 장점
17 |
18 | - 지역변수의 상태와 제어 흐름은 각 호출을 보존되기 때문에 코드가 단순합니다.
19 | - 제너레이터의 사용은 전체 리스트의 값을 단 한번 생성하기 때문에 함수를 사용하는 것보다 메모리를 적게 사용합니다.
20 |
21 |
22 |
23 | #### 2.9.3 단점
24 |
25 | - 제너레이터 내의 지역 변수는 제너레이터가 모두 소모되거나 자체적으로 가비지 컬렉션될 때까지 가비지 컬렉션되지 않습니다.
26 |
27 |
28 |
29 | #### 2.9.4 결론
30 |
31 | - 제너레이터 함수에서 docstring에 대해 "Returns:"보다 "Yields:"를 사용하세요.
32 | - 제너레이터가 비용이 많이 드는 자원을 관리하는 경우, 정리 작업을 강제로 수행해야 합니다.
33 | - 정리 작업을 잘 수행하는 방법 중 하나는 제너레이터를 컨텍스트 매니저로 감싸는 것입니다 ([PEP-0533](https://peps.python.org/pep-0533/)).
34 |
--------------------------------------------------------------------------------
/Google Python Style Guide/2. Python 언어 규칙/ReadMe.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 2.1 Lint
4 |
5 | - 이 [pylintrc](https://google.github.io/styleguide/pylintrc)를 사용하여 코드에서 `pylint`를 실행합니다.
6 |
7 |
8 |
9 | #### 2.1.1 정의
10 |
11 | - `pylint`는 파이썬 소스코드에서 버그와 스타일 문제를 찾기 위한 툴입니다. (`pylint`는 빌나 컴파일 시 에러 외에 `추가`로 오류검사를 할 수 있는 도구라고 생각하면 될 것 같습니다.)
12 | - 일반적으로 C나 C++와 같은 비동적 프로그래밍 언어에서의 컴파일러를 통해 잡히는 문제를 찾아냅니다.
13 | - 파이썬의 동적인 특성때문에 몇몇 경고들은 정확하지 않을 수 있지만 드물게 발생합니다.
14 |
15 |
16 |
17 | #### 2.1.2 장점
18 |
19 | - 오타와 같은 놓치기 쉬운 에러나 할당이 되지 않은 변수 사용 등의 에러를 쉽게 잡을 수 있습니다.
20 |
21 |
22 |
23 | #### 2.1.3 단점
24 |
25 | - `pylint`는 완벽하지 않습니다.
26 | - `pylint`를 이용하기 위해 다음과 같은 사항들을 따라야 합니다.
27 | - 주위에 작성한다.
28 | - 경고를 억제한다.
29 | - 그것을 개선한다.
30 |
31 |
32 |
33 | #### 2.1.4 결론
34 |
35 | - 코드에 `pylint`를 실행시키세요.
36 |
37 | - 다른 문제가 가려지지 않도록 경고가 부적절할 경우 경고를 띄우지 마세요.
38 | - 경고를 띄우지 않기 위해, 코드에 라인 단위로 주석을 달아야 합니다.
39 |
40 | ```python
41 | def do_PUT(self): # WSGI name, so pylint: disable=invalid-name
42 | ...
43 | ```
44 |
45 | - `pylint`의 경고는 각각 symbolic name(`empty-docstring`)으로 구별됩니다.
46 | - Google-specific 경고는 `g-`로 시작합니다.
47 | - symbolic name에서 경고를 억제한 이유가 명확하지 않으면 설명을 추가해야 합니다.
48 | - 이러한 방식으로 경고를 억제하면 쉽게 경고를 억제한 것들을 찾을 수 있는 이점이 있습니다.
49 | - `pylint`의 경고 리스트를 다음과 같은 방법으로 볼 수 있습니다.
50 |
51 | ```shell
52 | pylint --list-msgs
53 | ```
54 |
55 | - 각 메시지에 대해 자세한 정보를 얻고자 하는 경우 다음과 같은 방법으로 볼 수 있습니다.
56 |
57 | ```shell
58 | pylint --help-msg=invalid-name
59 | ```
60 |
61 | - `pyling: disable-msg`는 이전에 사용했던 방식으로 이제는 사용되지 않으며 `pylint: disable`를 사용합니다.
62 | - 사용되지 않는 인자에 대한 경고는 함수를 시작할 때 그 변수를 지움으로써 억제할 수 있습니다. 다만 그 변수를 왜 지웠는지에 대해 항상 주석으로 설명을 추가해야 합니다. 이러한 경우는 "Unused."라고 작성하면 충분합니다.
63 | - 아래 예시를 참고하세요.
64 |
65 | ```python
66 | def viking_cafe_order(spam: str, beans: str, eggs: str | None = None) -> str:
67 | del beans, eggs # Unused by vikings.
68 | return spam + spam + spam
69 | ```
70 |
71 | - 경고를 없애는 방법은 일반적인 형태로 사용되지 않은 인자의 이름으로 `_`를 사용하거나 이름에 `unused_`를 붙이거나 `_`으로 할당하는 것입니다. 이러한 형태는 허용되지만 권장하지 않습니다. break caller는 이름으로 인수를 전달하고 인수가 실제로 사용되지 않도록 강제하지 않습니다.
72 |
73 | ---
74 |
75 |
76 | ### 2.2 Imports
77 |
78 | - `import`문은 개별 타입, 클래스, 함수가 아니라 패키지와 모듈에만 사용하세요. (주: 개별 타입은 기본 자료형, 사용자 정의 클래스를 나타냅니다.)
79 |
80 |
81 |
82 | #### 2.2.1 정의
83 |
84 | - 하나의 모듈에서 다른 모듈로 코드를 공유하는 재사용 매커니즘 입니다.
85 |
86 |
87 |
88 | #### 2.2.2 장점
89 |
90 | - namespace management convention(이름을 짓는 방식)은 간단합니다. 각각 식별된 소스는 하나의 일관된 방식으로 작성됩니다. `x.Obj` 는 모듈 `x` 에 정의된 객체 `Obj` 를 의미합니다.
91 |
92 |
93 |
94 | #### 2.2.3 단점
95 |
96 | - 모듈 이름이 충돌할 수도 있습니다. 몇몇 모듈 이름은 불편할 정도로 깁니다.
97 |
98 |
99 |
100 | #### 2.2.4 결론
101 |
102 | - `import x`를 패키지와 모듈을 import할때 사용하세요.
103 | - `from x import y`를 `x`가 패키지의 접두어이고 `y`가 접두어가 없는 모듈일때 사용하세요.
104 | - 다음과 같은 상황에서는 `from x import y as z` 를 사용하세요.
105 | - `y`라는 이름을 가진 두 개의 모듈을 가져옵니다.
106 | - `y`는 현재 모듈에 정의된 최상위 이름과 충돌합니다.
107 | - `y`는 공개 API의 일부인 공통 매개변수 이름(예: 'features')과 충돌합니다.
108 | - `y`는 불편할 정도로 긴 이름입니다.
109 | - `y`는 코드 컨텍스트에서 너무 일반적입니다(예: `from storage.file_system import options as fs_options`).
110 | - `import y as z`를 `z` 가 공식적인 약어인 경우에만 사용하세요(e.g., `import numpy as np`)
111 |
112 | - 예를들어 `sound.effects.echo`모듈이 import 된다면 아래와 같습니다.
113 |
114 | ```python
115 | from sound.effects import echo
116 | ...
117 | echo.EchoFilter(input, output, delay=0.7, atten=4)
118 | ```
119 |
120 | - import된것들과 관련있는 이름을 사용하지마세요.
121 | - 모듈이 같은 패키지에 있더라도 전체 패키지 이름을 사용하세요.
122 | - 이는 무심코 패키지를 두번 import 하는것을 예방하는 것에 도움이 됩니다.
123 |
124 |
125 |
126 | ##### 2.2.4.1 예외
127 |
128 | - 이 규칙의 예외는 다음과 같습니다.
129 | - 다음 모듈의 심볼은 정적 분석 및 타입 검사를 지원하는 데 사용됩니다.
130 | - [`typing` module](#typing-imports)
131 | - [`collections.abc` module](#typing-imports)
132 | - [`typing_extensions` module](https://github.com/python/typing_extensions/blob/main/README.md)
133 | - [six.moves module](https://six.readthedocs.io/#module-six.moves)의 리다이렉션입니다.
134 |
135 | ---
136 |
137 |
138 | ### 2.3 Packages
139 |
140 | - 각각의 모듈은 그 모듈의 전체 경로 위치를 사용하여 import합니다.
141 |
142 |
143 |
144 | #### 2.3.1 장점
145 |
146 | - module 이름의 충돌이나 작성자가 예상하지 못한 module search path으로 인한 잘못된 import를 방지합니다.
147 | - 모듈을 쉽게 찾을 수 있도록 해줍니다.
148 |
149 |
150 |
151 | #### 2.3.2 단점
152 |
153 | - 패키지 계층을 복제해야 하므로 코드를 배포하기 어렵습니다. 다만 현대적 배포 매커니즘에서는 문제될게 없습니다.
154 |
155 |
156 |
157 | #### 2.3.3 결론
158 |
159 | - 모든 새로운 코드는 그 코드의 전체 패키지 이름으로 각각의 모듈을 import해야합니다.
160 | - Import는 아래 사항을 따라야 합니다.
161 |
162 | - 올바른 예
163 |
164 | ```python
165 | # Reference absl.flags in code with the complete name (verbose).
166 | import absl.flags
167 | from doctor.who import jodie
168 |
169 | _FOO = absl.flags.DEFINE_string(...)
170 | ```
171 |
172 | ```python
173 | # Reference flags in code with just the module name (common).
174 | from absl import flags
175 | from doctor.who import jodie
176 |
177 | _FOO = flags.DEFINE_string(...)
178 | ```
179 |
180 | - 부적절한 예 _(이 파일은 `doctor/who/` 에 있다고 가정하고 `jodie.py`또한 존재한다고 가정합니다.)_
181 |
182 | ```python
183 | # Unclear what module the author wanted and what will be imported. The actual
184 | # import behavior depends on external factors controlling sys.path.
185 | # Which possible jodie module did the author intend to import?
186 | import jodie
187 | ```
188 |
189 | - 메인 바이너리 디렉토리는 몇몇 환경에서 발생했음에도 불구하고`sys.path`에 있다고 예측하면 안됩니다.
190 | - 이러한 상황에서 코드는 `import jodie`는 파일로 된 `jodie.py`가 아닌 써드파티나 탑 레벨 패키지 이름이 `jodie`라고 참조한다고 가정해야합니다.
191 |
192 | ---
193 |
194 |
195 | ### 2.4 예외
196 |
197 | - 예외는 허용하지만 주의하며 사용해야합니다.
198 |
199 |
200 |
201 | #### 2.4.1 정의
202 |
203 | - 예외는 코드블록에서 정상적인 상황에 발생한 에러나 다른 예외적인 상황을 다루기 위해 정상적인 흐름에서 벗어나는것을 의미합니다.
204 |
205 |
206 |
207 | #### 2.4.2 장점
208 |
209 | - 일반적인 연산자에 대한 제어흐름은 에러 핸들링 코드에 의해 난잡해지지 않습니다.
210 | - 특정 조건이 발생했을 때 제어 흐름이 몇몇 프레임들을 생략할 수 있습니다.
211 | - 예를 들어, 에러 코드를 살펴보는 것 대신 한 번에 N개의 중첩 함수로부터 반환합니다.
212 |
213 |
214 |
215 | #### 2.4.3 단점
216 |
217 | - 제어 흐름이 혼란스러워질 수 있습니다. 라이브러리를 호출할때 에러 상황들을 놓치기 쉽습니다.
218 |
219 |
220 |
221 | #### 2.4.4 결론
222 |
223 | ##### 예외는 다음과 같은 조건을 만족해야 합니다
224 |
225 | - 내장 예외 클래스를 사용하는 데에 문제가 없다면 사용합니다. 예를 들어, 함수 인자를 검증할 때와 같은 프로그래밍 오류나 위반된 전제조건을 나타내기 위해 `ValueError`를 발생시키세요.
226 | - `assert` 문을 조건문이나 전제조건 검증 대신 사용하지 마세요. application logic에 중요하지 않아야 합니다. `assert`문을 제거해도 코드가 정상적으로 작동한다면, 그것이 기준이 될 수 있습니다. assert 조건문은 평가될 것이라고 [보장되지 않습니다](https://docs.python.org/3/reference/simple_stmts.html#the-assert-statement). [pytest](https://pytest.org)기반의 테스트에서는 `assert` 문을 사용하여 기대값을 검증하는 것이 적절하고 예상됩니다
227 |
228 | - 올바른 예
229 |
230 | ```python
231 | def connect_to_next_port(self, minimum: int) -> int:
232 | """Connects to the next available port.
233 |
234 | Args:
235 | minimum: A port value greater or equal to 1024.
236 | Raises:
237 | ValueError: If the minimum port specified is less than 1024.
238 | ConnectionError: If no available port is found.
239 | Returns:
240 | The new minimum port.
241 | """
242 | if minimum < 1024:
243 | raise ValueError(f'Min. port must be at least 1024, not {minimum}.')
244 | port = self._find_next_open_port(minimum)
245 | if port is None:
246 | raise ConnectionError(
247 | f'Could not connect to service on port {minimum} or higher.')
248 | # 이 코드의 결과는 이 assert에 의존하지 않습니다.
249 | assert port >= minimum, (
250 | f'Unexpected port {port} when minimum was {minimum}.')
251 | return port
252 | ```
253 |
254 | - 부적절한 예
255 |
256 | ```python
257 | def connect_to_next_port(self, minimum: int) -> int:
258 | """Connects to the next available port.
259 |
260 | Args:
261 | minimum: A port value greater or equal to 1024.
262 | Returns:
263 | The new minimum port.
264 | """
265 | assert minimum >= 1024, 'Minimum port must be at least 1024.'
266 | # 이 코드는 이전 assert에 의존합니다.
267 | port = self._find_next_open_port(minimum)
268 | assert port is not None
269 | # 반환 값에 대한 타입 검사는 assert에 의존합니다.
270 | return port
271 | ```
272 |
273 | - 라이브러리나 패키지는 고유의 예외가 정의되어 있을 것입니다.
274 | - 사용하는 동안, 기존에 존재하는 예외 클래스(exception class)로부터 상속을 받아야 합니다.
275 | - 예외 이름은 `Error`로 끝나야 하고 되풀이로 시작하면 안됩니다.(`foo.fooError`).
276 | - 예외를 다시 발생시키거나 쓰레드의 가장 바깥 쪽 블록에 있지않으면 절대 포괄적인 `except:`문을 사용하거나 `Exception`, `StandardError`을 사용하지마세요. (그리고 에러메시지를 출력하세요.) Python은 이와 관련해서 매우 관용적이며 `except:` 모든 오탈자를 비롯하여, sys.exit() 호출, Ctrl+C로 인한 인터럽트, 유닛테스트 실패와 마지막으로 당신이 포착을 원하지 않았던 다른 모든 종류의 예외들까지 모두 잡아낼 것입니다.
277 | - 코드상에서 `try`/`except` 블록의 수를 최소화시키세요. `try`문의 내부가 커질수록 예외는 당신이 예외가 발생할것이라 예상하지 않았던 코드에 의해 점점 더 발생할 것입니다. 이러한 상황에서, `try`/`except` 블록은 진짜 검출해야 할 에러를 가리게 됩니다.
278 | - 예외가 `try` 블록에서 발생하던 안하던 `finally`절은 코드를 실행시킨다. 이건 가끔 깔끔히 하는데 유용합니다. 예를들어, 파일을 닫을 때 가 그 예입니다.
279 |
280 | ---
281 |
282 |
283 |
284 |
285 |
286 | ### 2.5 변경 가능한 전역 상태
287 |
288 | - 변경 가능한 전역 상태를 사용하지 마세요.
289 |
290 |
291 |
292 | #### 2.5.1 정의
293 |
294 | - 프로그램 실행 중 변경될 수 있는 모듈 수준의 값이나 클래스 속성을 말합니다.
295 |
296 |
297 |
298 | #### 2.5.2 장점
299 |
300 | - 가끔 편리합니다.
301 |
302 |
303 |
304 |
305 |
306 | #### 2.5.3 단점
307 |
308 | - 캡슐화가 깨집니다.
309 | - 이러한 설계는 유효한 목표를 달성하기 어렵게 만들 수 있습니다. 예를 들면, 전역 상태를 사용하여 데이터베이스 연결을 관리하는 경우, 두 개의 서로 다른 데이터베이스를 동시에 연결하는 것이 어려워질 수 있습니다(e.g., 마이그레이션 중 차이를 계산할 때). 전역 레지스트리에서도 유사한 문제가 쉽게 발생할 수 있습니다.
310 | - 모듈이 처음 임포트될 때 전역 변수에 대한 할당이 이루어지기 때문에, 모듈의 동작을 임포트 중에 변경할 가능성이 있습니다.
311 |
312 |
313 |
314 |
315 |
316 | #### 2.5.4 결론
317 |
318 | - 변경 가능한 전역 상태를 사용하지 마세요.
319 | - 전역 상태를 사용하는 것이 드물게 필요한 경우, 변경 가능한 전역 엔티티는 모듈 수준이나 클래스 속성으로 선언하고, 이름 앞에 `_`를 붙여 내부적으로 사용해야 합니다. 필요한 경우, 변경 가능한 전역 상태에 대한 외부 접근은 공개 함수나 클래스 메소드를 통해 이루어져야 합니다. [Naming](#s3.16-naming)를 참고하세요. 변경 가능한 전역 상태를 사용하는 설계 이유에 대해서는 주석에 설명하거나 링크된 문서에서 설명해 주세요.
320 | - 모듈 수준의 상수는 허용되며 권장됩니다. 예를 들어, 내부 용도의 상수에는 `_MAX_HOLY_HANDGRENADE_COUNT = 3`를 사용하고, Public API 상수에는 `SIR_LANCELOTS_FAVORITE_COLOR = "blue"`를 사용하세요. 상수는 모두 대문자와 밑줄을 사용하여 명명해야 합니다. [Naming](#s3.16-naming)를 참고하세요.
321 |
322 | ---
323 |
324 |
325 | ### 2.6 중첩/지역/내부 클래스와 함수
326 |
327 | - 중첩된 지역 함수나 클래스는 지역변수에 접근할 때 사용하면 좋습니다.
328 | - 내부클래스에서는 괜찮습니다.
329 |
330 |
331 |
332 | #### 2.6.1 정의
333 |
334 | - 클래스는 메소드, 함수, 클래스 내에서 정의할 수 있습니다.
335 | - 함수는 메서드나 함수 내에서 정의할 수 있습니다.
336 | - 중첩함수는 해당 스코프에 정의된 변수를 읽기만 가능합니다.
337 |
338 |
339 |
340 | #### 2.6.2 장점
341 |
342 | - 제한된 스코프 내에서 사용하는 유틸리티 클래스와 함수의 정의를 허용합니다.
343 | - [ADT](https://ko.wikipedia.org/wiki/추상_자료형)가 무엇인지 참고하세요.
344 | - 일반적으로 데코레이터를 구현할 때 사용됩니다.
345 |
346 |
347 |
348 | #### 2.6.3 단점
349 |
350 | - 중첩된 함수와 클래스는 직접 테스트할 수 없습니다.
351 | - 중첩은 외부함수를 더 길고 읽기 어렵게 만들 수 있습니다.
352 |
353 |
354 |
355 | #### 2.6.4 결론
356 |
357 | - 몇가지 주의사항을 지키면 사용해도 괜찮습니다.
358 | - `self` 나 `cls`를 제외한 local value을 접근할 때 중첩함수나 중첩 클래스 사용을 피하세요.
359 | - 단순히 모듈 내 함수를 사용자들에게 숨기기 위해 중첩하지마세요. 대신, 모듈 수준에서 이름 앞에 \_을 붙여 test가 접근할 수 있게 하세요.
360 |
361 | ---
362 |
363 |
364 |
365 | ### 2.7 Comprehensions & 제너레이터 표현식
366 |
367 | - 복잡하지 않은 상황에서 사용하세요.
368 |
369 |
370 |
371 | #### 2.7.1 정의
372 |
373 | - 리스트와 딕셔너리, Set comprehensions, 제너레이터 표현식은 오래전부터 사용되어 왔던 반복문이나, `map()`, `filter()`, `lambda`를 사용하지 않고도 container 타입과 iterator를 만들때 간결하고 효율적인 방법을 제공합니다.
374 |
375 |
376 |
377 | #### 2.7.2 장점
378 |
379 | - 간단한 comprehension은 다른 딕셔너리나 리스트, set을 만드는 기술보다 명확하고 간단합니다.
380 | - 제너레이터 표현식은 리스트 전체를 만드는 것이 아니여서 매우 효율적입니다.
381 |
382 |
383 |
384 | #### 2.7.3 단점
385 |
386 | - 복잡한 comprehension이나 제너레이터 표현식은 읽기 힘듭니다.
387 |
388 |
389 |
390 | #### 2.7.4 결론
391 |
392 | - 컴프리헨션(comprehension)은 허용되지만, 여러 개의 for 절이나 필터 표현식은 허용되지 않습니다. 간결함보다는 가독성을 우선시하세요.
393 | - 올바른 예
394 |
395 | ```python
396 | result = [mapping_expr for value in iterable if filter_expr]
397 |
398 | result = [
399 | is_valid(metric={'key': value})
400 | for value in interesting_iterable
401 | if a_longer_filter_expression(value)
402 | ]
403 |
404 | descriptive_name = [
405 | transform({'key': key, 'value': value}, color='black')
406 | for key, value in generate_iterable(some_input)
407 | if complicated_condition_is_met(key, value)
408 | ]
409 |
410 | result = []
411 | for x in range(10):
412 | for y in range(5):
413 | if x * y > 10:
414 | result.append((x, y))
415 | return {
416 | x: complicated_transform(x)
417 | for x in long_generator_function(parameter)
418 | if x is not None
419 | }
420 | return (x**2 for x in range(10))
421 |
422 | unique_names = {user.name for user in users if user is not None}
423 | ```
424 |
425 | - 부적절한 예
426 |
427 | ```python
428 | result = [(x, y) for x in range(10) for y in range(5) if x * y > 10]
429 |
430 | return (
431 | (x, y, z)
432 | for x in range(5)
433 | for y in range(5)
434 | if x != y
435 | for z in range(5)
436 | if y != z
437 | )
438 | ```
439 |
440 | ---
441 |
442 |
443 | ### 2.8 기본 반복자와 연산자
444 |
445 | - 리스트나 딕셔너리, 파일등의 타입등에서 기본 반복자와 연산자를 지원하는 경우에 사용하세요.
446 |
447 |
448 |
449 | #### 2.8.1 정의
450 |
451 | - 딕셔너리나 리스트같은 컨테이너 타입은 기본 반복자와 ("in" 과 "not in")같은 멤버 연산자를 정의합니다.
452 |
453 |
454 |
455 | #### 2.8.2 장점
456 |
457 | - 기본 반복자와 연산자는 간단하고 효율적입니다. 추가적인 메소드를 호출하지 않고 연산자를 직접 표현합니다.
458 | - 제네릭은 기본 연산자를 사용한 함수입니다. 연산자를 지원해주는 어떠한 타입에서도 사용할 수 있습니다.
459 |
460 |
461 |
462 | #### 2.8.3 단점
463 |
464 | - 메소드 이름을 읽어도 객체의 타입을 유추할 수 없습니다.(변수에 타입 주석이 없는 경우) 이건 이점이 될 수도 있습니다.
465 |
466 |
467 |
468 | #### 2.8.4 결론
469 |
470 | - 리스트와 딕셔너리, 파일과 같은 연산자를 지원해주는 타입에서 기본 반복자와 연산자를 사용하세요.
471 | - built-in 타입은 iterator 메서드도 정의합니다.
472 | - 컨테이너를 반복하는 동안 컨테이너를 변경해서는 안 된다는 점을 제외하고 list를 반환하는 메서드보다 이러한 메서드를 선호합니다.
473 | - 올바른 예
474 |
475 | ```python
476 | for key in adict: ...
477 | if obj in alist: ...
478 | for line in afile: ...
479 | for k, v in adict.items(): ...
480 | ```
481 |
482 | - 부적절한 예
483 |
484 | ```python
485 | for key in adict.keys(): ...
486 | for line in afile.readlines(): ...
487 | ```
488 |
489 | ---
490 |
491 |
492 | ### 2.9 제너레이터
493 |
494 | - 필요에 따라 제너레이터를 사용하세요.
495 |
496 |
497 |
498 | #### 2.9.1 정의
499 |
500 | - 제너레이터 함수는 yield문을 실행할때마다 값을 생성해주는 반복자를 반환합니다.
501 | - 값을 계산한 다음, 제너레이터 함수의 runtime 상태는 다음 값이 필요해질 때 까지 정지됩니다.
502 |
503 |
504 |
505 | #### 2.9.2 장점
506 |
507 | - 지역변수의 상태와 제어 흐름은 각 호출을 보존되기 때문에 코드가 단순합니다.
508 | - 제너레이터의 사용은 전체 리스트의 값을 단 한번 생성하기 때문에 함수를 사용하는 것보다 메모리를 적게 사용합니다.
509 |
510 |
511 |
512 | #### 2.9.3 단점
513 |
514 | - 제너레이터 내의 지역 변수는 제너레이터가 모두 소모되거나 자체적으로 가비지 컬렉션될 때까지 가비지 컬렉션되지 않습니다.
515 |
516 |
517 |
518 | #### 2.9.4 결론
519 |
520 | - 제너레이터 함수에서 docstring에 대해 "Returns:"보다 "Yields:"를 사용하세요.
521 | - 제너레이터가 비용이 많이 드는 자원을 관리하는 경우, 정리 작업을 강제로 수행해야 합니다.
522 | - 정리 작업을 잘 수행하는 방법 중 하나는 제너레이터를 컨텍스트 매니저로 감싸는 것입니다 ([PEP-0533](https://peps.python.org/pep-0533/)).
523 |
524 | ---
525 |
526 |
527 | ### 2.10 람다 함수
528 |
529 | - 한 줄 작성에 사용하세요.
530 | - `lambda`에는 `map()` 또는 `filter()` 보다 제너레이터 구문이 더 적합합니다
531 |
532 |
533 |
534 | #### 2.10.1 정의
535 |
536 | - 람다는 표현에 있어 다른 `문` 과는 달리 익명 함수들을 정의합니다.
537 |
538 |
539 |
540 | #### 2.10.2 장점
541 |
542 | - 편리합니다.
543 |
544 |
545 |
546 | #### 2.10.3 단점
547 |
548 | - 로컬 함수에 비해 읽기 어렵고 디버깅이 힘듭니다. 이름이 없다는 것은 stack trace를 이해하기 어렵다는 것입니다.
549 | - 함수에는 오직 표현식만 담을 수 있어 표현이 제한됩니다.
550 |
551 |
552 |
553 | #### 2.10.4 결론
554 |
555 | - 람다 함수는 허용하지만, 람다 함수 내부의 코드가 여러 줄에 걸치거나 60-80자를 넘는 경우, 일반적인 [중첩 함수](#s2.16-lexical-scoping)로 정의하는 것이 더 나을 수 있습니다.
556 | - 곱셈 같은 일반 연산자에서는 `operator`모듈 대신에 람다 함수를 사용하세요.
557 | - 예를 들어, `operator.mul`을 `lambda x,y : x * y` 처럼 사용하시면 됩니다.
558 |
559 | ---
560 |
561 |
562 | ### 2.11 조건문 표현
563 |
564 | - 간단한 상황에 좋습니다.
565 |
566 |
567 |
568 | #### 2.11.1 정의
569 |
570 | - 조건식(삼항 연산자)은 if 문을 더 짧은 구문으로 사용하는 방법입니다. (e.g, `x = 1 if cond else 2`)
571 |
572 |
573 |
574 | #### 2.11.2 장점
575 |
576 | - if 문보다 짧고 편리합니다.
577 |
578 |
579 |
580 | #### 2.11.3 단점
581 |
582 | - if 문보다 읽기가 어려울 수 있습니다. 표현이 길어지면 조건을 찾기가 어려울 수 있습니다.
583 |
584 |
585 |
586 | #### 2.11.4 결론
587 |
588 | - 간단한 상황에 좋습니다. 그 외의 경우에는 if 문을 사용하는 것이 좋습니다.
589 | - `true-false`, `if-else` 표현 등 각각의 코드가 반드시 한 줄에 표현되어야 합니다.
590 | - 보다 복잡한 구문이 필요하다면 `lambda`가 아닌 완전한 `if` 구문을 사용하세요.
591 |
592 | ```python
593 |
594 | 올바른 예:
595 | one_line = 'yes' if predicate(value) else 'no'
596 | slightly_split = ('yes' if predicate(value)
597 | else 'no, nein, nyet')
598 | the_longest_ternary_style_that_can_be_done = (
599 | 'yes, true, affirmative, confirmed, correct'
600 | if predicate(value)
601 | else 'no, false, negative, nay')
602 |
603 | 잘못된 예:
604 | bad_line_breaking = ('yes' if predicate(value) else
605 | 'no')
606 | portion_too_long = ('yes'
607 | if some_long_module.some_long_predicate_function(
608 | really_long_variable_name)
609 | else 'no, false, negative, nay')
610 |
611 | ```
612 | ---
613 |
614 |
615 | ### 2.12 기본 인자 값
616 |
617 | - 대부분은 사용해도 됩니다.
618 |
619 |
620 |
621 | #### 2.12.1 정의
622 |
623 | - 함수의 매개변수 목록 끝에 있는 변수에 대한 값을 지정할 수 있습니다.
624 | - 예) `def foo(a, b=0):` 라는 함수의 경우에 만약 `foo`를 하나의 인자값으로 호출한다면 `b`의 값은 0으로 설정됩니다. 만약에 두 개의 인자값이라면 `b`의 값은 두 번째 인자값을 가지게 됩니다.
625 |
626 |
627 |
628 | #### 2.12.2 장점
629 |
630 | - 기본값을 많이 가지는 함수는 있지만, 기본값을 재정의하는 경우는 거의 없습니다.
631 | - 기본 인자값을 사용하면 드문 예외에 대해 많은 함수를 정의할 필요 없이 쉽게 처리할 수 있습니다.
632 | - 또한, Python은 매서드/함수에 대해 Overloading을 지원하지 않으므로 기본 인자값을 사용하면 쉽게 Overloading를 사용하는 것처럼 할 수 있습니다.
633 |
634 |
635 |
636 | #### 2.12.3 단점
637 |
638 | - 기본 인자값은 모듈이 불러올 때 한번 계산됩니다.
639 | - 인자값이 list나 dictionary 같은 경우 변형이 가능한 Object이면 문제를 일으킬 수 있습니다.
640 | - 만약에 함수가 Object를 수정하는 경우(list에 item을 추가하는 경우) 기본값이 수정됩니다.
641 |
642 | - 예시
643 |
644 | ```python
645 | def foo(b=[]):
646 | b.append(1)
647 | return b
648 | foo() # b = [1]
649 | foo() # b = [1, 1]
650 | print(foo()) # [1, 1, 1]
651 | ```
652 |
653 |
654 |
655 | #### 2.12.4 결론
656 |
657 | - 다음 주의사항과 함께 사용할 수 있습니다.
658 | - 함수 또는 메서드 정의할 때 `변할 수 있는 Object`를 기본값으로 사용하지 마세요.
659 | - 올바른 예
660 |
661 | ```python
662 | def foo(a, b=None):
663 | if b is None:
664 | b = []
665 | def foo(a, b: Sequence | None = None):
666 | if b is None:
667 | b = []
668 | def foo(a, b: Sequence = ()): # tuples은 불변하기 때문에 사용 가능합니다.
669 | ...
670 | ```
671 |
672 | - 부적절한 예
673 |
674 | ```python
675 | from absl import flags
676 | _FOO = flags.DEFINE_string(...)
677 |
678 | def foo(a, b=[]):
679 | ...
680 | def foo(a, b=time.time()): # `b`가 이 모듈이 로드된 시간을 나타내는 것인가요?
681 | ...
682 | def foo(a, b=_FOO.value): # sys.argv는 아직 구문 분석되지 않았습니다...
683 | ...
684 | def foo(a, b: Mapping = {}): # 확인되지 않은 코드로 전달 될 수 있습니다.
685 | ...
686 | ```
687 |
688 | ---
689 |
690 |
691 | ### 2.13 Properties
692 |
693 | - `Properties`는 간단한 계산이나 로직이 필요한 attribute을 가져오거나 설정하는 것을 제어하는 데 사용될 수 있습니다.
694 | - `Properties` 구현은 보통의 attribute 접근에 대한 일반적인 기대와 일치되어야 합니다.
695 |
696 |
697 |
698 | #### 2.13.1 정의
699 |
700 | - 일반적인 속성을 접근하듯이 속성을 가져오거나 설정하는 메서드 호출을 포장하는 방법입니다.
701 |
702 |
703 |
704 | #### 2.13.2 장점
705 |
706 | - getter, setter method 호출 대신 attribute 접근 및 할당 API를 허용합니다.
707 | - attribute를 읽기 전용으로 만드는 데 사용할 수 있습니다.
708 | - [느긋한 계산법](https://ko.wikipedia.org/wiki/느긋한_계산법)을 허용합니다.
709 | - 내부가 class 사용자와 독립적으로 발전할 때 클레스의 public interface를 유지 관리하는 방법을 제공합니다.
710 |
711 |
712 |
713 | #### 2.13.3 단점
714 |
715 | - 연산자 오버 로딩(operator overloading)과 같은 부작용을 숨길 수 있습니다.
716 | - 하위 클래스의 경우 혼란스러울 수 있습니다.
717 |
718 |
719 |
720 | #### 2.13.4 결론
721 |
722 | - Properties는 허용하지만 연산자 오버로딩과 마찬가지로 필요한 경우에만 사용해야 하며 일반적인 attribute 접근에 대한 기대와 일치해야합니다
723 | - 그렇지 않은 경우에는 [getters and setters](#getters-and-setters)규칙을 따르세요.
724 | - 예를 들어, 단순히 attribute를 가져오고 설정하기 위해 property를 사용하는 것은 허용되지 않습니다.
725 | - 계산이 발생하지 않으므로 property는 불필요합니다. ([대신 attribute를 public으로 설정합니다.](#getters-and-setters))
726 | - 이에 비해 attribute 접근을 제어하거나 사소한 파생 값을 계산하기 위해 property를 사용하는 것은 허용됩니다.
727 | - 로직은 간단하고 놀랍지 않습니다.
728 | - Properties는 `@property` [decorator](#s2.17-function-and-method-decorators)를 사용하여 생성해야합니다.
729 | - property descriptor를 수동으로 구현하는 것은 [power feature](#power-features)로 간주됩니다.
730 | - 속성에 대한 상속은 명백하지 않을 수 있습니다. subclass가 재정의하고 확장하기 위한 계산 도구로 properties를 사용하지 마세요.
731 |
732 | ---
733 |
734 |
735 | ### 2.14 True/False 평가
736 |
737 | - 가능한 경우 "암묵적(implicit)" `false`를 사용하세요. (몇 가지 주의사항이 있지만)
738 |
739 |
740 |
741 | #### 2.14.1 정의
742 |
743 | - Python은 boolean문에서 특정 값을 `False`으로 평가합니다.
744 | - 빠른 "거짓의 법칙"은 모든 "비어있는" 값을 `False`으로 간주되므로 `0, None, [], {}, ''`은 boolean문에서는 `False`으로 평가합니다.
745 |
746 |
747 |
748 | #### 2.14.2 장점
749 |
750 | - Python boolean을 사용하면 읽기 쉽고 오류가 적고 대부분의 경우 빠릅니다.
751 |
752 |
753 |
754 | #### 2.14.3 단점
755 |
756 | - C/C++ 개발자들에게는 이상하게 보일 수도 있습니다.
757 |
758 |
759 |
760 | #### 2.14.4 결론
761 |
762 | - 가능하다면 "암묵적(implicit)" `False`를 사용하세요. (e.g. `if foo != []:` 보다는 `if foo:` 가 좋습니다.)
763 | - 그러나 몇가지 주의 사항을 명심해야합니다.
764 |
765 | - 항상 `if foo is None:`(혹은 `is not None`)을 통해 `None` 값을 확인하세요.
766 | - 예를 들어, 기본값이 `None`인 변수나 인자를 어떤 값으로 설정했는지 확인할 때, 어떤 값이 boolean의 `False` 값일 수 있습니다.
767 | - `==`를 사용해서 boolean 변수인 `False`와 비교하지 마세요. 대신 `if not x:`를 사용하세요. `False`와 `None`를 구별해야 할 경우 `if not x and is not None:`와 같은 식으로 연결하세요.
768 | - sequences(strings, lists, tuples)의 경우 빈 sequences는 `False`이므로 `if len(seq):` 혹은 `if not len(seq):` 보다 `if seq:` 혹은 `if not seq:`가 더 바람직합니다.
769 | - 정수(integer)를 처리할때, 암묵적(implicit) `False`는 이점보다 더 많은 위험을 가져올 수 있습니다(즉 `None`을 0으로 잘못 처리합니다.). (`len()`의 결과가 아닌)정수라고 알려진 값을 정수 0과 비교할 수 있습니다.
770 |
771 | - 올바른 예
772 |
773 | ```python
774 | if not users:
775 | print('사용자가 없습니다.')
776 |
777 | if i % 10 == 0:
778 | self.handle_multiple_of_ten()
779 |
780 | def f(x=None):
781 | if x is None:
782 | x = []
783 | ```
784 |
785 | - 부적절한 예
786 |
787 | ```python
788 | if len(users) == 0:
789 | print('사용자가 없습니다.')
790 |
791 | if not i % 10:
792 | self.handle_multiple_of_ten()
793 |
794 | def f(x=None):
795 | x = x or []
796 | ```
797 |
798 | - `'0'`(즉, `0` 문자열)은 참으로 평가한다는 점에 유의해야합니다.
799 | - Numpy 배열은 암시적 boolean 컨텍스트에서 예외를 발생시킬 수 있습니다. `np.array`의 비어 있음을 테스트할 때 `.size` attribute를 선호합니다. (e.g. `if not users.size`)
800 |
801 | ---
802 |
803 |
804 | ### 2.16 렉시컬 스코핑(Lexical Scoping)
805 |
806 | - 사용해도 좋습니다.
807 |
808 |
809 |
810 | #### 2.16.1 정의
811 |
812 | - 중첩된 Python 함수는 주변 함수에 정의된 변수를 참조할 수 있지만 할당할 수 없습니다.
813 | - 변수 바인딩은 렉시컬 스코핑(Lexical Scoping)를 사용하여 해결합니다. 즉, 정적 프로그램 텍스트를 기반으로 합니다.
814 | - 블록 내에 할당된 모든 이름은 Python이 해당 이름에 대한 모든 참조를 할당에 앞서 사용하더라도 로컬 변수로 처리하게 할 것입니다. 만약에 전역 변수가 발생하면 그 이름은 전역 변수로 취급합니다.
815 |
816 | - 이 기능에 대해 사용예는 다음과 같습니다.
817 |
818 | ```python
819 | def get_adder(summand1: float) -> Callable[[float], float]:
820 | """주어진 숫자에 숫자를 더하는 함수를 반환합니다."""
821 | def adder(summand2: float) -> float:
822 | return summand1 + summand2
823 |
824 | return adder
825 | ```
826 |
827 |
828 |
829 | #### 2.16.2 장점
830 |
831 | - 종종 명확하고 우아한 코드를 만들어냅니다. 특히 Lisp와 Scheme(그리고 Haskell, ML ...) 개발자들에게 위안을 줍니다.
832 |
833 |
834 |
835 | #### 2.16.3 단점
836 |
837 | - [PEP-0227](https://peps.python.org/pep-0227)을 기반으로 한 이 예시와 같이 혼란스러운 버그를 초래할 수 있습니다.
838 |
839 | ```python
840 | i = 4
841 | def foo(x: Iterable[int]):
842 | def bar():
843 | print(i, end='') # foo 함수 밖에 있는 i와 동일한 i를 사용합니다.
844 | # ...
845 | # 코드 생략
846 | # ...
847 | for i in x: # foo함수 밖의 i와 동일한 i를 사용합니다. (i 값이 초기화 됩니다.)
848 | print(i, end='')
849 | bar()
850 | ```
851 |
852 | - `foo([1, 2, 3])`은 `1 2 3 4`가 아니라 `1 2 3 3`가 출력됩니다.
853 |
854 |
855 |
856 | #### 2.16.4 결론
857 |
858 | - 사용해도 좋습니다.
859 |
860 | ---
861 |
862 |
863 | ### 2.17 함수와 메서드 Decorators
864 |
865 | - Decorators는 확실하게 이점이 있을 때에 신중하게 사용하세요. `staticmethod`는 피하고 `classmethod`의 사용은 제한하세요.
866 |
867 |
868 |
869 | #### 2.17.1 정의
870 |
871 | - [함수와 메서드를 위한 Decorators 입니다.](https://docs.python.org/3/glossary.html#term-decorator) ("`@` 표기법"으로 알려져있습니다).
872 | - 일반적인 decorator 중 하나는 메서드를 동적으로 계산한 속성으로 변환하는 데 사용하는 `@property`가 있습니다. 그러나 decorator는 사용자 정의 decorator도 허용하고 있습니다.
873 | - 특히 이 `my_decorator` 함수 처럼 할 수 있습니다
874 |
875 | ```python
876 | class C:
877 | @my_decorator
878 | def method(self):
879 | # 메서드 구현부 ...
880 | ```
881 |
882 | - 위 와 동일한 역할 합니다
883 |
884 | ```python
885 | class C:
886 | def method(self):
887 | # 메서드 구현부 ...
888 | method = my_decorator(method)
889 | ```
890 |
891 |
892 |
893 | #### 2.17.2 장점
894 |
895 | - 메서드에 대해 몇몇 변형을 엄밀하게 명시합니다.
896 | - 변형은 몇 가지 반복적인 코드를 제거하고 불변성을 유지하게 만드는 작업 등을 수행합니다.
897 |
898 |
899 |
900 | #### 2.17.3 단점
901 |
902 | - Decorator는 함수의 인자, 반환 값에 대해 임의의 동작을 수행할 수 있으며 결과적으로 놀라운 암묵적 행동을 할 수 있습니다.
903 | - 게다가, Decorator는 object 정의 시 실행합니다. module-level 객체(classes, module functions, ...)의 경우 import할 때 발생합니다.
904 | - Decorator 코드 오류는 복구가 거의 불가능합니다.
905 |
906 |
907 |
908 | #### 2.17.4 결론
909 |
910 | - Decorator는 분명한 이점이 있더라도 현명하게 사용해야 합니다. Decorator는 import와 명명 지침을 따라야 합니다. Decorator pydoc는 decorator 함수 임을 분명히 명시해야합니다. dcorator를 위한 유닛 테스트(unit test)를 사용해야합니다.
911 | - Decorator(예. 파일, 소켓, 데이터베이스 연결 등) 를 실행할 때 (`pydoc` 혹은 기타 도구를 import 시간에 가져올 때) 사용 못할 수 있으므로 Decorator의 외부 의존성을 피하세요. 유효한 매개변수를 가진 Decorator은 모든 경우에 작동할 수 있도록 보장되어야 합니다.
912 | - Decorator는 "Top-level code"의 특별한 경우일 때에는 [main](#s3.17-main) 항목에 자세한 내용이 있습니다.
913 | - 기존 라이브러리에 정의된 API와 통합하기 위해 강제하지 않는 한 "staticmethod"를 사용하지 마세요. 대신 모듈 레벨 함수를 쓰세요.
914 | - classmethod는 명명된 생성자를 작성하거나 프로세스 전체 캐시와 같은 필수 전역 상태를 수정하는 클래스 특정 루틴을 작성할 때만 사용하세요.
915 |
916 | ---
917 |
918 |
919 | ### 2.18 스레드
920 |
921 | - 내장된 타입의 원자성에 의존하지 마세요. 딕셔너리와 같은 Python의 내장된 타입은 원자 형태로 조작할 수 있지만 그러지 않은 경우(예: `__hash__`이나 `__eq__`가 Python 함수로 구현되는 경우)도 있으며 원자로 되어있다고 신뢰하면 안 됩니다. 또한, 원자 변수 할당에 의존해서는 안 됩니다. (결국, 딕셔너리에 달려있기 때문입니다) 스레드 간 데이터를 통신하는 데 선호하는 방법으로 `queue` 모듈의 `Queue` 데이터 타입을 사용하세요. 그렇지 않으면 `threading` 모듈이나 locking primitives를 사용하세요. lower-level lock 대신해 Condition variables와 `threading.Condition`를 선호하세요.
922 |
923 | ---
924 |
925 |
926 | ### 2.19 강한 기능
927 |
928 | - 이런 기능들은 피하세요.
929 |
930 |
931 |
932 | #### 2.19.1 정의
933 |
934 | - Python은 매우 유연한 언어로서 당신에게 많은 화려한 기능을 줍니다. (e.g. 사용자 정의 mtaclasses, bytecode 접근, 즉각적인 컴파일, 동적 상속, object reparenting, import hacks, reflection (`getattr()`의 일부 사용), 시스템 내부 수정, 커스텀 Cleanup을 위한 `__del__` 메소드 등.)
935 |
936 |
937 |
938 | #### 2.19.2 장점
939 |
940 | - 이것들은 강력한 언어 기능입니다. 코드를 더 짧게 만들 수 있습니다.
941 |
942 |
943 |
944 | #### 2.19.3 단점
945 |
946 | - 이 "멋진"기능이 반드시 필요한 것은 아니나 사용하는 것이 매우 유혹적입니다. 이러한 흔치 않은 기능들을 사용하면 읽거나 이해하거나 디버그하는데 어렵습니다.
947 | - 처음에는 그렇게 보이지 않지만 (원저자에게) 코드를 다시 보면 코드는 간단하지만 긴 코드보다 어려운 경향이 있습니다.
948 |
949 |
950 |
951 | #### 2.19.4 결론
952 |
953 | - 코드에서 이러한 기능은 피하세요.
954 | - 이러한 기능을 내부적으로 사용하는 표준 라이브러리 모듈과 클래스는 사용할 수 있습니다. (예를 들면, `abc.ABCMeta`, `dataclasses`, `enum`)
955 |
956 | ---
957 |
958 |
959 | ### 2.20 Modern Python : from, \_\_future\_\_, imports
960 |
961 | - 새로운 언어 버전 의미 체계 변경 사항은 이전 런타임 내에서 파일 단위로 활성화하기 위해 특별한 향후 가져오기 뒤에 제어될 수 있습니다.
962 | (New language version semantic changes may be gated behind a special future import to enable them on a per-file basis within earlier runtimes.)
963 |
964 |
965 |
966 | #### 2.20.1 정의
967 |
968 | - `from __future__ import`문을 통해 보다 현대적인 기능 중 일부를 활성화할 수 있으면 예상되는 향후 Python 버전의 기능을 조기에 사용할 수 있습니다.
969 |
970 |
971 |
972 | #### 2.20.2 장점
973 |
974 | - 이는 호환성을 선언하고 해당 파일 내에서 회귀를 방지하면서 파일별로 변경이 이루어질 수 있으므로 런타임 버전 업그레이드를 더 원활하게 만드는 것으로 입중되었습니다.
975 | - 최신 코드는 향후 런타임 업그레이드 중에 문제가 될 수 있는 기술적 부채가 축적될 가능성이 적기 때문에 유지 관리가 더 쉽습니다.
976 |
977 |
978 |
979 | #### 2.20.3 단점
980 |
981 | - 이러한 코드는 필요한 feature 문을 도입하기 전에는 매우 오래된 인터프리터 버전에서 동작하지 않을 수 있습니다.
982 | - 일반적으로 다양한 환경을 지원해야하는 프로젝트에서 필요합니다.
983 |
984 |
985 |
986 | #### 2.20.4 결론
987 |
988 | ##### from \_\_future\_\_ imports
989 |
990 | - `from __future__ import`문을 사용하는 것이 좋습니다.
991 | - 주어진 소스파일에서 더욱 현대적인 Python 구문 기능을 사용할 수 있습니다.
992 | - `__future__` import 뒤에 기능이 숨겨져 있는 버전에서 더 이상 실행할 필요가 없다면 해당 줄을 자유롭게 제거하세요.
993 | - 3.7 이상이 아닌 3.5 이전 버전에서 실행될 수 있는 코드에서 가져올 경우
994 |
995 | ```python
996 | from __future__ import generator_stop
997 | ```
998 |
999 | - 자세한 내용은 [Python future statement definitions](https://docs.python.org/3/library/__future__.html) 문서를 읽어보세요.
1000 |
1001 | ---
1002 |
1003 |
1004 |
1005 | ### 2.21 Type 주석
1006 |
1007 | - Python에서 타입의 정보를 [PEP-484](https://www.python.org/dev/peps/pep-0484/)의 참고해서 주석으로 달 수 있습니다. 그리고 빌드 할 때 [pytype](https://github.com/google/pytype)같은 타입검사도구를 사용하세요.
1008 | - Type에 대한 주석은 소스 안이나 [stub pyi 파일](https://peps.python.org/pep-0484/#stub-files)에 있을 수 있습니다. 가능하면 주석은 소스안에 있어야 합니다. 타사 또는 확장 모듈에는 pyi 파일을 사용하세요.
1009 |
1010 |
1011 |
1012 | #### 2.21.1 정의
1013 |
1014 | - Type의 주석(혹은 Type 정보)은 함수나 메서드의 인자값이나 반환값입니다
1015 |
1016 | ```python
1017 | def func(a: int) -> list[int]:
1018 | ```
1019 |
1020 | - [PEP-526](https://peps.python.org/pep-0526/)구문 처럼 변수의 type을 선언할 때 사용합니다.
1021 |
1022 | ```python
1023 | a: SomeType = some_func()
1024 | ```
1025 |
1026 |
1027 |
1028 | #### 2.21.2 장점
1029 |
1030 | - Type에 대한 주석은 코드의 가독성과 유지관리에 도움을 줍니다. Type 검사기는 많은 런타임 오류를 빌드 타임 오류로 바꿔주고 [강력한 기능들](#s2.19-power-features)의 사용을 줄여줍니다.
1031 |
1032 |
1033 |
1034 | #### 2.21.3 단점
1035 |
1036 | - Type의 명세를 최신으로 유지해야합니다. 올바른 코드라고 생각했던 곳에서 Type 에러를 볼지도 모릅니다. [Type 검사기](https://github.com/google/pytype)를 사용하면 [강력한 기능들](#s2.19-power-features)을 활용하는 능력이 떨어질 수 있습니다.
1037 |
1038 |
1039 |
1040 | #### 2.21.4 결론
1041 |
1042 | - 프로젝트의 복잡성에 크게 좌우됩니다. 한번 해보세요.
1043 |
1044 | ---
1045 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.1 세미콜론.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.1 Semicolons
4 |
5 | - 세미콜론을 이용해서 문장을 끝내거나 한 줄에 2개의 구문을 작성하지 마세요.
6 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.10 문자열.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.10 Strings
4 |
5 | - 매개변수가 모두 문자열인 경우에도 [f-string](https://docs.python.org/3/reference/lexical_analysis.html#f-strings), `format` 메소드나 `%` 연산자를 사용하여 포메팅하세요.
6 | - 문자열 포맷팅 옵션 사이에서 최상의 판단을 사용하세요.
7 | - `+`를 사용한 단일 join은 괜찮지만, `+`를 사용한 포맷팅은 피하세요.
8 |
9 | - 올바른 예
10 |
11 | ```python
12 | x = f'name: {name}; score: {n}'
13 | x = '%s, %s!' % (imperative, expletive)
14 | x = '{}, {}'.format(first, second)
15 | x = 'name: %s; score: %d' % (name, n)
16 | x = 'name: %(name)s; score: %(score)d' % {'name':name, 'score':n}
17 | x = 'name: {}; score: {}'.format(name, n)
18 | x = a + b
19 | ```
20 |
21 | - 부적절한 예
22 |
23 | ```python
24 | x = first + ', ' + second
25 | x = 'name: ' + name + '; score: ' + str(n)
26 | ```
27 |
28 | - 반목문에서 `+` 나 `+=` 연산자를 사용하여 문자열을 누적하는 행위는 삼가세요.
29 | - 몇몇 상황에서 위 연산자를 이용하여 문자열을 누적하는 경우 리니어한 실행시간이 아닌 제곱형태의 실행시간이 소요될 수 있습니다.
30 | - 물론 이러한 문자열 누적은 CPython의 수정을 통하여 최적화 될 수도 있지만 최적화 여부는 매번 변경될 수도 있으며 이를 예측하는 것 또한 어렵습니다.
31 | - 위의 연산자 대신 리스트에 문자열을 넣고 반복문이 종료되면 `''.join` 를 사용하는것이 더 바람직합니다. (또는 각각의 문자열을 `io.BytesIO` 버퍼에 기록하는 것도 방법입니다.)
32 |
33 | - 올바른 예
34 |
35 | ```python
36 | items = ['
']
37 | for last_name, first_name in employee_list:
38 | items.append('%s, %s |
' % (last_name, first_name))
39 | items.append('
')
40 | employee_table = ''.join(items)
41 | ```
42 |
43 | - 부적절한 예
44 |
45 | ```python
46 | employee_table = ''
47 | for last_name, first_name in employee_list:
48 | employee_table += '%s, %s |
' % (last_name, first_name)
49 | employee_table += '
'
50 | ```
51 |
52 | - 하나의 파일에는 따옴표를 일관되게 사용하세요. `'` 또는 `"` 중 하나를 선택하고 그것만 사용하세요.
53 | - 다만 backslash-escape 따음표 문자 사용을 피하기 위해 같은 파일이더라도 다른 따옴표를 사용하는 것은 괜찮습니다.
54 |
55 | - 올바른 예
56 |
57 | ```python
58 | Python('Why are you hiding your eyes?')
59 | Gollum("I'm scared of lint errors.")
60 | Narrator('"Good!" thought a happy Python reviewer.')
61 | ```
62 |
63 | - 부적절한 예
64 |
65 | ```python
66 | Python("Why are you hiding your eyes?")
67 | Gollum('The lint. It burns. It burns us.')
68 | Gollum("Always the great lint. Watching. Watching.")
69 | ```
70 |
71 | - 다수의 문장을 이용할 때는 `'''` 보단 `"""` 를 이용하세요.
72 | - 프로젝트에 따라 docstring이 아닌 다른 여러줄의 문자열을 `'''` 를 이용하여 작성할 수 있습니다.
73 | - docstring은 상황과 무관하게 `"""` 를 사용합니다.
74 |
75 | - 다중 라인 문자열은 다른 코드의 들여쓰기를 따르지 않습니다.
76 | - 만약에 문자열에 추가 공간을 포함하는 것을 피하려면 단일 행 문자열을 연결하거나 [`textwrap.dedent()`](https://docs.python.org/3/library/textwrap.html#textwrap.dedent)와 함께 다중 라인 문자열을 사용하여 각 줄의 초기 공백을 제거합니다.
77 |
78 | - 부적절한 예
79 |
80 | ```python
81 | long_string = """This is pretty ugly.
82 | Don't do this.
83 | """
84 | ```
85 |
86 | - 올바른 예
87 |
88 | ```python
89 | long_string = """This is fine if your use case can accept
90 | extraneous leading spaces."""
91 | ```
92 |
93 | ```python
94 | long_string = ("And this is fine if you cannot accept\n" +
95 | "extraneous leading spaces.")
96 | ```
97 |
98 | ```python
99 | long_string = ("And this too is fine if you cannot accept\n"
100 | "extraneous leading spaces.")
101 | ```
102 |
103 | ```python
104 | import textwrap
105 |
106 | long_string = textwrap.dedent("""\
107 | This is also fine, because textwrap.dedent()
108 | will collapse common leading spaces in each line.""")
109 | ```
110 |
111 | - 여기서 백슬래시를 사용하는 것은 [명시적인 줄 이어쓰기](#line-length)에 대한 금지를 위반하지 않습니다.
112 | - 이 경우, 백슬래시는 문자열 리터럴에서 [줄바꿈을 이스케이프](https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals)하는 것입니다.
113 |
114 |
115 |
116 | #### 3.10.1 Logging
117 |
118 | - 첫번째 인자로 패턴문자열(% placeholder)이 요구되는 함수의 경우 아래 내용을 확인하세요.
119 | - 반드시 스트링 리터럴(f 스트링 아님)을 첫번째 인자, 패턴인자를 이후에 사용하여 호출하세요.
120 | - 일부 로깅방식의 경우 예상되지 않은 패턴문자열을 쿼리항목으로 이용합니다.
121 | - 또 로거가 필요없는 문자를 출력하는데에 시간을 낭비하지 않도록 방지합니다.
122 |
123 | ```python
124 | 올바른 예:
125 | import tensorflow as tf
126 | logger = tf.get_logger()
127 | logger.info('TensorFlow Version is: %s', tf.__version__)
128 | ```
129 |
130 | ```python
131 | 올바른 예:
132 | import os
133 | from absl import logging
134 | logging.info('Current $PAGER is: %s', os.getenv('PAGER', default=''))
135 | homedir = os.getenv('HOME')
136 | if homedir is None or not os.access(homedir, os.W_OK):
137 | logging.error('Cannot write to home directory, $HOME=%r', homedir)
138 | ```
139 |
140 | ```python
141 | 잘못된 예:
142 | import os
143 | from absl import logging
144 | logging.info('Current $PAGER is:')
145 | logging.info(os.getenv('PAGER', default=''))
146 | homedir = os.getenv('HOME')
147 | if homedir is None or not os.access(homedir, os.W_OK):
148 | logging.error(f'Cannot write to home directory, $HOME={homedir!r}')
149 | ```
150 |
151 |
152 |
153 | #### 3.10.2 Error Messages
154 |
155 | - 에러 메시지(`ValueError`와 같은 에외메시지, 유저에게 보여지는 메시지 등)는 아래의 가이드라인을 따라야합니다.
156 |
157 | 1. 에러메시지는 반드시 에러 조건과 정확하게 일치하여야 합니다.
158 | 2. 메시지 발생위치는 아래 예시와 같이 명확하게 알아볼 수 있어야합니다.
159 | 3. 에러메시지는 간단한 자동화 처리를 허용해야 합니다. (예: grepping)
160 |
161 | ```python
162 | 올바른 예:
163 | if not 0 <= p <= 1:
164 | raise ValueError(f'Not a probability: {p=}')
165 | try:
166 | os.rmdir(workdir)
167 | except OSError as error:
168 | logging.warning('Could not remove directory (reason: %r): %r',
169 | error, workdir)
170 | ```
171 |
172 | ```python
173 | 잘못된 예:
174 | if p < 0 or p > 1: # PROBLEM: also false for float('nan')!
175 | raise ValueError(f'Not a probability: {p=}')
176 | try:
177 | os.rmdir(workdir)
178 | except OSError:
179 | # 문제: 에러메시지가 사실이 아닐 수 있는 내용을 포함하고 있습니다:
180 | # 삭제작업이 실패했을 수도 있기에 이를 디버깅할 누군가가 오해할 수 있습니다
181 | logging.warning('Directory already was deleted: %s', workdir)
182 | try:
183 | os.rmdir(workdir)
184 | except OSError:
185 | # 문제: 메시지가 불필요하게 grep 하기 어려우며
186 | # `workdir`의 값에 따라 사용자가 혼란스러울 수도 있습니다
187 | # 누군가가 아래와 같은 workdir을 사용하는 경우를 생각해보세요
188 | # workdir = 'deleted'.:
189 | # 경고는 아래와 같이 표시될 것입니다.
190 | # "The deleted directory could not be deleted."
191 | logging.warning('The %s directory could not be deleted.', workdir)
192 | ```
193 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.11 파일과 소켓.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.11 파일과 소켓 그리고 유사한 Stateful Resources
4 |
5 | - 파일과 소켓의 사용이 끝나면 명시적으로 연결을 종료해주세요.
6 | - 이 규칙은 당연히 데이터베이스 연결과 같이 내부적으로 소켓을 사용하는 종료가 필요한 자원에도 적용됩니다.
7 | - 몇가지 예시를 들어보자면 아래의 경우가 있습니다
8 |
9 | - [mmap](https://docs.python.org/3/library/mmap.html)
10 | - [h5py File objects](https://docs.h5py.org/en/stable/high/file.html)
11 | - [matplotlib.pyplot figure windows](https://matplotlib.org/2.1.0/api/_as_gen/matplotlib.pyplot.close.html)
12 |
13 | - 파일이나 소켓과 같은 stateful 한 객체를 불필요하게 열어둔체로 남겨놓는것은 아래와 같은 단점들이 있습니다:
14 |
15 | - 파일 디스크립터와 같은 제한된 시스템 자원을 소모합니다.
16 | - 이러한 객체들을 많이 이용하는 코드라면 사용 후 시스템에 곧바로 반납하지 않는 행위는 자원의 고갈로 이어질 수 있습니다.
17 | - 파일을 열어둔 채로 방치하는 것은 파일의 이동, 제거 또는 마운트 해제가 불가능 할 수 있습니다.
18 | - 공유되는 파일이나 소켓의 경우 이용 종료 후에 다른 프로그램에 의해 의도치 않게 읽어지거나 쓰여질 수 있습니다.
19 | - 만약 정말 객체가 닫혀있다면 read/write를 시도할 때 exception을 일으켜 문제를 빠르게 알 수 있습니다.
20 |
21 | - 더욱이, 파일이나 소켓(비슷하게 동작하는 다른 자원 포함)은 객체가 소멸될 때 자동으로 닫혀지는 것은 맞으나 객체의 생명주기를 파일의 상태에 구속하는 것은 나쁜 습관입니다:
22 |
23 | - 런타임이 언제 `__del__` 메소드를 호출하는지 보장 할 수 없습니다.
24 | - 지연된 Garbage Collection 과 같이 파이썬의 종류에 따라 다른 방식의 메모리 관리 기법을 사용하기에 객체의 생명주기가 임의로 늘어나거나 영원히 죽지 않을 수도 있습니다.
25 | - globals 또는 예외추적 과 같이 의도치 않은 파일의 참조는 본래 생명주기보다 더 오랫동안 유지시킬 수 있습니다.
26 |
27 | - 수십 년 동안 여러 언어로 [finalizers](https://en.wikipedia.org/wiki/Finalizer)에 의한 자동 정리를 수행하는 것은 주목할 만한 사이드 임팩트를 거듭해서 재발견되었고 중대한 문제로 이어지고 있습니다. ( [Java에 대한 이 기사 참조](https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers) )
28 |
29 | - 가장 선호되는 파일(비슷하게 동작하는 다른 자원 포함)관리 방식은 [`with` 구문](http://docs.python.org/reference/compound_stmts.html#the-with-statement) 입니다
30 |
31 | ```python
32 | with open("hello.txt") as hello_file:
33 | for line in hello_file:
34 | print(line)
35 | ```
36 |
37 | - `with` 구문을 지원하지 않는 file-like 객체는 `contextlib.closing()`을 사용하세요.
38 |
39 | ```python
40 | import contextlib
41 |
42 | with contextlib.closing(urllib.urlopen("http://www.python.org/")) as front_page:
43 | for line in front_page:
44 | print(line)
45 | ```
46 |
47 | 드물게 컨텍스트 기반 자원관리가 불가피한 경우 코드의 설명을 통해 어떻게 해당 자원의 생명주기가 관리되고 있는지 반드시 기술하여야 합니다
48 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.12 TODO 주석.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.12 TODO Comments
4 |
5 | - 임시적, 잠시 사용하려는 코드 또는 좋기는 하지만 완벽하지 않은 코드의 경우 `TODO` 주석을 사용하세요.
6 |
7 | - `TODO` 주석은 모두 대문자로 된 `TODO`로 시작하고, 다음에 콜론을 붙이며, 맥락이 포함된 리소스에 대한 링크(이상적으로는 버그 참조)를 포함해야 합니다.
8 | - 버그 참조가 선호됩니다. 왜냐하면 버그는 추적되며 후속 댓글이 달리기 때문입니다.
9 | - 이 문맥 다음에 하이픈 `-`으로 시작하는 설명 문자열을 추가하세요..
10 | - 목적은 일관된 `TODO` 형식을 유지하여, 더 많은 세부 정보를 찾기 위해 검색할 수 있도록 하는 것입니다.
11 |
12 | ```python
13 | # TODO: crbug.com/192795 - Investigate cpufreq optimizations.
14 | ```
15 |
16 | - 이전 스타일로, 예전에는 권장되었지만 새로운 코드에서는 사용이 권장되지 않습니다.
17 |
18 | ```python
19 | # TODO(crbug.com/192795): Investigate cpufreq optimizations.
20 | # TODO(yourusername): Use a "\*" here for concatenation operator.
21 | ```
22 |
23 | - 문맥으로 개인이나 팀을 참조하는 TODO를 추가하는 것을 피하세요.
24 |
25 | ```python
26 | # TODO: @yourusername - File an issue and use a '*' for repetition.
27 | ```
28 |
29 | - `TODO`가 "미래의 어느 시점에 무엇을 해야 한다"는 형식이라면, 미래의 코드 유지 관리자가 이해할 수 있도록 매우 구체적인 날짜("2009년 11월까지")나 사건("모든 클라이언트가 XML 요청을 해결 할수 있을때 이 코드 삭제")을 포함해야 합니다.
30 | - 이슈는 이를 추적하는 데 이상적입니다.
31 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.13 import형식.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.13 import 형식
4 |
5 | - imports는 개별적인 라인에 두어야 합니다; [`typing` 그리고 `collections.abc` imports에 대한 예외가 있습니다.](#s3.19.12-imports).
6 |
7 | - 올바른 예
8 |
9 | ```python
10 | import os
11 | import sys
12 | from typing import Any, NewType
13 | ```
14 |
15 | - 부적절한 예
16 |
17 | ```python
18 | import os, sys
19 | ```
20 |
21 | - import는 모듈의 주석 과 docstring 바로 다음, 모듈 전역 및 상수 바로 앞 파일의 맨 위에 배치됩니다.
22 | - import는 가장 일반적인 것 부터 최소한의 일반적인 것들까지 묶여야 합니다.
23 |
24 | 1. Python의 **future** import 문
25 |
26 | ```python
27 | from __future__ import annotations
28 | ```
29 |
30 | 자세한 내용은 [위](#from-future-imports)를 참조하세요.
31 |
32 | 2. 파이썬의 표준 라이브러리
33 |
34 | - import 예시는 다음과 같습니다.
35 |
36 | ```python
37 | import sys
38 | ```
39 |
40 | 3. [third-party](https://pypi.org/)
41 |
42 | - 모듈이나 패키지의 import 예시는 다음과 같습니다.
43 |
44 | ```python
45 | import tensorflow as tf
46 | ```
47 |
48 | 4. Code repository
49 |
50 | - 서브 패키지의 import 예시는 다음과 같습니다.
51 |
52 | ```python
53 | from otherproject.ai import mind
54 | ```
55 |
56 | 5. 동일한 top 레벨에 속하는 어플리케이션의 특정을 import하는 것은 **더 이상 사용되지 않습니다**
57 |
58 | - 서브 패키지의 파일 import 예시는 다음과 같습니다.
59 |
60 | ```python
61 | from myproject.backend.hgwells import time_machine
62 | ```
63 |
64 | - 오래된 Google Python Style code에서 이걸 발견했을 것입니다. 그러나 이건 오래 사용되지는 않았습니다.
65 | - **새로운 코드는 이에 대해 신경쓰지 않도록 되어있습니다.** 간단하게 어플리케이션 서브 패키지를 import 하는 것을 다른 서브 패키지를 import하는 것과 동일하게 취급하세요.
66 |
67 | - 각각의 grouping에서 import는 사전 순으로 정렬되어야 하지만 이러한 조건을 무시해도 될 때는 각각의 모듈의 전체 패키지 경로(`from path import ...` 의 `path`)를 따랐을 경우입니다.
68 | - 코드는 import부분에서 선택적으로 개행을 두어도 됩니다.
69 |
70 | ```python
71 | import collections
72 | import queue
73 | import sys
74 |
75 | from absl import app
76 | from absl import flags
77 | import bs4
78 | import cryptography
79 | import tensorflow as tf
80 |
81 | from book.genres import scifi
82 | from myproject.backend import huxley
83 | from myproject.backend.hgwells import time_machine
84 | from myproject.backend.state_machine import main_loop
85 | from otherproject.ai import body
86 | from otherproject.ai import mind
87 | from otherproject.ai import soul
88 |
89 | # Older style code may have these imports down here instead:
90 | #from myproject.backend.hgwells import time_machine
91 | #from myproject.backend.state_machine import main_loop
92 | ```
93 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.14 statements.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.14 Statements
4 |
5 | - 일반적으로 한 라인에는 오직 한 statement만 있어야 합니다.
6 | - 그러나, 테스트에 관한 statement 전체가 한 라인에 들어간다면 테스트 결과를 같은 줄에 둘 수 있습니다.
7 | - 특히 절대 `try`/`except`에서 `try` 와 `except`를 같은 라인에 둘 수 없고 `if`문에 `else`가 있지 않은 경우에는 가능합니다.
8 |
9 | - 올바른 예
10 |
11 | ```python
12 | if foo: bar(foo)
13 | ```
14 |
15 | - 부적절한 예
16 |
17 | ```python
18 | if foo: bar(foo)
19 | else: baz(foo)
20 |
21 | try: bar(foo)
22 | except ValueError: baz(foo)
23 |
24 | try:
25 | bar(foo)
26 | except ValueError: baz(foo)
27 | ```
28 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.15 접근 제어.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ### 3.15 접근 제어
5 |
6 | - Getter/Setter 함수(접근자 및 변경자라고도함)는 변수 값을 가져오거나 설정하기 위한 의미 있는 역할이나 동작을 제공하는 경우 사용해야 합니다.
7 | - 특히 현재 또는 합리적인 미래에 변수를 가져오거나 설정하는 것이 복잡하거나 비용이 상당할 때 사용해야 합니다.
8 | - 예를 들어 한 쌍의 getter/setter가 단순히 내부 속성을 읽고 쓰는 경우 내부 속성은 대신 공개되어야 합니다.
9 | - 이에 비해 변수를 설정하면 일부 상태가 무효화되거나 다시 작성됨을 의미하는 경우 이는 setter 함수여야 합니다.
10 | - 함수 호출은 잠재적으로 사소하지 않은 작업이 발생하고 있음을 암시합니다.
11 | - 또한 간단한 논리가 필요하거나 더 이상 getter/setter가 필요하지 않도록 리팩토링할 때 [properties](#properties) 옵션이 될 수 있습니다.
12 | - Getter/Setter는 `get_foo()`, `set_foo()`와 같은 [Naming](#s3.16-naming) 지침을 따라야 합니다.
13 | - 이전 동작에서 property을 통한 엑세스가 허용된 경우 새 getter/setter함수를 property에 바인딩하지 마세요.
14 | - 여전히 이전 방법으로 변수에 액세스하려고 시도하는 코드는 눈에 띄게 중단되어 복잡성의 변화를 인식할 수 있습니다.
15 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.16 네이밍.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.16 네이밍
4 |
5 | `module_name`,
6 | `package_name`,
7 | `ClassName`,
8 | `method_name`,
9 | `ExceptionName`,
10 | `function_name`,
11 | `GLOBAL_CONSTANT_NAME`,
12 | `global_var_name`,
13 | `instance_var_name`,
14 | `function_parameter_name`,
15 | `local_var_name`,
16 | `query_proper_noun_for_thing`,
17 | `send_acronym_via_https`.
18 |
19 | - 함수 이름, 변수 이름, 그리고 파일 이름은 설명적이여야 하고 약어로 적는 일을 피해야 합니다.
20 | - 특히 모호하거나 프로젝트에 참여하지 않은 사람들이 읽었을 때 익숙하지 않은 약어를 사용하지마세요. 그리고 절대 단어에서 글자를 지워 줄이지 마세요.
21 |
22 | - 항상 `.py`파일 이름 확장자를 사용하고 절대 대시`-`를 사용하지 마세요.
23 |
24 |
25 |
26 | #### 3.16.1 피해야 할 이름
27 |
28 | - 아래와 같은 특별한 경우를 제외한 단일 글자는 피합니다.
29 |
30 | - counters이나 iterators에서 사용할 때 (예. `i`, `j`, `k`, `v` 등)
31 | - `try/except`문에서 예외 식별자로 `e`를 사용할 때
32 | - with문의 파일 핸들에서 `f`를 사용할 때
33 | - 제약 조건이 없는 비공식적인 [type variables](#typing-type-var)를 사용할 때 (e.g., `_T = TypeVar("_T"), _P = ParamSpec("_P")`)
34 |
35 | 단일 글자를 남용하지 않도록 주의해야합니다. 일반적으로 말해서 서술성은 이름의 가시성 범위에 비례해야합니다. 예를 들어 `i`는 5행 코드 블록에 적합한 이름일 수 있지만 중첩된 여러 범위 내에서는 너무 모호할 수 있습니다.
36 |
37 | - package/module 이름에서 dashes(`-`)를 사용할 때
38 | - `__이중_선행_및_후행_밑줄__` 이름을 사용할 때 (Python에서 예약어)
39 |
40 | - 원본에 없는 추가 설명 : double leading and trailing underscore : (앞 뒤로 \_가 2개씩 있는것 e.g **name**, **init**)
41 |
42 | - 공격적인 단어
43 | - 불필요하게 변수 타입을 포함하는 이름 (예 : `id_to_name_dict`)
44 |
45 |
46 |
47 | #### 3.16.2 Naming Conventions
48 |
49 | 모듈에 관련 클래스와 최상위 기능을 함께 배치합니다.
50 |
51 | - "Internal"는 모듈의 내부 또는 클래스 내에서 protected 또는 private를 의미합니다.
52 | - 단일 밑줄(`_`)을 추가하면 모듈 변수와 함수를 보호하기 위한 몇 가지 지원이 있습니다. (linters는 보호된 멤버 접근에 플래그를 지정합니다.)
53 | - 단일 언더스코어(`_`)를 접두사로 사용하는 것은 모듈 변수와 함수 보호를 위한 일부 지원을 제공합니다 (linters가 보호된 멤버 접근을 경고할 수 있습니다). 그러나 유닛 테스트가 테스트 중인 모듈의 보호된 상수에 접근하는 것은 괜찮습니다.
54 | - 인스턴스 변수나 메소드에 이중 밑줄(`__` : dunder)을 추가하면 변수나 메소드가 해당 클래스에 대해 효과적으로 private 됩니다.
55 | - 가독성과 테스트 가능성에 영향을 미치고 _실제로_ 비공개가 아니므로 사용을 권장하지 않습니다.
56 | - 하나의 밑줄을 선호합니다.
57 | - 모듈에 관련 클래스와 top-level 함수를 함께 배치합니다.
58 | - 자바와는 다르게 하나의 모듈에 대해 하나의 클래스로 제한을 할 필요가 없습니다.
59 | - CapWords(단어의 첫 글자를 대문자로 하는 방식)을 사용하지만 모듈의 이름이 \_with_under.py 같은 경우에는 소문자로 합니다.
60 |
61 | - 비록 몇몇 오래된 모듈의 이름이 CapWords.py일지라도 이제는 모듈의 이름을 class이름에 따라 짓게 되면 혼란스러우므로 권장하지 않습니다. (e.g "잠깐만, -- 내가 `import StringIO`를 한거야 아니면 `from StringIO import StringIO`를 한거야 ?" 같은 상황이 발생할 수 있습니다.)
62 |
63 | - 새로운 유닛 테스트 파일은 PEP 8을 준수하는 소문자와 언더스코어 방식의 메서드 이름을 따릅니다.
64 | - 예를 들어, `test**`와 같은 형식을 사용합니다.
65 | - 일관성을 위해(\*) 이전 모듈에서 CapWords 함수 이름을 따르는 경우, `test`로 시작하는 메서드 이름에 논리적 구성 요소를 구분하기 위해 언더스코어가 포함될 수 있습니다.
66 | - 하나의 가능한 패턴은 `test_`입니다.
67 |
68 |
69 |
70 | #### 3.16.3 파일 네이밍
71 |
72 | - 파이썬 파일이름은 반드시 `.py`확장자를 가지고 (`-`)를 가지고 있으면 안됩니다.
73 | - 이건 import와 유닛테스트를 할 수 있게 해줍니다.
74 | - 만약 확장자 없이 실행 파일에 접근하려면 `exec "$0.py" "$@"` 가 들어 있는 심볼 링크나 간단한 bash wrapper를 사용하세요.
75 |
76 |
77 |
78 | #### 3.16.4 [Guido](https://en.wikipedia.org/wiki/Guido_van_Rossum)의 권고에 따른 가이드라인
79 |
80 | | 타입 | Public | Internal |
81 | | -------------------- | -------------------- | --------------------------------- |
82 | | 패키지 | `lower_with_under` | |
83 | | 모듈 | `lower_with_under` | `_lower_with_under` |
84 | | 클래스 | `CapWords` | `_CapWords` |
85 | | 예외 | `CapWords` | |
86 | | 함수 | `lower_with_under()` | `_lower_with_under()` |
87 | | 글로벌/클래스 상수 | `CAPS_WITH_UNDER` | `_CAPS_WITH_UNDER` |
88 | | 글로벌/클래스 변수 | `lower_with_under` | `_lower_with_under` |
89 | | 인스턴스 변수 | `lower_with_under` | `_lower_with_under` (protected) |
90 | | 메서드 이름 | `lower_with_under()` | `_lower_with_under()` (protected) |
91 | | 함수/메서드 매개변수 | `lower_with_under` | |
92 | | 지역 변수 | `lower_with_under` | |
93 |
94 |
95 |
96 | #### 3.16.5 수학 표기법
97 |
98 | - 수학적으로 복잡한 코드의 경우 일반적으로 코딩 스타일 가이드를 벗어나는 짧은 변수이더라도 참고서나 알고리즘에서 보편적으로 사용되는 정립된 표식은 허용됩니다.
99 | - 이런 경우 주석이나 docstring으로 표식의 출처를 참조해주세요.
100 | - 출처에 접근할 수 없는 경우 명확하게 명명규칙을 기술하세요.
101 | - 공개 API의 경우 더 자주 사용되는 PEP8-compliant `descriptive_names`이 선호됩니다.
102 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.17 Main.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.17 Main
4 |
5 | - 파이썬에서 `pydoc`과 유닛 테스트는 모듈을 import할 수 있어야 합니다.
6 | - 파일이 실행파일로써 사용되어야 하더라도 주된 기능은 `main()` 함수에 포함되어야 합니다.
7 | - 당신의 코드에서 메인 프로그램이 모듈을 import 할 때 실행되지 않도록 메인 프로그램을 실행시키기 전에 `if __name__ == '__main__'`을 항상 확인해야 합니다.
8 |
9 | - [absl](https://github.com/abseil/abseil-py)를 사용할 때 `app.run`를 사용하세요.
10 |
11 | ```python
12 | from absl import app
13 | ...
14 |
15 | def main(argv: Sequence[str]):
16 | # process non-flag arguments
17 | ...
18 |
19 | if __name__ == '__main__':
20 | app.run(main)
21 | ```
22 |
23 | - 그렇지 않으면 다음을 사용하세요.
24 |
25 | ```python
26 | def main():
27 | ...
28 |
29 | if __name__ == '__main__':
30 | main()
31 | ```
32 |
33 | - top level에 있는 모든 코드는 모듈이 import될 때 실행될 것입니다.
34 | - 파일을 `pydoc`으로 만들 때 실행하면 안되는 연산을 하거나 함수를 호출하는 것과 객체를 만드는 것을 조심하세요.
35 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.18 함수 길이.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.18 함수 길이
4 |
5 | - 함수의 길이가 작고 필수기능으로만 작성된 함수를 선호하세요.
6 |
7 | - 우리는 길이가 긴 함수들이 가끔 필요하다는걸 알고있습니다. 그래서 함수 길이에 딱히 제한은 없습니다.
8 | - 하지만 만약 함수가 40줄을 넘어가면 프로그램의 구조에 피해가 안가면서 줄일 수 있는지 생각해보세요.
9 |
10 | - 비록 작성한 길이가 긴 함수가 당장은 완벽하게 작동할지라도 누군가 몇 달 이내에 함수에 새로운 동작을 추가할수 도 있습니다.
11 | - 이건 버그를 찾기 어렵게 할수 도 있습니다.
12 | - 작성한 함수를 짧고 간단하게 하여 다른 사람들이 읽고 코드를 수정하기 쉽게 만드세요.
13 |
14 | - 작업을 할때 몇몇 길고 복잡한 함수를 발견할 수 있습니다. 절대 기존의 코드를 수정한다는 협박을 하지 마세요
15 | - 만약 함수가 사용하기 어렵다고 판단되면, 에러를 디버깅 하기 힘들다는걸 알거나 몇몇 다른 문맥에서 이 에러들을 사용하기 원한다고 할때
16 | - 그 함수를 작고 더욱 관리가 가능한 조각들로 나누는 것을 생각해 보세요.
17 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.19 Type 주석 방법.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.19 Type 주석 방법
4 |
5 |
6 |
7 | #### 3.19.1 일반적인 규칙
8 |
9 | - [PEP-484](https://peps.python.org/pep-0484/)을 읽으세요.
10 |
11 | - `self` 또는 `cls`에 주석을 달 필요는 일반적으로 없습니다. 올바른 타입 정보를 위해 필요한 경우에만 [`Self`](https://docs.python.org/3/library/typing.html#typing.Self)를 사용할 수 있습니다.
12 |
13 | ```python
14 | from typing import Self
15 | class BaseClass:
16 | @classmethod
17 | def create(cls) -> Self:
18 | ...
19 | def difference(self, other: Self) -> float:
20 | ...
21 | ```
22 |
23 | - 마찬가지로, `__init__`의 반환 값에 주석을 달 필요는 없습니다 (여기서 `None`만 유효한 옵션입니다).
24 |
25 | - 모든 변수나 반환되는 Type이 정해지지 않았다면 `Any`를 사용하세요.
26 |
27 | - 모듈에서 모든 함수에 주석을 달 필요는 없습니다.
28 | - Public API에는 최소한의 주석을 답니다.
29 | - 판단력을 사용하여 한편으로는 안전성과 명확성, 그리고 다른 한편으로는 유연성 사이의 균형을 잘 잡아야 합니다.
30 | - Type 관련 오류(이전 버그 또는 복잡성)가 발생하기 쉬운 코드에 주석을 답니다.
31 | - 이해하기 어려운 코드에 주석을 답니다.
32 | - Type의 관점에서 코드가 안정화되면 주석을 답니다. 많은 경우에 너무 변하는 코드를 제외한 모든 심사숙고한 코드에 주석을 달 수 있습니다.
33 |
34 |
35 |
36 | #### 3.19.2 줄 바꿈
37 |
38 | - 기존의 [들여쓰기](#s3.4-indentation) 규칙을 따르세요.
39 |
40 | - 주석처리하고나서 많은 함수는 "한 줄에 하나의 파라미터"가 될 것입니다.
41 | - 반환 타입이 별도의 줄에 표시되도록 보장하기 위해, 마지막 매개변수 뒤에 쉼표를 추가할 수 있습니다.
42 |
43 | ```python
44 | def my_method(
45 | self,
46 | first_var: int,
47 | second_var: Foo,
48 | third_var: Bar | None,
49 | ) -> int:
50 | ...
51 | ```
52 |
53 | - 한줄에 맞출 수 있다면 사용해도 좋지만, 예제처럼 변수와 예를 들어 변수 이름과 유형 주석 간에는 포함되지않은 사이에는 항상 끊는 것을 선호합니다.
54 |
55 | ```python
56 | def my_method(self, first_var: int) -> int:
57 | ...
58 | ```
59 |
60 | - 함수 이름, 마지막 매개 변수 및 리턴 Type의 조합이 너무 길면 새 행에서 4만큼 들여 쓰기됩니다.
61 | - 줄 바꿈을 사용할 때는 각 매개변수와 반환 타입을 별도의 줄에 배치하고, 닫는 괄호를 `def`와 정렬하는 것이 좋습니다.
62 |
63 | ```python
64 | def my_method(
65 | self,
66 | other_arg: MyLongType | None,
67 | ) -> tuple[MyLongType1, MyLongType1]:
68 | ...
69 | ```
70 |
71 | - 선택적으로, 반환 타입을 마지막 매개변수와 같은 줄에 배치할 수도 있습니다.
72 |
73 | - 괜찮은 예
74 |
75 | ```python
76 | def my_method(
77 | self,
78 | first_var: int,
79 | second_var: int) -> dict[OtherLongType, MyLongType]:
80 | ...
81 | ```
82 |
83 | - `pylint`를 사용하면 닫는 괄호를 새 줄로 이동하고 여는 줄과 맞출 수 있지만 읽기 어렵습니다.
84 |
85 | - 부적절한 예
86 |
87 | ```python
88 | def my_method(self,
89 | other_arg: MyLongType | None,
90 | ) -> dict[OtherLongType, MyLongType]:
91 | ...
92 | ```
93 |
94 | - 위 예처럼, Type을 깨지 않는 것을 선호합니다.
95 | - 하지만 때때로는 너무 길어서 한 줄에 담을 수 없습니다. (sub-type를 끊어지지 않도록 노력합니다.)
96 |
97 | ```python
98 | def my_method(
99 | self,
100 | first_var: tuple[list[MyLongType1],
101 | list[MyLongType2]],
102 | second_var: list[dict[
103 | MyLongType3, MyLongType4]],
104 | ) -> None:
105 | ...
106 | ```
107 |
108 | - 단일 이름과 Type이 너무 길면 Type에 대한 [alias(별칭)](#s3.19.6-aliases)사용을 고려하세요.
109 | - 최후의 수단은 다음에 4칸을 들여 쓰는 것입니다.
110 |
111 | - 올바른 예
112 |
113 | ```python
114 | def my_function(
115 | long_variable_name:
116 | long_module_name.LongTypeName,
117 | ) -> None:
118 | ...
119 | ```
120 |
121 | - 부적절한 예
122 |
123 | ```python
124 | def my_function(
125 | long_variable_name: long_module_name.
126 | LongTypeName,
127 | ) -> None:
128 | ...
129 | ```
130 |
131 |
132 |
133 | #### 3.19.3 전방선언
134 |
135 | - 아직 정의되지 않은 클래스 이름(예를 들어, 클래스 선언 내부에서 클래스 이름이 필요하거나 코드에서 나중에 정의된 클래스를 사용할 경우)을 사용해야 할 경우, `from __future__ import annotations`를 사용하거나 클래스 이름을 문자열로 사용하세요.
136 |
137 | - 올바른 예
138 |
139 | ```python
140 | from __future__ import annotations
141 |
142 | class MyClass:
143 | def __init__(self, stack: Sequence[MyClass], item: OtherClass) -> None:
144 |
145 | class OtherClass:
146 | ...
147 | ```
148 |
149 | ```python
150 | class MyClass:
151 | def __init__(self, stack: Sequence['MyClass'], item: 'OtherClass') -> None:
152 |
153 | class OtherClass:
154 | ...
155 | ```
156 |
157 |
158 |
159 | #### 3.19.4 기본 값
160 |
161 | - PEP-008에 따라 유형 주석과 기본값이 모두 있는 인수의 경우 "=" \_ only" 주위에 공백을 사용하십시오.
162 | - [PEP-008](https://peps.python.org/pep-0008/#other-recommendations)에 따라 Type 주석과 기본 값이 모두 있는 인수의 경우 `=` _only_ 주위에 공백을 사용하세요,
163 |
164 | - 올바른 예
165 |
166 | ```python
167 | def func(a: int = 0) -> int:
168 | ...
169 | ```
170 |
171 | - 부적절한 예
172 |
173 | ```python
174 | def func(a:int=0) -> int:
175 | ...
176 | ```
177 |
178 |
179 |
180 | #### 3.19.5 NoneType
181 |
182 | - 파이썬형에서 노네타입(NoneType)은 퍼스트클래스형이며, 타이핑을 위해 노네타입(NoneType)은 노네타입(NoneType)의 별칭이다.
183 | - 인자가 `None`이 될 수 있는 경우, 이를 선언해야 합니다!
184 | - 새로운 Python 3.10+ 코드에서는 `|` 유니온 타입 표현식을 사용하는 것이 권장되며, 이전에는 `Optional`과 `Union` 구문을 사용할 수 있습니다.
185 |
186 | - 암시적인 대신 명시적인 `X | None`을 사용하세요.
187 | - 이전 버전의 PEP 484에서는 `a: str = None`을 `a: str | None = None`으로 해석할 수 있었지만, 이제는 이것이 선호되는 동작이 아닙니다.
188 |
189 | - 올바른 예
190 |
191 | ```python
192 | def modern_or_union(a: str | int | None, b: str | None = None) -> str:
193 | ...
194 | def union_optional(a: Union[str, int, None], b: Optional[str] = None) -> str:
195 | ...
196 | ```
197 |
198 | - 부적절한 예
199 |
200 | ```python
201 | def nullable_union(a: Union[None, str]) -> str:
202 | ...
203 | def implicit_optional(a: str = None) -> str:
204 | ...
205 | ```
206 |
207 |
208 |
209 |
210 | #### 3.19.6 Type Aliases
211 |
212 | - 복잡한 유형의 별칭을 선언할 수 있다. 가명의 이름은 CapWorded여야 한다. 별칭이 이 모듈에서만 사용되는 경우 \_Private여야 한다.
213 |
214 | - 어려운 Type을 별칭으로 선언할 수 있습니다. 별칭은 CapWorded여야 합니다. 별칭이 이 모듈에서만 사용하는 경우에는 \_Private여야 합니다.
215 |
216 | - TypeAlias 주석은 버전 3.10 이상에서만 지원된다는 점에 유의하세요.
217 |
218 | ```python
219 | from typing import TypeAlias
220 | _LossAndGradient: TypeAlias = tuple[tf.Tensor, tf.Tensor]
221 | ComplexTFMap: TypeAlias = Mapping[str, _LossAndGradient]
222 | ```
223 |
224 |
225 |
226 |
227 | #### 3.19.7 Ignoring Types
228 |
229 | - `# type: ignore` 주석으로 Type 검사를 사용하지 않도록 설정 할 수 있습니다.
230 |
231 | - `pytype`에는 특정 오류에 대한 비활성화 옵션이 있습니다.(lint과 유사).
232 |
233 | ```python
234 | # pytype: disable=attribute-error
235 | ```
236 |
237 |
238 |
239 |
240 | #### 3.19.8 내부 변수 작성
241 |
242 |
243 |
244 | - [_Annotated Assignments_](#annotated-assignments): 내부 변수의 타입을 추론하기 어렵거나 불가능한 경우, 주석이 달린 할당으로 타입을 명시하세요. 변수 이름과 값 사이에 콜론과 타입을 사용합니다 (기본값이 있는 함수 인수와 동일한 방식으로).
245 |
246 | ```python
247 | a: Foo = SomeUndecoratedFunction()
248 | ```
249 |
250 |
251 |
252 | - [_Type Comments_](#type-comments): 코드베이스에 여전히 남아 있을 수 있지만 (Python 3.6 이전에는 필요했음), 더 이상 `# type: ` 주석을 줄 끝에 추가하지 마세요.
253 |
254 | ```python
255 | a = SomeUndecoratedFunction() # type: Foo
256 | ```
257 |
258 |
259 |
260 |
261 | #### 3.19.9 튜플 vs 리스트
262 |
263 | - 리스트 타입은 한가지 타입의 오프젝트만 포함할 수 있습니다. 튜플 타입은 반복되는 하나의 타입이나 서로 다른 타입을 넣을 수 있습니다.
264 | - 서로 다른 타입의 수를 넣는 경우는 일반적으로 함수에서 타입을 반환할 때 사용됩니다.
265 | - 리스트는 함수의 반환 타입으로 일반적으로 사용된다.
266 |
267 | ```python
268 | a: list[int] = [1, 2, 3]
269 | b: tuple[int, ...] = (1, 2, 3)
270 | c: tuple[int, str, float] = (1, "2", 3.5)
271 | ```
272 |
273 |
274 |
275 |
276 |
277 | #### 3.19.10 Type variables
278 |
279 | - 파이썬형 시스템은 일반성을 가지고 있다. 공장 기능인 TypeVar는 흔히 사용하는 방법입니다.
280 |
281 | - 파이선 Type에는 [generics](https://peps.python.org/pep-0484/#generics)를 가지고 있습니다.
282 | - `TypeVar`와 `ParamSpec`과 같은 타입 변수는 제너릭을 사용하는 일반적인 방법입니다.
283 |
284 | ```python
285 | from collections.abc import Callable
286 | from typing import ParamSpec, TypeVar
287 | _P = ParamSpec("_P")
288 | _T = TypeVar("_T")
289 | ...
290 | def next(l: list[_T]) -> _T:
291 | return l.pop()
292 | def print_when_called(f: Callable[_P, _T]) -> Callable[_P, _T]:
293 | def inner(*args: _P.args, **kwargs: _P.kwargs) -> _T:
294 | print("Function was called")
295 | return f(*args, **kwargs)
296 | return inner
297 | ```
298 |
299 | - `TypeVar`는 부자연스러울 수도 있습니다.
300 |
301 | ```python
302 | AddableType = TypeVar("AddableType", int, float, str)
303 | def add(a: AddableType, b: AddableType) -> AddableType:
304 | return a + b
305 | ```
306 |
307 | - `typing` 모듈의 흔히 미리 정의된 Type 변수는 `AnyStr`입니다. `bytes`, `str`일 수 있고 모두 같은 Type이어야 하는 여러 주석에 사용합니다.
308 |
309 | ```python
310 | from typing import AnyStr
311 | def check_length(x: AnyStr) -> AnyStr:
312 | if len(x) <= 42:
313 | return x
314 | raise ValueError()
315 | ```
316 |
317 | - 타입 변수는 설명적인 이름을 가져야 합니다. 단, 다음 모든 기준을 충족하는 경우에는 예외입니다.
318 |
319 | - 외부에서 보이지 않는 경우
320 | - 제약 조건이 없는 경우
321 |
322 | - 올바른 예
323 |
324 | ```python
325 | _T = TypeVar("_T")
326 | _P = ParamSpec("_P")
327 | AddableType = TypeVar("AddableType", int, float, str)
328 | AnyFunction = TypeVar("AnyFunction", bound=Callable)
329 | ```
330 |
331 | - 부적절한 예
332 |
333 | ```python
334 | T = TypeVar("T")
335 | P = ParamSpec("P")
336 | _T = TypeVar("_T", int, float, str)
337 | _F = TypeVar("_F", bound=Callable)
338 | ```
339 |
340 |
341 |
342 |
343 |
344 |
345 | #### 3.19.11 문자열 Type
346 |
347 | > 새로운 코드에서는 `typing.Text`를 사용하지 마세요. 이는 Python 2/3 호환성을 위한 것입니다.
348 |
349 | - 문자열/텍스트 데이터에는 `str`을 사용하세요. 이진 데이터와 관련된 코드에서는 `bytes`를 사용하세요.
350 |
351 | ```python
352 | def deals_with_text_data(x: str) -> str:
353 | ...
354 | def deals_with_binary_data(x: bytes) -> bytes:
355 | ...
356 | ```
357 |
358 | - 함수의 모든 string Type이 항상 동일한 경우(예, 반환 Type이 위의 코드에서 인자 Type과 동일한 경우) [AnyStr](#s3.19.10-type-var)를 사용하세요.
359 |
360 | - 이렇게 사용하면 Python 3에 코드를 포팅하는 과정이 간단해집니다.
361 |
362 |
363 |
364 |
365 | #### 3.19.12 Typing 추가
366 |
367 | - `typing` 또는 `collections.abc` 모듈에서 정적 분석 및 타입 검사를 지원하기 위해 사용하는 심볼(타입, 함수, 상수 등)은 항상 심볼 자체를 임포트하세요.
368 | - 이렇게 하면 일반적인 주석이 더 간결해지고, 전 세계적으로 사용되는 타입 주석 관행에 맞출 수 있습니다.
369 | - `typing` 및 `collections.abc` 모듈에서 여러 개의 특정 심볼을 한 줄에서 명시적으로 임포트할 수 있습니다.
370 |
371 | ```python
372 | from collections.abc import Mapping, Sequence
373 | from typing import Any, Generic, cast, TYPE_CHECKING
374 | ```
375 |
376 | - 이 방식으로 임포트하면 로컬 네임스페이스에 항목이 추가되므로, `typing` 또는 `collections.abc`의 이름은 키워드와 유사하게 취급되어야 하며, Python 코드에서 정의되지 않아야 합니다. 타입 여부와 관계없이 말입니다.
377 | - 모듈 내에서 타입과 기존 이름 간에 충돌이 있는 경우, `import x as y`를 사용하여 임포트하세요.
378 |
379 | ```python
380 | from typing import Any as AnyType
381 | ```
382 |
383 | - 가능한 경우, 주석으로 내장 타입을 사용하는 것이 좋습니다.
384 | - Prefer to use built-in types as annotations where available.
385 | - Python은 [PEP-585](https://peps.python.org/pep-0585/)를 통해 매개형 컨테이너 타입을 사용한 타입 주석을 지원하며, 이는 Python 3.9에서 도입되었습니다.
386 |
387 | ```python
388 | def generate_foo_scores(foo: set[str]) -> list[float]:
389 | ...
390 | ```
391 |
392 |
393 |
394 |
395 | #### 3.19.13 조건 Imports
396 |
397 | - 형식 확인에 필요한 추가 가져오기를 런타임에 피해야 하는 예외적인 경우에만 조건부 가져오기를 사용하십시오.
398 |
399 | - 이러한 패턴은 바람직하지 않습니다.
400 | - 최고 수준의 수입을 허용하도록 코드 재인쇄와 같은 대안이 선호되어야 합니다.
401 |
402 | - Type 확인에 필요한 import 추가는 런타임에 피해야 하는 예외적인 경우에만 조건부 가져오기를 사용하세요.
403 |
404 | - 이러한 패턴은 바람직하지 않습니다.
405 | - top level import을 허용하도록 코드 재구성과 같은 대안이 선호되어야 합니다.
406 |
407 | - Type 주석에만 필요한 impot는 `if TYPE_CHECKING:` 블록 내에 배치 할 수 있습니다.
408 | - 조건부로 import한 Type을 문자열로 참조하여 주석 표현이 실제로 평가되는 Python 3.6과 정방향 호환 가능합니다.
409 | - 입력에만 사용되는 속성만 정의되어야 합니다. 별칭이 포함되어야 하며 그렇지 않으면 모듈을 런타임에 가져오지 않기 때문에 런타임 오류가 발생합니다.
410 | - 블록은 모든 정상 import 후여야 합니다.
411 | - typing import 목록에 빈 줄이 없어야 합니다.
412 | - 목록을 일반 import 목록인 것처럼 정렬하세요.
413 |
414 | ```python
415 | import typing
416 | if typing.TYPE_CHECKING:
417 | import sketch
418 | def f(x: "sketch.Sketch"): ...
419 | ```
420 |
421 |
422 |
423 |
424 | #### 3.19.14 Circular 종속
425 |
426 | - Circular 종속의 원인은 심오한 문제(code smells)를 작성하는 것입니다.
427 |
428 | - 그런 코드는 리팩터링에 적합합니다.
429 | - 하지만 기술적으로 Circular 종속성을 유지하는 것은 가능하지만, 다양한 빌드 시스템은 다른 모듈에 의존해야 하기 때문에 그렇게 하도록 허락하지 않을 것입니다.
430 |
431 | - Circular 종속을 생성하는 모듈을 `Any`로 교체합니다.
432 | - 의미있는 이름으로 [alias](#s3.19.6-aliases)를 지정하고 모듈의 실제 Type 이름을 사용하세요 (`Any`의 모든 속성은 `Any`입니다.).
433 | - Alias의 정의는 마지막으로 import와 한 줄로 분리합니다.
434 |
435 | ```python
436 | from typing import Any
437 |
438 | some_mod = Any # some_mod.py에서 이 모듈을 import 합니다.
439 | ...
440 |
441 | def my_method(self, var: "some_mod.SomeType") -> None:
442 | ...
443 | ```
444 |
445 |
446 |
447 | #### 3.19.15 일반
448 |
449 | - 주석을 달때, 일반 Type를 지정하기를 선호하며 그렇지 [않을 때에는 `Any`로 가정합니다](https://peps.python.org/pep-0484/#the-any-type).
450 |
451 | - 올바른 예
452 |
453 | ```python
454 | def get_names(employee_ids: Sequence[int]) -> Mapping[int, str]:
455 | ...
456 | ```
457 |
458 | - 부적절한 예
459 |
460 | ```python
461 | # 이는 get_names(employee_ids: Sequence[Any]) -> Mapping[Any, Any]로 해석됩니다.
462 | def get_names(employee_ids: Sequence) -> Mapping:
463 | ```
464 |
465 | - 파라미터의 적합한 Type이 `Any`일 때, 명시적으로 표현되며, 많은 경우에 [`TypeVar`](#s3.19.10-type-var)가 더 적합할 수 있음을 기억해야합니다.
466 |
467 | - 부적절한 예
468 |
469 | ```python
470 | def get_names(employee_ids: Sequence[Any]) -> Mapping[Any, str]:
471 | """직원의 아이디를 이름과 연결하여 반환합니다."""
472 | ```
473 |
474 | - 올바른 예
475 |
476 | ```python
477 | _T = TypeVar('_T')
478 | def get_names(employee_ids: Sequence[_T]) -> Mapping[_T, str]:
479 | """직원의 아이디를 이름과 연결하여 반환합니다."""
480 | ```
481 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.2 줄 길이.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.2 Line length
4 |
5 | - 최대 줄 길이는 _80자_ 입니다.
6 |
7 | - 예외
8 | - 긴 import 구문
9 | - URLs, 경로이름, 또는 주석의 긴 플래그
10 | - 경로이름이나 URLs와 같은 공백을 포함하지 않는 긴 모듈수준 문자상수는 여러 줄에 나누어 기록하기 불편할 경우
11 | - Pylint 비활성화 주석문 (e.g.: `# pylint: disable=invalid-name`)
12 |
13 | - [명시적인 줄 연속](https://docs.python.org/3/reference/lexical_analysis.html#explicit-line-joining)을 위해 백슬래시를 사용하지 마세요.
14 | - 대신에 Python의 [소/중/대 괄호 내부의 묵시적 라인결합](http://docs.python.org/reference/lexical_analysis.html#implicit-line-joining)을 사용하세요.
15 | - 필요하다면, 구문 양쪽에 추가로 괄호를 더할 수 있습니다.
16 | - 이 규칙은 문자열 내에서 백슬래시로 이스케이프된 개행을 금지하지 않습니다(아래 [참조](#strings)).
17 |
18 | - 올바른 예
19 |
20 | ```python
21 | foo_bar(self, width, height, color='black', design=None, x='foo',
22 | emphasis=None, highlight=0)
23 |
24 | if (width == 0 and height == 0 and
25 | color == 'red' and emphasis == 'strong'):
26 | (bridge_questions.clarification_on
27 | .average_airspeed_of.unladen_swallow) = 'African or European?'
28 | with (
29 | very_long_first_expression_function() as spam,
30 | very_long_second_expression_function() as beans,
31 | third_thing() as eggs,
32 | ):
33 | place_order(eggs, beans, spam, beans)
34 | ```
35 |
36 | - 부적절한 예
37 |
38 | ```python
39 | if width == 0 and height == 0 and \
40 | color == 'red' and emphasis == 'strong':
41 | bridge_questions.clarification_on \
42 | .average_airspeed_of.unladen_swallow = 'African or European?'
43 | with very_long_first_expression_function() as spam, \
44 | very_long_second_expression_function() as beans, \
45 | third_thing() as eggs:
46 | place_order(eggs, beans, spam, beans)
47 | ```
48 |
49 | - 만약 리터럴 문자열을 한 줄에 표현하기 어렵다면 아래와 같이 괄호를 이용하여 묵시적 라인결합을 사용하세요.
50 |
51 | ```python
52 | x = ('This will build a very long long '
53 | 'long long long long long long string')
54 | ```
55 |
56 | - 가능한 가장 높은 구문 수준에서 줄을 나누는 것을 선호하세요. 줄을 두 번 나눠야 하는 경우, 두 번 모두 동일한 구문 수준에서 나누세요.
57 |
58 | - 올바른 예
59 |
60 | ```python
61 | bridgekeeper.answer(
62 | name="Arthur", quest=questlib.find(owner="Arthur", perilous=True))
63 | answer = (a_long_line().of_chained_methods()
64 | .that_eventually_provides().an_answer())
65 | if (
66 | config is None
67 | or 'editor.language' not in config
68 | or config['editor.language'].use_spaces is False
69 | ):
70 | use_tabs()
71 | ```
72 |
73 | - 부적절한 예
74 |
75 | ```python
76 | bridgekeeper.answer(name="Arthur", quest=questlib.find(
77 | owner="Arthur", perilous=True))
78 | answer = a_long_line().of_chained_methods().that_eventually_provides(
79 | ).an_answer()
80 | if (config is None or 'editor.language' not in config or config[
81 | 'editor.language'].use_spaces is False):
82 | use_tabs()
83 | ```
84 |
85 | - 주석의 경우 긴 URLs 들은 한줄에 표현하세요.
86 |
87 | - 올바른 예
88 |
89 | ```python
90 | # See details at
91 | # http://www.example.com/us/developer/documentation/api/content/v2.0/csv_file_name_extension_full_specification.html
92 | ```
93 |
94 | - 부적절한 예
95 |
96 | ```python
97 | # See details at
98 | # http://www.example.com/us/developer/documentation/api/content/\
99 | # v2.0/csv_file_name_extension_full_specification.html
100 | ```
101 |
102 | - 위의 예시에서 각 요소에 사용된 들여쓰기를 잘 기억하세요. 더 자세한 정보는 [들여쓰기](#s3.4-indentation) 챕터를 확인하세요.
103 | - 위에서 언급되지 않은 상황에서 한 줄의 길이가 80자를 초과함에도 [Black](https://github.com/psf/black) 혹은 [Pyink](https://github.com/google/pyink) 오토포메터가 별다른 도움을 주지 못한다면 80자 이상 초과가 허용됩니다. 작성자는 상식적인 수준내에서 위 문서의 사항을 참고하여 줄을 분리하는것이 바람직합니다.
104 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.3 괄호.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.3 Parentheses
4 |
5 | - 괄호를 적게 사용하세요.
6 |
7 | - 필요하지는 않지만 튜플의 양쪽에 괄호를 사용하여도 무방합니다.
8 | - 하지만 묵시적 문장연장이나 튜플을 나타내기 위한 상황을 제외하고 리턴문이나 조건문에는 사용하지 마세요.
9 |
10 | - 올바른 예
11 |
12 | ```python
13 | if foo:
14 | bar()
15 | while x:
16 | x = bar()
17 | if x and y:
18 | bar()
19 | if not x:
20 | bar()
21 | # For a 1 item tuple the ()s are more visually obvious than the comma.
22 | onesie = (foo,)
23 | return foo
24 | return spam, beans
25 | return (spam, beans)
26 | for (x, y) in dict.items(): ...
27 | ```
28 |
29 | - 부적절한 예
30 |
31 | ```python
32 | if (x):
33 | bar()
34 | if not(x):
35 | bar()
36 | return (foo)
37 | ```
38 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.4 들여쓰기.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.4 Indentation
4 |
5 | - 코드를 작성할 때 _4 칸_ 들여쓰기를 하세요.
6 |
7 | - 탭을 절대 사용하지 마세요. 암시된 줄 연속은 래핑된 요소를 수직으로 정렬해야 하며([줄 길이 예제](#s3.2-line-length) 참조), 또는 4개의 공백을 사용하여 행을 들여쓰기 하세요.
8 | - 닫는 괄호(원, 대각선 또는 중괄호)는 표현식의 끝에 배치하거나 별도의 줄에 배치할 수 있지만, 이 경우 해당 여는 괄호와 같은 줄에 들여쓰기해야 합니다.
9 |
10 | - 올바른 예
11 |
12 | ```python
13 | # 여는 구분 기호와 정렬됨
14 | foo = long_function_name(var_one, var_two,
15 | var_three, var_four)
16 | meal = (spam,
17 | beans)
18 |
19 | # 딕셔너리의 여는 구분 기호와 정렬됨
20 | foo = {
21 | 'long_dictionary_key': value1 +
22 | value2,
23 | ...
24 | }
25 |
26 | # 4칸 공백의 걸쳐서 들여쓰기, 첫 번째 줄에는 아무것도 없음
27 | foo = long_function_name(
28 | var_one, var_two, var_three,
29 | var_four)
30 | meal = (
31 | spam,
32 | beans)
33 |
34 | # 4칸 공백의 걸쳐서 들여쓰기; 첫 번째 줄에는 아무것도 없음, 닫는 괄호는 새 줄에 배치
35 | foo = long_function_name(
36 | var_one, var_two, var_three,
37 | var_four
38 | )
39 | meal = (
40 | spam,
41 | beans,
42 | )
43 | # 딕셔너리에서 4칸 공백의 걸쳐서 들여쓰기
44 | foo = {
45 | 'long_dictionary_key':
46 | long_dictionary_value,
47 | ...
48 | }
49 | ```
50 |
51 | - 부적절한 예
52 |
53 | ```python
54 | # 첫 번째 줄에 내용이 있어서는 안 됩니다.
55 | foo = long_function_name(var_one, var_two,
56 | var_three, var_four)
57 | meal = (spam,
58 | beans)
59 |
60 | # 2칸 공백의 걸쳐서 들여쓰기는 금지됩니다.
61 | foo = long_function_name(
62 | var_one, var_two, var_three,
63 | var_four)
64 |
65 | # 딕셔너리에서는 걸쳐서 들여쓰기를 사용하지 않습니다.
66 | foo = {
67 | 'long_dictionary_key':
68 | long_dictionary_value,
69 | ...
70 | }
71 | ```
72 |
73 |
74 |
75 | #### 3.4.1 원소 나열 시 후행 쉼표
76 |
77 | - 후행 쉼표는 시퀀스의 요소에서 닫는 구문 기호 `]`, `)`, 또는 `}`가 마지막 요소와 같은 줄에 나타나지 않는 경우와 단일 요소를 가진 튜플에 대해서만 권장됩니다.
78 | - 후행 쉼표의 존재는 Python 코드 자동 포맷터인 [Black](https://github.com/psf/black)이나 [Pyink](https://github.com/google/pyink)에게 마지막 요소 뒤에 `,`가 있을 때 항목의 컨테이너를 한 줄에 하나의 항목씩 자동으로 포맷하도록 지시하는 힌트로도 사용됩니다.
79 |
80 | - 올바른 예
81 |
82 | ```python
83 | golomb3 = [0, 1, 3]
84 | golomb4 = [
85 | 0,
86 | 1,
87 | 4,
88 | 6,
89 | ]
90 | ```
91 |
92 | - 부적절한 예
93 |
94 | ```python
95 | golomb4 = [
96 | 0,
97 | 1,
98 | 4,
99 | 6,]
100 | ```
101 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.5 빈 줄.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.5 Blank Lines
4 |
5 | - 함수 선언이든 객체 선언이든 최상위 선언문과는 2개의 빈 줄을 사이에 두어야 합니다.
6 | - 각 메소드 선언 또는 `class`의 docstring 줄과 젓 번째 메소드 선언 시 그 사이에는 한 개의 빈 줄이 있어야 합니다.
7 | - `def` 줄 이후에는 빈 줄이 없어야 합니다.
8 | - 함수와 메소드 사이에 개발자의 판단하에 적절하게 한 개의 빈 줄을 사용하세요.
9 |
10 | - 빈 줄을 정의에 고정할 필요는 없습니다.
11 | - 예를 들어, 함수와 클래스 및 메서드 정의 바로 앞에 있는 관련 주석이 의미가 있을 수 있습니다.
12 | - comment가 Docstring의 일부로 더 유용할 수 있는 지 고려해야합니다.
13 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.6 Whitespace.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.6 Whitespace
4 |
5 | - 표준 조판 규칙을 따라 구두점 주변에 스페이스를 사용하세요.
6 |
7 | - 괄호, 중괄호, 대괄호 내부에는 화이트스페이스 없어야 합니다.
8 |
9 | - 올바른 예
10 |
11 | ```python
12 | spam(ham[1], {'eggs']: 2}, [])
13 | ```
14 |
15 | - 부적절한 예
16 |
17 | ```python
18 | spam( ham[ 1 ], { 'eggs': 2 }, [ ] )
19 | ```
20 |
21 | - 컴마, 세미콜론, 콜론 앞에는 화이트스페이스가 없어야 합니다.
22 | - 문장 끝을 제외하고 컴마, 세미콜론, 콜론 뒤에 화이트스페이스를 사용하지 마세요.
23 |
24 | - 올바른 예
25 |
26 | ```python
27 | if x == 4:
28 | print(x, y)
29 | x, y = y, x
30 | ```
31 |
32 | - 부적절한 예
33 |
34 | ```python
35 | if x == 4 :
36 | print(x , y)
37 | x , y = y , x
38 | ```
39 |
40 | - 매개변수 목록, 인덱싱, 슬라이싱의 시작에 사용된 열린 소/중괄호 앞에는 화이트스페이스를 사용하지 마세요.
41 |
42 | - 올바른 예
43 |
44 | ```python
45 | spam(1)
46 | ```
47 |
48 | - 부적절한 예
49 |
50 | ```python
51 | spam (1)
52 | ```
53 |
54 | - 올바른 예
55 |
56 | ```python
57 | dict['key'] = list[index]
58 | ```
59 |
60 | - 부적절한 예
61 |
62 | ```python
63 | dict ['key'] = list [index]
64 | ```
65 |
66 | - 대입(`=`), 비교(`==, <, >, !=, <>, <=, >=, in, not in, is, is not`), 불린(`and, or, not`) 과 같은 바이너리 연산자는 앞, 뒤로 한 칸 띄우세요.
67 | - 수리 연산자 앞, 뒤의 공백은 개발자의 판단에 따라 사용하세요.
68 |
69 | - 올바른 예
70 |
71 | ```python
72 | x == 1
73 | ```
74 |
75 | - 부적절한 예
76 |
77 | ```python
78 | x<1
79 | ```
80 |
81 | - 한가지 예외사항인 [Type 지정이 존재할 떄](#s3.19.4-default-values)를 제외하고 키워드 매개변수나 매개변수의 기본값을 지정하는 경우 `=` 기호 앞뒤에는 공백을 사용하지 마세요.
82 | - 형 지정이 존재한다면 매개변수의 기본값을 지정할 때 `=` 앞뒤에 공백을 _사용_ 하세요.
83 |
84 | - 올바른 예
85 |
86 | ```python
87 | def complex(real, imag=0.0): return Magic(r=real, i=imag)
88 | def complex(real, imag: float = 0.0): return Magic(r=real, i=imag)
89 | ```
90 |
91 | - 부적절한 예
92 |
93 | ```python
94 | def complex(real, imag = 0.0): return Magic(r = real, i = imag)
95 | def complex(real, imag: float=0.0): return Magic(r = real, i = imag)
96 | ```
97 |
98 | - 유지보수에 짐이 되기 때문에 공백을 이용하여 연속된 여러 줄을 수직정렬하지 마세요 (`:`, `#`, `=` 등에 적용됩니다.).
99 |
100 | - 올바른 예
101 |
102 | ```python
103 | foo = 1000 # comment
104 | long_name = 2 # comment that should not be aligned
105 |
106 | dictionary = {
107 | 'foo': 1,
108 | 'long_name': 2,
109 | }
110 | ```
111 |
112 | - 부적절한 예
113 |
114 | ```python
115 | foo = 1000 # comment
116 | long_name = 2 # comment that should not be aligned
117 |
118 | dictionary = {
119 | 'foo' : 1,
120 | 'long_name': 2,
121 | }
122 | ```
123 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.7 Shebang_Line.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.7 Shebang Line
4 |
5 | - 대부분의 `.py` 파일은 `#!` 로 시작하지 않아도 됩니다.
6 | - [PEP-394](https://peps.python.org/pep-0394/)에 따라 프로그램의 메인 파일 첫 줄에 `#!/usr/bin/env python3` (virtualenvs 지원) 또는 `#!/usr/bin/python3`사용하면 됩니다.
7 |
8 | - 이 줄은 파이썬 파일을 import 할때는 무시되지만 실행 될때는 커널이 어떤 파이썬 인터프리터를 사용해야 하는지 알려줍니다.
9 | - 따라서 직접 실행될 파일에 기록하는것이 적합합니다.
10 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/3.8 주석과 docstring.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.8 Comments and Docstrings
4 |
5 | - 모듈, 함수, 메소드에 올바른 형식의 docstring과 인라인 주석을 사용하세요.
6 |
7 |
8 |
9 | #### 3.8.1 Docstrings
10 |
11 | - 파이썬은 코드를 문서화 할 때 _docstring_ 을 사용합니다.
12 | - docstring 은 패키지, 모듈, 클래스나 함수의 첫번째 선언되는 문자열입니다.
13 | - 이 문자열은 `pydoc` 이 사용하는 `__doc__` 멤버 오브젝트에서 자동으로 추출될 수 있습니다. (여러분의 모듈에서 `pydoc` 를 실행 후 결과를 확인해보세요)
14 | - [PEP257](https://peps.python.org/pep-0257/) 에 따라 docstring 을 시작하거나 끝낼 때는 `"""` 를 사용하세요.
15 | - docstring은 마침표, 물음표, 느낌표로 끝나는 요약줄(한 줄)로 시작하여야 하며 한 줄의 공백을 두고 내용을 담고있는 나머지 docstring 이 이어져야 합니다.
16 | - 또한 내용을 담고있는 docstring 은 `"""` 와 같은 커서위치에서 시작하여야 합니다.
17 |
18 |
19 |
20 | #### 3.8.2 Modules
21 |
22 | - 프로젝트에 알맞는 라이센스 보일러 플레이트를 선택하세요. (예를 들면, Apache 2.0, BSD, LGPL, GPL)
23 | - 모든 파일은 라이센스 보일러 플레이트를 가지고 있어야 합니다.
24 |
25 | ```python
26 | """모듈이나 프로그램에 대한 한 줄 요약으로, 마침표로 끝나야 합니다.
27 |
28 | 한 줄을 비워두세요. 이 docstring의 나머지 부분에는 모듈이나 프로그램에
29 | 대한 전반적인 설명이 포함되어야 합니다. 선택적으로, 내보낸 클래스와
30 | 함수에 대한 간단한 설명 및/또는 사용 예시도 포함될 수 있습니다.
31 |
32 | 전형적인 사용 예시:
33 |
34 | foo = ClassFoo()
35 | bar = foo.FunctionBar()
36 | """
37 | ```
38 |
39 |
40 |
41 |
42 | ##### 3.8.2.1 Test modules
43 |
44 | - 테스트 파일의 모듈 수준 docstring은 필수는 아닙니다.
45 | - 추가적인 정보를 제공할 필요가 있는 경우에만 포함해야 합니다.
46 | - 예를 들면, 테스트를 실행하는 방법에 대한 구체적인 내용, 특이한 설정 패턴에 대한 설명, 외부 환경에 대한 의존성 등이 포함될 수 있습니다.
47 |
48 | ```python
49 | """이 Blaze 테스트는 golden 파일을 사용합니다.
50 | `google3` 디렉토리에서
51 | `blaze run //foo/bar:foo_test -- --update_golden_files` 명령어를 실행하여
52 | 이러한 파일을 업데이트할 수 있습니다.
53 | """
54 | ```
55 |
56 | - 새로운 정보를 제공하지 않는 docstring은 사용하지 말아야 합니다.
57 |
58 | ```python
59 | """Tests for foo.bar."""
60 | ```
61 |
62 |
63 |
64 | #### 3.8.3 Functions and Methods
65 |
66 | - 이 섹션에서 ‘function’은 메소드, 함수, 제너레이터 또는 속성을 의미합니다.
67 |
68 | - 다음 중 하나 이상의 속성을 가진 모든 함수에는 docstring이 필수입니다.
69 |
70 | - 공개 API의 일부인 경우
71 | - 비교적 큰 경우
72 | - 직관적이지 않은 로직을 가진 경우
73 |
74 | - docstring은 함수의 코드를 읽지 않고도 함수 호출을 작성할 수 있을 만큼 충분한 정보를 제공해야 합니다.
75 | - docstring은 함수의 호출 구문과 의미를 설명해야 하며, 일반적으로 구현 세부 사항은 포함하지 않아야 하지만, 이러한 세부 사항이 함수 사용 방법에 중요하다면 예외입니다.
76 | - 예를 들어, 인자를 사이드 임펙트로 변경하는 함수는 그 점을 docstring에 명시해야 합니다.
77 |
78 | - 그렇지 않으면, 호출자에게 중요하지 않은 함수 구현의 미묘하지만 중요한 세부 사항은 함수의 docstring보다는 코드 옆에 주석으로 표현하는 것이 좋습니다.
79 | - docstring은 서술형(`"""Fetches rows from a Bigtable."""`) 또는 명령형(`"""Fetch rows from a Bigtable."""`) 스타일일 수 있지만, 파일 내에서 스타일은 일관되게 유지해야 합니다.
80 | - `@property` 속성의 docstring은 속성이나 [함수 인자](#doc-function-args)의 docstring과 같은 스타일을 사용해야 합니다 (`"""The Bigtable path."""` 대신에 `"""Returns the Bigtable path."""`).
81 |
82 | - 함수의 특정 측면은 아래에 나열된 특별한 섹션에서 문서화해야 합니다.
83 | - 각 섹션은 콜론으로 끝나는 제목 행으로 시작합니다.
84 | - 제목을 제외한 모든 섹션은 2칸 또는 4칸 공백의 걸쳐서 들여쓰기를 유지해야 합니다 (파일 내에서 일관되게 유지).
85 | - 함수의 이름과 시그니처가 충분히 정보를 제공하여 한 줄의 docstring으로 적절히 설명할 수 있는 경우, 이러한 섹션은 생략할 수 있습니다.
86 |
87 |
88 |
89 | ##### [_Args:_](#doc-function-args)
90 |
91 | - 매개변수를 각각 이름으로 나열합니다. 각 이름에는 설명문이 따르며 콜론 뒤에 공백이나 새로운 라인으로 분리되어야 합니다.
92 | - 만약 설명문이 너무 길어 한 줄인 80자를 초과할 경우 매개변수 이름보다 2칸 또는 4칸의 들여쓰기를 사용합니다.(파일의 나머지 문서(docstring)와 일치합니다.)
93 | - 만약 코드가 자료형에 대한 주석을 담고 있지 않다면 설명문은 요구되는 자료형을 포함해서 기록해야 합니다.
94 | - 함수가 `*foo`(가변길이의 매개변수 리스트) 또는 `**bar`(임의의 키워드 매개변수)를 받는다면 `*foo` 와 `**bar`로 기록되어야 합니다.
95 |
96 |
97 |
98 | ##### [_Returns:_ (제너레이터에는 _Yields:_)](#doc-function-returns)
99 |
100 | - 반환 값의 의미를 설명하고, 타입 어노테이션에서 제공하지 않는 타입 정보도 포함해야 합니다.
101 | - 함수가 None만 반환하는 경우, 이 섹션은 필요하지 않습니다.
102 | - docstring이 "Return", "Returns", "Yield", "Yields"로 시작하고(e.g. `"""Returns row from Bigtable as a tuple of strings."""`), 첫 번째 문장이 반환 값을 설명하기에 충분할 경우, 이 섹션은 생략될 수 있습니다.
103 | - 이전의 'NumPy 스타일'을 모방하지 마세요. ([example](https://numpy.org/doc/1.24/reference/generated/numpy.linalg.qr.html)) 이 스타일은 종종 튜플 반환 값을 여러 개의 개별 반환 값처럼 각각의 이름으로 문서화했습니다. (튜플이라는 점을 언급하지 않고)
104 | - 대신, 반환 값을 다음과 같이 설명하세요: "Returns: A tuple (mat_a, mat_b), where mat_a is ..., and ...".
105 | - docstring에서 사용되는 설명용 이름은 함수 본문에서 사용되는 내부 이름과 반드시 일치할 필요는 없습니다 (내부 이름은 API의 일부가 아니기 때문입니다)
106 | - 함수가 `yield`를 사용하는 경우(즉, 제너레이터인 경우), `Yields:` 섹션에서는 호출 결과로 반환되는 제너레이터 객체가 아니라, `next()`에 의해 반환되는 객체를 문서화해야 합니다.
107 |
108 |
109 |
110 | ##### [_Raises:_](#doc-function-raises)
111 |
112 | - interface와 관련된 모든 예외를 설명 뒤에 나열합니다.
113 | - `Args:`에 설명된 것과 유사한 예외 이름 + 콜론 + 공백 또는 줄 바꿈과 hanging indent 스타일을 사용하세요.
114 | - 명시된 API가 docstring을 위반했을 될 경우, 예외를 문서화하지 않습니다. (왜냐하면 이것은 역설적으로 API의 API를 위반하는 행동을 만들 수 있기 때문이다.)
115 |
116 | ```python
117 | def fetch_smalltable_rows(
118 | table_handle: smalltable.Table,
119 | keys: Sequence[bytes | str],
120 | require_all_keys: bool = False,
121 | ) -> Mapping[bytes, tuple[str, ...]]:
122 | """Fetches rows from a Smalltable.
123 |
124 | Retrieves rows pertaining to the given keys from the Table instance
125 | represented by table_handle. String keys will be UTF-8 encoded.
126 |
127 | Args:
128 | table_handle: An open smalltable.Table instance.
129 | keys: A sequence of strings representing the key of each table
130 | row to fetch. String keys will be UTF-8 encoded.
131 | require_all_keys: If True only rows with values set for all keys will be
132 | returned.
133 |
134 | Returns:
135 | A dict mapping keys to the corresponding table row data
136 | fetched. Each row is represented as a tuple of strings. For
137 | example:
138 |
139 | {b'Serak': ('Rigel VII', 'Preparer'),
140 | b'Zim': ('Irk', 'Invader'),
141 | b'Lrrr': ('Omicron Persei 8', 'Emperor')}
142 |
143 | Returned keys are always bytes. If a key from the keys argument is
144 | missing from the dictionary, then that row was not found in the
145 | table (and require_all_keys must have been False).
146 |
147 | Raises:
148 | IOError: An error occurred accessing the smalltable.
149 | """
150 | ```
151 |
152 | - 마찬가지로, 줄 바꿈이 있는 `Args:`도 허용합니다.
153 |
154 | ```python
155 | def fetch_smalltable_rows(
156 | table_handle: smalltable.Table,
157 | keys: Sequence[bytes | str],
158 | require_all_keys: bool = False,
159 | ) -> Mapping[bytes, tuple[str, ...]]:
160 | """Fetches rows from a Smalltable.
161 |
162 | Retrieves rows pertaining to the given keys from the Table instance
163 | represented by table_handle. String keys will be UTF-8 encoded.
164 |
165 | Args:
166 | table_handle:
167 | An open smalltable.Table instance.
168 | keys:
169 | A sequence of strings representing the key of each table row to
170 | fetch. String keys will be UTF-8 encoded.
171 | require_all_keys:
172 | If True only rows with values set for all keys will be returned.
173 |
174 | Returns:
175 | A dict mapping keys to the corresponding table row data
176 | fetched. Each row is represented as a tuple of strings. For
177 | example:
178 |
179 | {b'Serak': ('Rigel VII', 'Preparer'),
180 | b'Zim': ('Irk', 'Invader'),
181 | b'Lrrr': ('Omicron Persei 8', 'Emperor')}
182 |
183 | Returned keys are always bytes. If a key from the keys argument is
184 | missing from the dictionary, then that row was not found in the
185 | table (and require_all_keys must have been False).
186 |
187 | Raises:
188 | IOError: An error occurred accessing the smalltable.
189 | """
190 | ```
191 |
192 |
193 |
194 |
195 | ##### 3.8.3.1 Overridden Methods
196 |
197 | - 기본 클래스의 메서드를 오버라이드하는 메서드는 [`@override`](https://typing-extensions.readthedocs.io/en/latest/#override) 데코레이터(`typing_extensions` 또는 `typing` 모듈에서 제공)를 명시적으로 사용하는 경우 docstring이 필요하지 않습니다.
198 | - 단, 오버라이딩된 메서드의 동작이 기본 메서드의 계약을 실질적으로 개선하거나, 추가적인 사이드 임펙트 등을 문서화해야 하는 경우에는, 그러한 차이점이 최소한 포함된 docstring이 오버라이딩 메서드에 필요합니다.
199 |
200 | ```python
201 | from typing_extensions import override
202 | class Parent:
203 | def do_something(self):
204 | """Parent method, includes docstring."""
205 | # 자식 클래스, 오버라이드로 주석이 달린 메서드.
206 | class Child(Parent):
207 | @override
208 | def do_something(self):
209 | pass
210 | ```
211 |
212 | ```python
213 | # 자식 클래스에서 @override 데코레이터가 없는 경우, docstring이 필요합니다.
214 | class Child(Parent):
215 | def do_something(self):
216 | pass
217 | # docstring이 단순한 경우, @override만으로도 문서가 기본 클래스에 있음을 표시할 수 있습니다.
218 | class Child(Parent):
219 | @override
220 | def do_something(self):
221 | """See base class."""
222 | ```
223 |
224 |
225 |
226 | #### 3.8.4 Classes
227 |
228 | - 클래스는 선언 바로 아래에 해당 클래스를 설명하는 docstring 를 가지고 있어야 합니다.
229 | - [properties](#properties)을 제외한 공개 속성은 `Attributes` 섹션에서 문서화해야 하며, [함수의 `Args`](#doc-function-args) 섹션과 동일한 형식을 따라야 합니다.
230 |
231 | ```python
232 | class SampleClass:
233 | """Summary of class here.
234 |
235 | Longer class information...
236 | Longer class information...
237 |
238 | Attributes:
239 | likes_spam: A boolean indicating if we like SPAM or not.
240 | eggs: An integer count of the eggs we have laid.
241 | """
242 |
243 | def __init__(self, likes_spam: bool = False):
244 | """Initializes the instance based on spam preference.
245 | Args:
246 | likes_spam: Defines if instance exhibits this preference.
247 | """
248 | self.likes_spam = likes_spam
249 | self.eggs = 0
250 |
251 | @property
252 | def butter_sticks(self) -> int:
253 | """The number of butter sticks we have."""
254 | ```
255 |
256 | - 모든 클래스의 docstring은 클래스 인스턴스가 무엇을 나타내는지를 설명하는 한 줄 요약으로 시작해야 합니다. 이는 `Exception`의 서브클래스도 예외가 무엇을 나타내는지를 설명해야 하며, 발생할 수 있는 컨텍스트에 대해서는 설명하지 않아야 함을 의미합니다. 클래스의 docstring은 클래스가 클래스라는 등의 불필요한 정보를 반복해서는 안 됩니다.
257 |
258 | - 올바른 예
259 |
260 | ```python
261 | class CheeseShopAddress:
262 | """The address of a cheese shop.
263 | ...
264 | """
265 | class OutOfCheeseError(Exception):
266 | """No more cheese is available."""
267 | ```
268 |
269 | - 부적절한 예
270 |
271 | ```python
272 | class CheeseShopAddress:
273 | """Class that describes the address of a cheese shop.
274 | ...
275 | """
276 | class OutOfCheeseError(Exception):
277 | """Raised when no more cheese is available."""
278 | ```
279 |
280 |
281 |
282 |
283 | #### 3.8.5 Block and Inline Comments
284 |
285 | - 마지막으로 주석을 달아야 하는 곳은 코드의 복잡한 부분입니다.
286 | - 만약 추후 [code review](http://en.wikipedia.org/wiki/Code_review)에서 코드를 설명하려고 한다면 지금 주석을 달아두어야 합니다.
287 | - 복잡한 동작은 시작하기 전에 몇 줄의 주석을 달아야 합니다.
288 | - 잘 알려져 있지 않는 부분은 끝에 주석을 달아야 합니다.
289 |
290 | ```python
291 | # We use a weighted dictionary search to find out where i is in
292 | # the array. We extrapolate position based on the largest num
293 | # in the array and the array size and then do binary search to
294 | # get the exact number.
295 |
296 | if i & (i-1) == 0: # True if i is 0 or a power of 2.
297 | ```
298 |
299 | - 가독성 향상을 위해 이러한 주석들은 코드에서 최소 2줄 떨어져 있어야 합니다.
300 |
301 | - 하지만 코드 자체를 설명하지는 마세요.
302 | - 코드를 읽고 있는 사람이 여러분보다 파이썬을 더 잘 알고 있다고 가정하세요. (물론 그게 중요한 것은 아닙니다.)
303 |
304 | - 부적절한 예(주석)
305 |
306 | ```python
307 | # Now go through the b array and make sure whenever i occurs
308 | # the next element is i+1
309 | ```
310 |
311 |
312 |
313 | #### 3.8.6 Punctuation, Spelling and Grammar
314 |
315 | - 스펠링과 문법 그리고 구두점에 주의를 기울이세요. 잘 써진 주석이 읽기도 편합니다.
316 |
317 | - 주석은 마치 말하는 것처럼 자연스럽게 읽을 수 있어야 하며 영문 주석의 경우 올바른 대문자와 구두점이 필요합니다.
318 | - 대부분의 경우 조각난 문장보다 온전한 문장이 높은 가독성을 가집니다.
319 | - 코드 끝에 붙는 짧은 주석 등의 경우 다소 형식적이지 않아도 되지만, 전체적인 일관성을 맞추어야 합니다.
320 |
321 | - 코드 리뷰어가 세미콜론이 사용되어야 하는데 컴마를 사용했다고 지적하는 것은 불만스러울 수 있지만 소스코드가 높은 수준의 명료성과 가독성을 가지는것은 매우 중요합니다.
322 | - 올바른 구두점, 스펠링 그리고 문법은 이를 얻을 수 있도록 도와줍니다.
323 |
--------------------------------------------------------------------------------
/Google Python Style Guide/3. Python 스타일 규칙/ReadMe.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 3.1 Semicolons
4 |
5 | - 세미콜론을 이용해서 문장을 끝내거나 한 줄에 2개의 구문을 작성하지 마세요.
6 |
7 | ---
8 |
9 |
10 | ### 3.2 Line length
11 |
12 | - 최대 줄 길이는 _80자_ 입니다.
13 |
14 | - 예외
15 | - 긴 import 구문
16 | - URLs, 경로이름, 또는 주석의 긴 플래그
17 | - 경로이름이나 URLs와 같은 공백을 포함하지 않는 긴 모듈수준 문자상수는 여러 줄에 나누어 기록하기 불편할 경우
18 | - Pylint 비활성화 주석문 (e.g.: `# pylint: disable=invalid-name`)
19 |
20 | - [명시적인 줄 연속](https://docs.python.org/3/reference/lexical_analysis.html#explicit-line-joining)을 위해 백슬래시를 사용하지 마세요.
21 | - 대신에 Python의 [소/중/대 괄호 내부의 묵시적 라인결합](http://docs.python.org/reference/lexical_analysis.html#implicit-line-joining)을 사용하세요.
22 | - 필요하다면, 구문 양쪽에 추가로 괄호를 더할 수 있습니다.
23 | - 이 규칙은 문자열 내에서 백슬래시로 이스케이프된 개행을 금지하지 않습니다(아래 [참조](#strings)).
24 |
25 | - 올바른 예
26 |
27 | ```python
28 | foo_bar(self, width, height, color='black', design=None, x='foo',
29 | emphasis=None, highlight=0)
30 |
31 | if (width == 0 and height == 0 and
32 | color == 'red' and emphasis == 'strong'):
33 | (bridge_questions.clarification_on
34 | .average_airspeed_of.unladen_swallow) = 'African or European?'
35 | with (
36 | very_long_first_expression_function() as spam,
37 | very_long_second_expression_function() as beans,
38 | third_thing() as eggs,
39 | ):
40 | place_order(eggs, beans, spam, beans)
41 | ```
42 |
43 | - 부적절한 예
44 |
45 | ```python
46 | if width == 0 and height == 0 and \
47 | color == 'red' and emphasis == 'strong':
48 | bridge_questions.clarification_on \
49 | .average_airspeed_of.unladen_swallow = 'African or European?'
50 | with very_long_first_expression_function() as spam, \
51 | very_long_second_expression_function() as beans, \
52 | third_thing() as eggs:
53 | place_order(eggs, beans, spam, beans)
54 | ```
55 |
56 | - 만약 리터럴 문자열을 한 줄에 표현하기 어렵다면 아래와 같이 괄호를 이용하여 묵시적 라인결합을 사용하세요.
57 |
58 | ```python
59 | x = ('This will build a very long long '
60 | 'long long long long long long string')
61 | ```
62 |
63 | - 가능한 가장 높은 구문 수준에서 줄을 나누는 것을 선호하세요. 줄을 두 번 나눠야 하는 경우, 두 번 모두 동일한 구문 수준에서 나누세요.
64 |
65 | - 올바른 예
66 |
67 | ```python
68 | bridgekeeper.answer(
69 | name="Arthur", quest=questlib.find(owner="Arthur", perilous=True))
70 | answer = (a_long_line().of_chained_methods()
71 | .that_eventually_provides().an_answer())
72 | if (
73 | config is None
74 | or 'editor.language' not in config
75 | or config['editor.language'].use_spaces is False
76 | ):
77 | use_tabs()
78 | ```
79 |
80 | - 부적절한 예
81 |
82 | ```python
83 | bridgekeeper.answer(name="Arthur", quest=questlib.find(
84 | owner="Arthur", perilous=True))
85 | answer = a_long_line().of_chained_methods().that_eventually_provides(
86 | ).an_answer()
87 | if (config is None or 'editor.language' not in config or config[
88 | 'editor.language'].use_spaces is False):
89 | use_tabs()
90 | ```
91 |
92 | - 주석의 경우 긴 URLs 들은 한줄에 표현하세요.
93 |
94 | - 올바른 예
95 |
96 | ```python
97 | # See details at
98 | # http://www.example.com/us/developer/documentation/api/content/v2.0/csv_file_name_extension_full_specification.html
99 | ```
100 |
101 | - 부적절한 예
102 |
103 | ```python
104 | # See details at
105 | # http://www.example.com/us/developer/documentation/api/content/\
106 | # v2.0/csv_file_name_extension_full_specification.html
107 | ```
108 |
109 | - 위의 예시에서 각 요소에 사용된 들여쓰기를 잘 기억하세요. 더 자세한 정보는 [들여쓰기](#s3.4-indentation) 챕터를 확인하세요.
110 | - 위에서 언급되지 않은 상황에서 한 줄의 길이가 80자를 초과함에도 [Black](https://github.com/psf/black) 혹은 [Pyink](https://github.com/google/pyink) 오토포메터가 별다른 도움을 주지 못한다면 80자 이상 초과가 허용됩니다. 작성자는 상식적인 수준내에서 위 문서의 사항을 참고하여 줄을 분리하는것이 바람직합니다.
111 |
112 | ---
113 |
114 |
115 | ### 3.3 Parentheses
116 |
117 | - 괄호를 적게 사용하세요.
118 |
119 | - 필요하지는 않지만 튜플의 양쪽에 괄호를 사용하여도 무방합니다.
120 | - 하지만 묵시적 문장연장이나 튜플을 나타내기 위한 상황을 제외하고 리턴문이나 조건문에는 사용하지 마세요.
121 |
122 | - 올바른 예
123 |
124 | ```python
125 | if foo:
126 | bar()
127 | while x:
128 | x = bar()
129 | if x and y:
130 | bar()
131 | if not x:
132 | bar()
133 | # For a 1 item tuple the ()s are more visually obvious than the comma.
134 | onesie = (foo,)
135 | return foo
136 | return spam, beans
137 | return (spam, beans)
138 | for (x, y) in dict.items(): ...
139 | ```
140 |
141 | - 부적절한 예
142 |
143 | ```python
144 | if (x):
145 | bar()
146 | if not(x):
147 | bar()
148 | return (foo)
149 | ```
150 |
151 | ---
152 |
153 |
154 | ### 3.4 Indentation
155 |
156 | - 코드를 작성할 때 _4 칸_ 들여쓰기를 하세요.
157 |
158 | - 탭을 절대 사용하지 마세요. 암시된 줄 연속은 래핑된 요소를 수직으로 정렬해야 하며([줄 길이 예제](#s3.2-line-length) 참조), 또는 4개의 공백을 사용하여 행을 들여쓰기 하세요.
159 | - 닫는 괄호(원, 대각선 또는 중괄호)는 표현식의 끝에 배치하거나 별도의 줄에 배치할 수 있지만, 이 경우 해당 여는 괄호와 같은 줄에 들여쓰기해야 합니다.
160 |
161 | - 올바른 예
162 |
163 | ```python
164 | # 여는 구분 기호와 정렬됨
165 | foo = long_function_name(var_one, var_two,
166 | var_three, var_four)
167 | meal = (spam,
168 | beans)
169 |
170 | # 딕셔너리의 여는 구분 기호와 정렬됨
171 | foo = {
172 | 'long_dictionary_key': value1 +
173 | value2,
174 | ...
175 | }
176 |
177 | # 4칸 공백의 걸쳐서 들여쓰기, 첫 번째 줄에는 아무것도 없음
178 | foo = long_function_name(
179 | var_one, var_two, var_three,
180 | var_four)
181 | meal = (
182 | spam,
183 | beans)
184 |
185 | # 4칸 공백의 걸쳐서 들여쓰기; 첫 번째 줄에는 아무것도 없음, 닫는 괄호는 새 줄에 배치
186 | foo = long_function_name(
187 | var_one, var_two, var_three,
188 | var_four
189 | )
190 | meal = (
191 | spam,
192 | beans,
193 | )
194 | # 딕셔너리에서 4칸 공백의 걸쳐서 들여쓰기
195 | foo = {
196 | 'long_dictionary_key':
197 | long_dictionary_value,
198 | ...
199 | }
200 | ```
201 |
202 | - 부적절한 예
203 |
204 | ```python
205 | # 첫 번째 줄에 내용이 있어서는 안 됩니다.
206 | foo = long_function_name(var_one, var_two,
207 | var_three, var_four)
208 | meal = (spam,
209 | beans)
210 |
211 | # 2칸 공백의 걸쳐서 들여쓰기는 금지됩니다.
212 | foo = long_function_name(
213 | var_one, var_two, var_three,
214 | var_four)
215 |
216 | # 딕셔너리에서는 걸쳐서 들여쓰기를 사용하지 않습니다.
217 | foo = {
218 | 'long_dictionary_key':
219 | long_dictionary_value,
220 | ...
221 | }
222 | ```
223 |
224 |
225 |
226 | #### 3.4.1 원소 나열 시 후행 쉼표
227 |
228 | - 후행 쉼표는 시퀀스의 요소에서 닫는 구문 기호 `]`, `)`, 또는 `}`가 마지막 요소와 같은 줄에 나타나지 않는 경우와 단일 요소를 가진 튜플에 대해서만 권장됩니다.
229 | - 후행 쉼표의 존재는 Python 코드 자동 포맷터인 [Black](https://github.com/psf/black)이나 [Pyink](https://github.com/google/pyink)에게 마지막 요소 뒤에 `,`가 있을 때 항목의 컨테이너를 한 줄에 하나의 항목씩 자동으로 포맷하도록 지시하는 힌트로도 사용됩니다.
230 |
231 | - 올바른 예
232 |
233 | ```python
234 | golomb3 = [0, 1, 3]
235 | golomb4 = [
236 | 0,
237 | 1,
238 | 4,
239 | 6,
240 | ]
241 | ```
242 |
243 | - 부적절한 예
244 |
245 | ```python
246 | golomb4 = [
247 | 0,
248 | 1,
249 | 4,
250 | 6,]
251 | ```
252 |
253 | ---
254 |
255 |
256 | ### 3.5 Blank Lines
257 |
258 | - 함수 선언이든 객체 선언이든 최상위 선언문과는 2개의 빈 줄을 사이에 두어야 합니다.
259 | - 각 메소드 선언 또는 `class`의 docstring 줄과 젓 번째 메소드 선언 시 그 사이에는 한 개의 빈 줄이 있어야 합니다.
260 | - `def` 줄 이후에는 빈 줄이 없어야 합니다.
261 | - 함수와 메소드 사이에 개발자의 판단하에 적절하게 한 개의 빈 줄을 사용하세요.
262 |
263 | - 빈 줄을 정의에 고정할 필요는 없습니다.
264 | - 예를 들어, 함수와 클래스 및 메서드 정의 바로 앞에 있는 관련 주석이 의미가 있을 수 있습니다.
265 | - comment가 Docstring의 일부로 더 유용할 수 있는 지 고려해야합니다.
266 |
267 | ---
268 |
269 |
270 | ### 3.6 Whitespace
271 |
272 | - 표준 조판 규칙을 따라 구두점 주변에 스페이스를 사용하세요.
273 |
274 | - 괄호, 중괄호, 대괄호 내부에는 화이트스페이스 없어야 합니다.
275 |
276 | - 올바른 예
277 |
278 | ```python
279 | spam(ham[1], {'eggs']: 2}, [])
280 | ```
281 |
282 | - 부적절한 예
283 |
284 | ```python
285 | spam( ham[ 1 ], { 'eggs': 2 }, [ ] )
286 | ```
287 |
288 | - 컴마, 세미콜론, 콜론 앞에는 화이트스페이스가 없어야 합니다.
289 | - 문장 끝을 제외하고 컴마, 세미콜론, 콜론 뒤에 화이트스페이스를 사용하지 마세요.
290 |
291 | - 올바른 예
292 |
293 | ```python
294 | if x == 4:
295 | print(x, y)
296 | x, y = y, x
297 | ```
298 |
299 | - 부적절한 예
300 |
301 | ```python
302 | if x == 4 :
303 | print(x , y)
304 | x , y = y , x
305 | ```
306 |
307 | - 매개변수 목록, 인덱싱, 슬라이싱의 시작에 사용된 열린 소/중괄호 앞에는 화이트스페이스를 사용하지 마세요.
308 |
309 | - 올바른 예
310 |
311 | ```python
312 | spam(1)
313 | ```
314 |
315 | - 부적절한 예
316 |
317 | ```python
318 | spam (1)
319 | ```
320 |
321 | - 올바른 예
322 |
323 | ```python
324 | dict['key'] = list[index]
325 | ```
326 |
327 | - 부적절한 예
328 |
329 | ```python
330 | dict ['key'] = list [index]
331 | ```
332 |
333 | - 대입(`=`), 비교(`==, <, >, !=, <>, <=, >=, in, not in, is, is not`), 불린(`and, or, not`) 과 같은 바이너리 연산자는 앞, 뒤로 한 칸 띄우세요.
334 | - 수리 연산자 앞, 뒤의 공백은 개발자의 판단에 따라 사용하세요.
335 |
336 | - 올바른 예
337 |
338 | ```python
339 | x == 1
340 | ```
341 |
342 | - 부적절한 예
343 |
344 | ```python
345 | x<1
346 | ```
347 |
348 | - 한가지 예외사항인 [Type 지정이 존재할 떄](#s3.19.4-default-values)를 제외하고 키워드 매개변수나 매개변수의 기본값을 지정하는 경우 `=` 기호 앞뒤에는 공백을 사용하지 마세요.
349 | - 형 지정이 존재한다면 매개변수의 기본값을 지정할 때 `=` 앞뒤에 공백을 _사용_ 하세요.
350 |
351 | - 올바른 예
352 |
353 | ```python
354 | def complex(real, imag=0.0): return Magic(r=real, i=imag)
355 | def complex(real, imag: float = 0.0): return Magic(r=real, i=imag)
356 | ```
357 |
358 | - 부적절한 예
359 |
360 | ```python
361 | def complex(real, imag = 0.0): return Magic(r = real, i = imag)
362 | def complex(real, imag: float=0.0): return Magic(r = real, i = imag)
363 | ```
364 |
365 | - 유지보수에 짐이 되기 때문에 공백을 이용하여 연속된 여러 줄을 수직정렬하지 마세요 (`:`, `#`, `=` 등에 적용됩니다.).
366 |
367 | - 올바른 예
368 |
369 | ```python
370 | foo = 1000 # comment
371 | long_name = 2 # comment that should not be aligned
372 |
373 | dictionary = {
374 | 'foo': 1,
375 | 'long_name': 2,
376 | }
377 | ```
378 |
379 | - 부적절한 예
380 |
381 | ```python
382 | foo = 1000 # comment
383 | long_name = 2 # comment that should not be aligned
384 |
385 | dictionary = {
386 | 'foo' : 1,
387 | 'long_name': 2,
388 | }
389 | ```
390 |
391 | ---
392 |
393 |
394 | ### 3.7 Shebang Line
395 |
396 | - 대부분의 `.py` 파일은 `#!` 로 시작하지 않아도 됩니다.
397 | - [PEP-394](https://peps.python.org/pep-0394/)에 따라 프로그램의 메인 파일 첫 줄에 `#!/usr/bin/env python3` (virtualenvs 지원) 또는 `#!/usr/bin/python3`사용하면 됩니다.
398 |
399 | - 이 줄은 파이썬 파일을 import 할때는 무시되지만 실행 될때는 커널이 어떤 파이썬 인터프리터를 사용해야 하는지 알려줍니다.
400 | - 따라서 직접 실행될 파일에 기록하는것이 적합합니다.
401 |
402 | ---
403 |
404 |
405 | ### 3.8 Comments and Docstrings
406 |
407 | - 모듈, 함수, 메소드에 올바른 형식의 docstring과 인라인 주석을 사용하세요.
408 |
409 |
410 |
411 | #### 3.8.1 Docstrings
412 |
413 | - 파이썬은 코드를 문서화 할 때 _docstring_ 을 사용합니다.
414 | - docstring 은 패키지, 모듈, 클래스나 함수의 첫번째 선언되는 문자열입니다.
415 | - 이 문자열은 `pydoc` 이 사용하는 `__doc__` 멤버 오브젝트에서 자동으로 추출될 수 있습니다. (여러분의 모듈에서 `pydoc` 를 실행 후 결과를 확인해보세요)
416 | - [PEP257](https://peps.python.org/pep-0257/) 에 따라 docstring 을 시작하거나 끝낼 때는 `"""` 를 사용하세요.
417 | - docstring은 마침표, 물음표, 느낌표로 끝나는 요약줄(한 줄)로 시작하여야 하며 한 줄의 공백을 두고 내용을 담고있는 나머지 docstring 이 이어져야 합니다.
418 | - 또한 내용을 담고있는 docstring 은 `"""` 와 같은 커서위치에서 시작하여야 합니다.
419 |
420 |
421 |
422 | #### 3.8.2 Modules
423 |
424 | - 프로젝트에 알맞는 라이센스 보일러 플레이트를 선택하세요. (예를 들면, Apache 2.0, BSD, LGPL, GPL)
425 | - 모든 파일은 라이센스 보일러 플레이트를 가지고 있어야 합니다.
426 |
427 | ```python
428 | """모듈이나 프로그램에 대한 한 줄 요약으로, 마침표로 끝나야 합니다.
429 |
430 | 한 줄을 비워두세요. 이 docstring의 나머지 부분에는 모듈이나 프로그램에
431 | 대한 전반적인 설명이 포함되어야 합니다. 선택적으로, 내보낸 클래스와
432 | 함수에 대한 간단한 설명 및/또는 사용 예시도 포함될 수 있습니다.
433 |
434 | 전형적인 사용 예시:
435 |
436 | foo = ClassFoo()
437 | bar = foo.FunctionBar()
438 | """
439 | ```
440 |
441 |
442 |
443 |
444 | ##### 3.8.2.1 Test modules
445 |
446 | - 테스트 파일의 모듈 수준 docstring은 필수는 아닙니다.
447 | - 추가적인 정보를 제공할 필요가 있는 경우에만 포함해야 합니다.
448 | - 예를 들면, 테스트를 실행하는 방법에 대한 구체적인 내용, 특이한 설정 패턴에 대한 설명, 외부 환경에 대한 의존성 등이 포함될 수 있습니다.
449 |
450 | ```python
451 | """이 Blaze 테스트는 golden 파일을 사용합니다.
452 | `google3` 디렉토리에서
453 | `blaze run //foo/bar:foo_test -- --update_golden_files` 명령어를 실행하여
454 | 이러한 파일을 업데이트할 수 있습니다.
455 | """
456 | ```
457 |
458 | - 새로운 정보를 제공하지 않는 docstring은 사용하지 말아야 합니다.
459 |
460 | ```python
461 | """Tests for foo.bar."""
462 | ```
463 |
464 |
465 |
466 | #### 3.8.3 Functions and Methods
467 |
468 | - 이 섹션에서 ‘function’은 메소드, 함수, 제너레이터 또는 속성을 의미합니다.
469 |
470 | - 다음 중 하나 이상의 속성을 가진 모든 함수에는 docstring이 필수입니다.
471 |
472 | - 공개 API의 일부인 경우
473 | - 비교적 큰 경우
474 | - 직관적이지 않은 로직을 가진 경우
475 |
476 | - docstring은 함수의 코드를 읽지 않고도 함수 호출을 작성할 수 있을 만큼 충분한 정보를 제공해야 합니다.
477 | - docstring은 함수의 호출 구문과 의미를 설명해야 하며, 일반적으로 구현 세부 사항은 포함하지 않아야 하지만, 이러한 세부 사항이 함수 사용 방법에 중요하다면 예외입니다.
478 | - 예를 들어, 인자를 사이드 임펙트로 변경하는 함수는 그 점을 docstring에 명시해야 합니다.
479 |
480 | - 그렇지 않으면, 호출자에게 중요하지 않은 함수 구현의 미묘하지만 중요한 세부 사항은 함수의 docstring보다는 코드 옆에 주석으로 표현하는 것이 좋습니다.
481 | - docstring은 서술형(`"""Fetches rows from a Bigtable."""`) 또는 명령형(`"""Fetch rows from a Bigtable."""`) 스타일일 수 있지만, 파일 내에서 스타일은 일관되게 유지해야 합니다.
482 | - `@property` 속성의 docstring은 속성이나 [함수 인자](#doc-function-args)의 docstring과 같은 스타일을 사용해야 합니다 (`"""The Bigtable path."""` 대신에 `"""Returns the Bigtable path."""`).
483 |
484 | - 함수의 특정 측면은 아래에 나열된 특별한 섹션에서 문서화해야 합니다.
485 | - 각 섹션은 콜론으로 끝나는 제목 행으로 시작합니다.
486 | - 제목을 제외한 모든 섹션은 2칸 또는 4칸 공백의 걸쳐서 들여쓰기를 유지해야 합니다 (파일 내에서 일관되게 유지).
487 | - 함수의 이름과 시그니처가 충분히 정보를 제공하여 한 줄의 docstring으로 적절히 설명할 수 있는 경우, 이러한 섹션은 생략할 수 있습니다.
488 |
489 |
490 |
491 | ##### [_Args:_](#doc-function-args)
492 |
493 | - 매개변수를 각각 이름으로 나열합니다. 각 이름에는 설명문이 따르며 콜론 뒤에 공백이나 새로운 라인으로 분리되어야 합니다.
494 | - 만약 설명문이 너무 길어 한 줄인 80자를 초과할 경우 매개변수 이름보다 2칸 또는 4칸의 들여쓰기를 사용합니다.(파일의 나머지 문서(docstring)와 일치합니다.)
495 | - 만약 코드가 자료형에 대한 주석을 담고 있지 않다면 설명문은 요구되는 자료형을 포함해서 기록해야 합니다.
496 | - 함수가 `*foo`(가변길이의 매개변수 리스트) 또는 `**bar`(임의의 키워드 매개변수)를 받는다면 `*foo` 와 `**bar`로 기록되어야 합니다.
497 |
498 |
499 |
500 | ##### [_Returns:_ (제너레이터에는 _Yields:_)](#doc-function-returns)
501 |
502 | - 반환 값의 의미를 설명하고, 타입 어노테이션에서 제공하지 않는 타입 정보도 포함해야 합니다.
503 | - 함수가 None만 반환하는 경우, 이 섹션은 필요하지 않습니다.
504 | - docstring이 "Return", "Returns", "Yield", "Yields"로 시작하고(e.g. `"""Returns row from Bigtable as a tuple of strings."""`), 첫 번째 문장이 반환 값을 설명하기에 충분할 경우, 이 섹션은 생략될 수 있습니다.
505 | - 이전의 'NumPy 스타일'을 모방하지 마세요. ([example](https://numpy.org/doc/1.24/reference/generated/numpy.linalg.qr.html)) 이 스타일은 종종 튜플 반환 값을 여러 개의 개별 반환 값처럼 각각의 이름으로 문서화했습니다. (튜플이라는 점을 언급하지 않고)
506 | - 대신, 반환 값을 다음과 같이 설명하세요: "Returns: A tuple (mat_a, mat_b), where mat_a is ..., and ...".
507 | - docstring에서 사용되는 설명용 이름은 함수 본문에서 사용되는 내부 이름과 반드시 일치할 필요는 없습니다 (내부 이름은 API의 일부가 아니기 때문입니다)
508 | - 함수가 `yield`를 사용하는 경우(즉, 제너레이터인 경우), `Yields:` 섹션에서는 호출 결과로 반환되는 제너레이터 객체가 아니라, `next()`에 의해 반환되는 객체를 문서화해야 합니다.
509 |
510 |
511 |
512 | ##### [_Raises:_](#doc-function-raises)
513 |
514 | - interface와 관련된 모든 예외를 설명 뒤에 나열합니다.
515 | - `Args:`에 설명된 것과 유사한 예외 이름 + 콜론 + 공백 또는 줄 바꿈과 hanging indent 스타일을 사용하세요.
516 | - 명시된 API가 docstring을 위반했을 될 경우, 예외를 문서화하지 않습니다. (왜냐하면 이것은 역설적으로 API의 API를 위반하는 행동을 만들 수 있기 때문이다.)
517 |
518 | ```python
519 | def fetch_smalltable_rows(
520 | table_handle: smalltable.Table,
521 | keys: Sequence[bytes | str],
522 | require_all_keys: bool = False,
523 | ) -> Mapping[bytes, tuple[str, ...]]:
524 | """Fetches rows from a Smalltable.
525 |
526 | Retrieves rows pertaining to the given keys from the Table instance
527 | represented by table_handle. String keys will be UTF-8 encoded.
528 |
529 | Args:
530 | table_handle: An open smalltable.Table instance.
531 | keys: A sequence of strings representing the key of each table
532 | row to fetch. String keys will be UTF-8 encoded.
533 | require_all_keys: If True only rows with values set for all keys will be
534 | returned.
535 |
536 | Returns:
537 | A dict mapping keys to the corresponding table row data
538 | fetched. Each row is represented as a tuple of strings. For
539 | example:
540 |
541 | {b'Serak': ('Rigel VII', 'Preparer'),
542 | b'Zim': ('Irk', 'Invader'),
543 | b'Lrrr': ('Omicron Persei 8', 'Emperor')}
544 |
545 | Returned keys are always bytes. If a key from the keys argument is
546 | missing from the dictionary, then that row was not found in the
547 | table (and require_all_keys must have been False).
548 |
549 | Raises:
550 | IOError: An error occurred accessing the smalltable.
551 | """
552 | ```
553 |
554 | - 마찬가지로, 줄 바꿈이 있는 `Args:`도 허용합니다.
555 |
556 | ```python
557 | def fetch_smalltable_rows(
558 | table_handle: smalltable.Table,
559 | keys: Sequence[bytes | str],
560 | require_all_keys: bool = False,
561 | ) -> Mapping[bytes, tuple[str, ...]]:
562 | """Fetches rows from a Smalltable.
563 |
564 | Retrieves rows pertaining to the given keys from the Table instance
565 | represented by table_handle. String keys will be UTF-8 encoded.
566 |
567 | Args:
568 | table_handle:
569 | An open smalltable.Table instance.
570 | keys:
571 | A sequence of strings representing the key of each table row to
572 | fetch. String keys will be UTF-8 encoded.
573 | require_all_keys:
574 | If True only rows with values set for all keys will be returned.
575 |
576 | Returns:
577 | A dict mapping keys to the corresponding table row data
578 | fetched. Each row is represented as a tuple of strings. For
579 | example:
580 |
581 | {b'Serak': ('Rigel VII', 'Preparer'),
582 | b'Zim': ('Irk', 'Invader'),
583 | b'Lrrr': ('Omicron Persei 8', 'Emperor')}
584 |
585 | Returned keys are always bytes. If a key from the keys argument is
586 | missing from the dictionary, then that row was not found in the
587 | table (and require_all_keys must have been False).
588 |
589 | Raises:
590 | IOError: An error occurred accessing the smalltable.
591 | """
592 | ```
593 |
594 |
595 |
596 |
597 | ##### 3.8.3.1 Overridden Methods
598 |
599 | - 기본 클래스의 메서드를 오버라이드하는 메서드는 [`@override`](https://typing-extensions.readthedocs.io/en/latest/#override) 데코레이터(`typing_extensions` 또는 `typing` 모듈에서 제공)를 명시적으로 사용하는 경우 docstring이 필요하지 않습니다.
600 | - 단, 오버라이딩된 메서드의 동작이 기본 메서드의 계약을 실질적으로 개선하거나, 추가적인 사이드 임펙트 등을 문서화해야 하는 경우에는, 그러한 차이점이 최소한 포함된 docstring이 오버라이딩 메서드에 필요합니다.
601 |
602 | ```python
603 | from typing_extensions import override
604 | class Parent:
605 | def do_something(self):
606 | """Parent method, includes docstring."""
607 | # 자식 클래스, 오버라이드로 주석이 달린 메서드.
608 | class Child(Parent):
609 | @override
610 | def do_something(self):
611 | pass
612 | ```
613 |
614 | ```python
615 | # 자식 클래스에서 @override 데코레이터가 없는 경우, docstring이 필요합니다.
616 | class Child(Parent):
617 | def do_something(self):
618 | pass
619 | # docstring이 단순한 경우, @override만으로도 문서가 기본 클래스에 있음을 표시할 수 있습니다.
620 | class Child(Parent):
621 | @override
622 | def do_something(self):
623 | """See base class."""
624 | ```
625 |
626 |
627 |
628 | #### 3.8.4 Classes
629 |
630 | - 클래스는 선언 바로 아래에 해당 클래스를 설명하는 docstring 를 가지고 있어야 합니다.
631 | - [properties](#properties)을 제외한 공개 속성은 `Attributes` 섹션에서 문서화해야 하며, [함수의 `Args`](#doc-function-args) 섹션과 동일한 형식을 따라야 합니다.
632 |
633 | ```python
634 | class SampleClass:
635 | """Summary of class here.
636 |
637 | Longer class information...
638 | Longer class information...
639 |
640 | Attributes:
641 | likes_spam: A boolean indicating if we like SPAM or not.
642 | eggs: An integer count of the eggs we have laid.
643 | """
644 |
645 | def __init__(self, likes_spam: bool = False):
646 | """Initializes the instance based on spam preference.
647 | Args:
648 | likes_spam: Defines if instance exhibits this preference.
649 | """
650 | self.likes_spam = likes_spam
651 | self.eggs = 0
652 |
653 | @property
654 | def butter_sticks(self) -> int:
655 | """The number of butter sticks we have."""
656 | ```
657 |
658 | - 모든 클래스의 docstring은 클래스 인스턴스가 무엇을 나타내는지를 설명하는 한 줄 요약으로 시작해야 합니다. 이는 `Exception`의 서브클래스도 예외가 무엇을 나타내는지를 설명해야 하며, 발생할 수 있는 컨텍스트에 대해서는 설명하지 않아야 함을 의미합니다. 클래스의 docstring은 클래스가 클래스라는 등의 불필요한 정보를 반복해서는 안 됩니다.
659 |
660 | - 올바른 예
661 |
662 | ```python
663 | class CheeseShopAddress:
664 | """The address of a cheese shop.
665 | ...
666 | """
667 | class OutOfCheeseError(Exception):
668 | """No more cheese is available."""
669 | ```
670 |
671 | - 부적절한 예
672 |
673 | ```python
674 | class CheeseShopAddress:
675 | """Class that describes the address of a cheese shop.
676 | ...
677 | """
678 | class OutOfCheeseError(Exception):
679 | """Raised when no more cheese is available."""
680 | ```
681 |
682 |
683 |
684 |
685 | #### 3.8.5 Block and Inline Comments
686 |
687 | - 마지막으로 주석을 달아야 하는 곳은 코드의 복잡한 부분입니다.
688 | - 만약 추후 [code review](http://en.wikipedia.org/wiki/Code_review)에서 코드를 설명하려고 한다면 지금 주석을 달아두어야 합니다.
689 | - 복잡한 동작은 시작하기 전에 몇 줄의 주석을 달아야 합니다.
690 | - 잘 알려져 있지 않는 부분은 끝에 주석을 달아야 합니다.
691 |
692 | ```python
693 | # We use a weighted dictionary search to find out where i is in
694 | # the array. We extrapolate position based on the largest num
695 | # in the array and the array size and then do binary search to
696 | # get the exact number.
697 |
698 | if i & (i-1) == 0: # True if i is 0 or a power of 2.
699 | ```
700 |
701 | - 가독성 향상을 위해 이러한 주석들은 코드에서 최소 2줄 떨어져 있어야 합니다.
702 |
703 | - 하지만 코드 자체를 설명하지는 마세요.
704 | - 코드를 읽고 있는 사람이 여러분보다 파이썬을 더 잘 알고 있다고 가정하세요. (물론 그게 중요한 것은 아닙니다.)
705 |
706 | - 부적절한 예(주석)
707 |
708 | ```python
709 | # Now go through the b array and make sure whenever i occurs
710 | # the next element is i+1
711 | ```
712 |
713 |
714 |
715 | #### 3.8.6 Punctuation, Spelling and Grammar
716 |
717 | - 스펠링과 문법 그리고 구두점에 주의를 기울이세요. 잘 써진 주석이 읽기도 편합니다.
718 |
719 | - 주석은 마치 말하는 것처럼 자연스럽게 읽을 수 있어야 하며 영문 주석의 경우 올바른 대문자와 구두점이 필요합니다.
720 | - 대부분의 경우 조각난 문장보다 온전한 문장이 높은 가독성을 가집니다.
721 | - 코드 끝에 붙는 짧은 주석 등의 경우 다소 형식적이지 않아도 되지만, 전체적인 일관성을 맞추어야 합니다.
722 |
723 | - 코드 리뷰어가 세미콜론이 사용되어야 하는데 컴마를 사용했다고 지적하는 것은 불만스러울 수 있지만 소스코드가 높은 수준의 명료성과 가독성을 가지는것은 매우 중요합니다.
724 | - 올바른 구두점, 스펠링 그리고 문법은 이를 얻을 수 있도록 도와줍니다.
725 |
726 | ---
727 |
728 |
729 | ### 3.10 Strings
730 |
731 | - 매개변수가 모두 문자열인 경우에도 [f-string](https://docs.python.org/3/reference/lexical_analysis.html#f-strings), `format` 메소드나 `%` 연산자를 사용하여 포메팅하세요.
732 | - 문자열 포맷팅 옵션 사이에서 최상의 판단을 사용하세요.
733 | - `+`를 사용한 단일 join은 괜찮지만, `+`를 사용한 포맷팅은 피하세요.
734 |
735 | - 올바른 예
736 |
737 | ```python
738 | x = f'name: {name}; score: {n}'
739 | x = '%s, %s!' % (imperative, expletive)
740 | x = '{}, {}'.format(first, second)
741 | x = 'name: %s; score: %d' % (name, n)
742 | x = 'name: %(name)s; score: %(score)d' % {'name':name, 'score':n}
743 | x = 'name: {}; score: {}'.format(name, n)
744 | x = a + b
745 | ```
746 |
747 | - 부적절한 예
748 |
749 | ```python
750 | x = first + ', ' + second
751 | x = 'name: ' + name + '; score: ' + str(n)
752 | ```
753 |
754 | - 반목문에서 `+` 나 `+=` 연산자를 사용하여 문자열을 누적하는 행위는 삼가세요.
755 | - 몇몇 상황에서 위 연산자를 이용하여 문자열을 누적하는 경우 리니어한 실행시간이 아닌 제곱형태의 실행시간이 소요될 수 있습니다.
756 | - 물론 이러한 문자열 누적은 CPython의 수정을 통하여 최적화 될 수도 있지만 최적화 여부는 매번 변경될 수도 있으며 이를 예측하는 것 또한 어렵습니다.
757 | - 위의 연산자 대신 리스트에 문자열을 넣고 반복문이 종료되면 `''.join` 를 사용하는것이 더 바람직합니다. (또는 각각의 문자열을 `io.BytesIO` 버퍼에 기록하는 것도 방법입니다.)
758 |
759 | - 올바른 예
760 |
761 | ```python
762 | items = ['']
763 | for last_name, first_name in employee_list:
764 | items.append('%s, %s |
' % (last_name, first_name))
765 | items.append('
')
766 | employee_table = ''.join(items)
767 | ```
768 |
769 | - 부적절한 예
770 |
771 | ```python
772 | employee_table = ''
773 | for last_name, first_name in employee_list:
774 | employee_table += '%s, %s |
' % (last_name, first_name)
775 | employee_table += '
'
776 | ```
777 |
778 | - 하나의 파일에는 따옴표를 일관되게 사용하세요. `'` 또는 `"` 중 하나를 선택하고 그것만 사용하세요.
779 | - 다만 backslash-escape 따음표 문자 사용을 피하기 위해 같은 파일이더라도 다른 따옴표를 사용하는 것은 괜찮습니다.
780 |
781 | - 올바른 예
782 |
783 | ```python
784 | Python('Why are you hiding your eyes?')
785 | Gollum("I'm scared of lint errors.")
786 | Narrator('"Good!" thought a happy Python reviewer.')
787 | ```
788 |
789 | - 부적절한 예
790 |
791 | ```python
792 | Python("Why are you hiding your eyes?")
793 | Gollum('The lint. It burns. It burns us.')
794 | Gollum("Always the great lint. Watching. Watching.")
795 | ```
796 |
797 | - 다수의 문장을 이용할 때는 `'''` 보단 `"""` 를 이용하세요.
798 | - 프로젝트에 따라 docstring이 아닌 다른 여러줄의 문자열을 `'''` 를 이용하여 작성할 수 있습니다.
799 | - docstring은 상황과 무관하게 `"""` 를 사용합니다.
800 |
801 | - 다중 라인 문자열은 다른 코드의 들여쓰기를 따르지 않습니다.
802 | - 만약에 문자열에 추가 공간을 포함하는 것을 피하려면 단일 행 문자열을 연결하거나 [`textwrap.dedent()`](https://docs.python.org/3/library/textwrap.html#textwrap.dedent)와 함께 다중 라인 문자열을 사용하여 각 줄의 초기 공백을 제거합니다.
803 |
804 | - 부적절한 예
805 |
806 | ```python
807 | long_string = """This is pretty ugly.
808 | Don't do this.
809 | """
810 | ```
811 |
812 | - 올바른 예
813 |
814 | ```python
815 | long_string = """This is fine if your use case can accept
816 | extraneous leading spaces."""
817 | ```
818 |
819 | ```python
820 | long_string = ("And this is fine if you cannot accept\n" +
821 | "extraneous leading spaces.")
822 | ```
823 |
824 | ```python
825 | long_string = ("And this too is fine if you cannot accept\n"
826 | "extraneous leading spaces.")
827 | ```
828 |
829 | ```python
830 | import textwrap
831 |
832 | long_string = textwrap.dedent("""\
833 | This is also fine, because textwrap.dedent()
834 | will collapse common leading spaces in each line.""")
835 | ```
836 |
837 | - 여기서 백슬래시를 사용하는 것은 [명시적인 줄 이어쓰기](#line-length)에 대한 금지를 위반하지 않습니다.
838 | - 이 경우, 백슬래시는 문자열 리터럴에서 [줄바꿈을 이스케이프](https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals)하는 것입니다.
839 |
840 |
841 |
842 | #### 3.10.1 Logging
843 |
844 | - 첫번째 인자로 패턴문자열(% placeholder)이 요구되는 함수의 경우 아래 내용을 확인하세요.
845 | - 반드시 스트링 리터럴(f 스트링 아님)을 첫번째 인자, 패턴인자를 이후에 사용하여 호출하세요.
846 | - 일부 로깅방식의 경우 예상되지 않은 패턴문자열을 쿼리항목으로 이용합니다.
847 | - 또 로거가 필요없는 문자를 출력하는데에 시간을 낭비하지 않도록 방지합니다.
848 |
849 | ```python
850 | 올바른 예:
851 | import tensorflow as tf
852 | logger = tf.get_logger()
853 | logger.info('TensorFlow Version is: %s', tf.__version__)
854 | ```
855 |
856 | ```python
857 | 올바른 예:
858 | import os
859 | from absl import logging
860 | logging.info('Current $PAGER is: %s', os.getenv('PAGER', default=''))
861 | homedir = os.getenv('HOME')
862 | if homedir is None or not os.access(homedir, os.W_OK):
863 | logging.error('Cannot write to home directory, $HOME=%r', homedir)
864 | ```
865 |
866 | ```python
867 | 잘못된 예:
868 | import os
869 | from absl import logging
870 | logging.info('Current $PAGER is:')
871 | logging.info(os.getenv('PAGER', default=''))
872 | homedir = os.getenv('HOME')
873 | if homedir is None or not os.access(homedir, os.W_OK):
874 | logging.error(f'Cannot write to home directory, $HOME={homedir!r}')
875 | ```
876 |
877 |
878 |
879 | #### 3.10.2 Error Messages
880 |
881 | - 에러 메시지(`ValueError`와 같은 에외메시지, 유저에게 보여지는 메시지 등)는 아래의 가이드라인을 따라야합니다.
882 |
883 | 1. 에러메시지는 반드시 에러 조건과 정확하게 일치하여야 합니다.
884 | 2. 메시지 발생위치는 아래 예시와 같이 명확하게 알아볼 수 있어야합니다.
885 | 3. 에러메시지는 간단한 자동화 처리를 허용해야 합니다. (예: grepping)
886 |
887 | ```python
888 | 올바른 예:
889 | if not 0 <= p <= 1:
890 | raise ValueError(f'Not a probability: {p=}')
891 | try:
892 | os.rmdir(workdir)
893 | except OSError as error:
894 | logging.warning('Could not remove directory (reason: %r): %r',
895 | error, workdir)
896 | ```
897 |
898 | ```python
899 | 잘못된 예:
900 | if p < 0 or p > 1: # PROBLEM: also false for float('nan')!
901 | raise ValueError(f'Not a probability: {p=}')
902 | try:
903 | os.rmdir(workdir)
904 | except OSError:
905 | # 문제: 에러메시지가 사실이 아닐 수 있는 내용을 포함하고 있습니다:
906 | # 삭제작업이 실패했을 수도 있기에 이를 디버깅할 누군가가 오해할 수 있습니다
907 | logging.warning('Directory already was deleted: %s', workdir)
908 | try:
909 | os.rmdir(workdir)
910 | except OSError:
911 | # 문제: 메시지가 불필요하게 grep 하기 어려우며
912 | # `workdir`의 값에 따라 사용자가 혼란스러울 수도 있습니다
913 | # 누군가가 아래와 같은 workdir을 사용하는 경우를 생각해보세요
914 | # workdir = 'deleted'.:
915 | # 경고는 아래와 같이 표시될 것입니다.
916 | # "The deleted directory could not be deleted."
917 | logging.warning('The %s directory could not be deleted.', workdir)
918 | ```
919 |
920 | ---
921 |
922 |
923 | ### 3.11 파일과 소켓 그리고 유사한 Stateful Resources
924 |
925 | - 파일과 소켓의 사용이 끝나면 명시적으로 연결을 종료해주세요.
926 | - 이 규칙은 당연히 데이터베이스 연결과 같이 내부적으로 소켓을 사용하는 종료가 필요한 자원에도 적용됩니다.
927 | - 몇가지 예시를 들어보자면 아래의 경우가 있습니다
928 |
929 | - [mmap](https://docs.python.org/3/library/mmap.html)
930 | - [h5py File objects](https://docs.h5py.org/en/stable/high/file.html)
931 | - [matplotlib.pyplot figure windows](https://matplotlib.org/2.1.0/api/_as_gen/matplotlib.pyplot.close.html)
932 |
933 | - 파일이나 소켓과 같은 stateful 한 객체를 불필요하게 열어둔체로 남겨놓는것은 아래와 같은 단점들이 있습니다:
934 |
935 | - 파일 디스크립터와 같은 제한된 시스템 자원을 소모합니다.
936 | - 이러한 객체들을 많이 이용하는 코드라면 사용 후 시스템에 곧바로 반납하지 않는 행위는 자원의 고갈로 이어질 수 있습니다.
937 | - 파일을 열어둔 채로 방치하는 것은 파일의 이동, 제거 또는 마운트 해제가 불가능 할 수 있습니다.
938 | - 공유되는 파일이나 소켓의 경우 이용 종료 후에 다른 프로그램에 의해 의도치 않게 읽어지거나 쓰여질 수 있습니다.
939 | - 만약 정말 객체가 닫혀있다면 read/write를 시도할 때 exception을 일으켜 문제를 빠르게 알 수 있습니다.
940 |
941 | - 더욱이, 파일이나 소켓(비슷하게 동작하는 다른 자원 포함)은 객체가 소멸될 때 자동으로 닫혀지는 것은 맞으나 객체의 생명주기를 파일의 상태에 구속하는 것은 나쁜 습관입니다:
942 |
943 | - 런타임이 언제 `__del__` 메소드를 호출하는지 보장 할 수 없습니다.
944 | - 지연된 Garbage Collection 과 같이 파이썬의 종류에 따라 다른 방식의 메모리 관리 기법을 사용하기에 객체의 생명주기가 임의로 늘어나거나 영원히 죽지 않을 수도 있습니다.
945 | - globals 또는 예외추적 과 같이 의도치 않은 파일의 참조는 본래 생명주기보다 더 오랫동안 유지시킬 수 있습니다.
946 |
947 | - 수십 년 동안 여러 언어로 [finalizers](https://en.wikipedia.org/wiki/Finalizer)에 의한 자동 정리를 수행하는 것은 주목할 만한 사이드 임팩트를 거듭해서 재발견되었고 중대한 문제로 이어지고 있습니다. ( [Java에 대한 이 기사 참조](https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers) )
948 |
949 | - 가장 선호되는 파일(비슷하게 동작하는 다른 자원 포함)관리 방식은 [`with` 구문](http://docs.python.org/reference/compound_stmts.html#the-with-statement) 입니다
950 |
951 | ```python
952 | with open("hello.txt") as hello_file:
953 | for line in hello_file:
954 | print(line)
955 | ```
956 |
957 | - `with` 구문을 지원하지 않는 file-like 객체는 `contextlib.closing()`을 사용하세요.
958 |
959 | ```python
960 | import contextlib
961 |
962 | with contextlib.closing(urllib.urlopen("http://www.python.org/")) as front_page:
963 | for line in front_page:
964 | print(line)
965 | ```
966 |
967 | 드물게 컨텍스트 기반 자원관리가 불가피한 경우 코드의 설명을 통해 어떻게 해당 자원의 생명주기가 관리되고 있는지 반드시 기술하여야 합니다
968 |
969 | ---
970 |
971 |
972 | ### 3.12 TODO Comments
973 |
974 | - 임시적, 잠시 사용하려는 코드 또는 좋기는 하지만 완벽하지 않은 코드의 경우 `TODO` 주석을 사용하세요.
975 |
976 | - `TODO` 주석은 모두 대문자로 된 `TODO`로 시작하고, 다음에 콜론을 붙이며, 맥락이 포함된 리소스에 대한 링크(이상적으로는 버그 참조)를 포함해야 합니다.
977 | - 버그 참조가 선호됩니다. 왜냐하면 버그는 추적되며 후속 댓글이 달리기 때문입니다.
978 | - 이 문맥 다음에 하이픈 `-`으로 시작하는 설명 문자열을 추가하세요..
979 | - 목적은 일관된 `TODO` 형식을 유지하여, 더 많은 세부 정보를 찾기 위해 검색할 수 있도록 하는 것입니다.
980 |
981 | ```python
982 | # TODO: crbug.com/192795 - Investigate cpufreq optimizations.
983 | ```
984 |
985 | - 이전 스타일로, 예전에는 권장되었지만 새로운 코드에서는 사용이 권장되지 않습니다.
986 |
987 | ```python
988 | # TODO(crbug.com/192795): Investigate cpufreq optimizations.
989 | # TODO(yourusername): Use a "\*" here for concatenation operator.
990 | ```
991 |
992 | - 문맥으로 개인이나 팀을 참조하는 TODO를 추가하는 것을 피하세요.
993 |
994 | ```python
995 | # TODO: @yourusername - File an issue and use a '*' for repetition.
996 | ```
997 |
998 | - `TODO`가 "미래의 어느 시점에 무엇을 해야 한다"는 형식이라면, 미래의 코드 유지 관리자가 이해할 수 있도록 매우 구체적인 날짜("2009년 11월까지")나 사건("모든 클라이언트가 XML 요청을 해결 할수 있을때 이 코드 삭제")을 포함해야 합니다.
999 | - 이슈는 이를 추적하는 데 이상적입니다.
1000 |
1001 | ---
1002 |
1003 |
1004 | ### 3.13 import 형식
1005 |
1006 | - imports는 개별적인 라인에 두어야 합니다; [`typing` 그리고 `collections.abc` imports에 대한 예외가 있습니다.](#s3.19.12-imports).
1007 |
1008 | - 올바른 예
1009 |
1010 | ```python
1011 | import os
1012 | import sys
1013 | from typing import Any, NewType
1014 | ```
1015 |
1016 | - 부적절한 예
1017 |
1018 | ```python
1019 | import os, sys
1020 | ```
1021 |
1022 | - import는 모듈의 주석 과 docstring 바로 다음, 모듈 전역 및 상수 바로 앞 파일의 맨 위에 배치됩니다.
1023 | - import는 가장 일반적인 것 부터 최소한의 일반적인 것들까지 묶여야 합니다.
1024 |
1025 | 1. Python의 **future** import 문
1026 |
1027 | ```python
1028 | from __future__ import annotations
1029 | ```
1030 |
1031 | 자세한 내용은 [위](#from-future-imports)를 참조하세요.
1032 |
1033 | 2. 파이썬의 표준 라이브러리
1034 |
1035 | - import 예시는 다음과 같습니다.
1036 |
1037 | ```python
1038 | import sys
1039 | ```
1040 |
1041 | 3. [third-party](https://pypi.org/)
1042 |
1043 | - 모듈이나 패키지의 import 예시는 다음과 같습니다.
1044 |
1045 | ```python
1046 | import tensorflow as tf
1047 | ```
1048 |
1049 | 4. Code repository
1050 |
1051 | - 서브 패키지의 import 예시는 다음과 같습니다.
1052 |
1053 | ```python
1054 | from otherproject.ai import mind
1055 | ```
1056 |
1057 | 5. 동일한 top 레벨에 속하는 어플리케이션의 특정을 import하는 것은 **더 이상 사용되지 않습니다**
1058 |
1059 | - 서브 패키지의 파일 import 예시는 다음과 같습니다.
1060 |
1061 | ```python
1062 | from myproject.backend.hgwells import time_machine
1063 | ```
1064 |
1065 | - 오래된 Google Python Style code에서 이걸 발견했을 것입니다. 그러나 이건 오래 사용되지는 않았습니다.
1066 | - **새로운 코드는 이에 대해 신경쓰지 않도록 되어있습니다.** 간단하게 어플리케이션 서브 패키지를 import 하는 것을 다른 서브 패키지를 import하는 것과 동일하게 취급하세요.
1067 |
1068 | - 각각의 grouping에서 import는 사전 순으로 정렬되어야 하지만 이러한 조건을 무시해도 될 때는 각각의 모듈의 전체 패키지 경로(`from path import ...` 의 `path`)를 따랐을 경우입니다.
1069 | - 코드는 import부분에서 선택적으로 개행을 두어도 됩니다.
1070 |
1071 | ```python
1072 | import collections
1073 | import queue
1074 | import sys
1075 |
1076 | from absl import app
1077 | from absl import flags
1078 | import bs4
1079 | import cryptography
1080 | import tensorflow as tf
1081 |
1082 | from book.genres import scifi
1083 | from myproject.backend import huxley
1084 | from myproject.backend.hgwells import time_machine
1085 | from myproject.backend.state_machine import main_loop
1086 | from otherproject.ai import body
1087 | from otherproject.ai import mind
1088 | from otherproject.ai import soul
1089 |
1090 | # Older style code may have these imports down here instead:
1091 | #from myproject.backend.hgwells import time_machine
1092 | #from myproject.backend.state_machine import main_loop
1093 | ```
1094 |
1095 | ---
1096 |
1097 |
1098 | ### 3.14 Statements
1099 |
1100 | - 일반적으로 한 라인에는 오직 한 statement만 있어야 합니다.
1101 | - 그러나, 테스트에 관한 statement 전체가 한 라인에 들어간다면 테스트 결과를 같은 줄에 둘 수 있습니다.
1102 | - 특히 절대 `try`/`except`에서 `try` 와 `except`를 같은 라인에 둘 수 없고 `if`문에 `else`가 있지 않은 경우에는 가능합니다.
1103 |
1104 | - 올바른 예
1105 |
1106 | ```python
1107 | if foo: bar(foo)
1108 | ```
1109 |
1110 | - 부적절한 예
1111 |
1112 | ```python
1113 | if foo: bar(foo)
1114 | else: baz(foo)
1115 |
1116 | try: bar(foo)
1117 | except ValueError: baz(foo)
1118 |
1119 | try:
1120 | bar(foo)
1121 | except ValueError: baz(foo)
1122 | ```
1123 |
1124 | ---
1125 |
1126 |
1127 |
1128 | ### 3.15 접근 제어
1129 |
1130 | - Getter/Setter 함수(접근자 및 변경자라고도함)는 변수 값을 가져오거나 설정하기 위한 의미 있는 역할이나 동작을 제공하는 경우 사용해야 합니다.
1131 | - 특히 현재 또는 합리적인 미래에 변수를 가져오거나 설정하는 것이 복잡하거나 비용이 상당할 때 사용해야 합니다.
1132 | - 예를 들어 한 쌍의 getter/setter가 단순히 내부 속성을 읽고 쓰는 경우 내부 속성은 대신 공개되어야 합니다.
1133 | - 이에 비해 변수를 설정하면 일부 상태가 무효화되거나 다시 작성됨을 의미하는 경우 이는 setter 함수여야 합니다.
1134 | - 함수 호출은 잠재적으로 사소하지 않은 작업이 발생하고 있음을 암시합니다.
1135 | - 또한 간단한 논리가 필요하거나 더 이상 getter/setter가 필요하지 않도록 리팩토링할 때 [properties](#properties) 옵션이 될 수 있습니다.
1136 | - Getter/Setter는 `get_foo()`, `set_foo()`와 같은 [Naming](#s3.16-naming) 지침을 따라야 합니다.
1137 | - 이전 동작에서 property을 통한 엑세스가 허용된 경우 새 getter/setter함수를 property에 바인딩하지 마세요.
1138 | - 여전히 이전 방법으로 변수에 액세스하려고 시도하는 코드는 눈에 띄게 중단되어 복잡성의 변화를 인식할 수 있습니다.
1139 |
1140 | ---
1141 |
1142 |
1143 | ### 3.16 네이밍
1144 |
1145 | `module_name`,
1146 | `package_name`,
1147 | `ClassName`,
1148 | `method_name`,
1149 | `ExceptionName`,
1150 | `function_name`,
1151 | `GLOBAL_CONSTANT_NAME`,
1152 | `global_var_name`,
1153 | `instance_var_name`,
1154 | `function_parameter_name`,
1155 | `local_var_name`,
1156 | `query_proper_noun_for_thing`,
1157 | `send_acronym_via_https`.
1158 |
1159 | - 함수 이름, 변수 이름, 그리고 파일 이름은 설명적이여야 하고 약어로 적는 일을 피해야 합니다.
1160 | - 특히 모호하거나 프로젝트에 참여하지 않은 사람들이 읽었을 때 익숙하지 않은 약어를 사용하지마세요. 그리고 절대 단어에서 글자를 지워 줄이지 마세요.
1161 |
1162 | - 항상 `.py`파일 이름 확장자를 사용하고 절대 대시`-`를 사용하지 마세요.
1163 |
1164 |
1165 |
1166 | #### 3.16.1 피해야 할 이름
1167 |
1168 | - 아래와 같은 특별한 경우를 제외한 단일 글자는 피합니다.
1169 |
1170 | - counters이나 iterators에서 사용할 때 (예. `i`, `j`, `k`, `v` 등)
1171 | - `try/except`문에서 예외 식별자로 `e`를 사용할 때
1172 | - with문의 파일 핸들에서 `f`를 사용할 때
1173 | - 제약 조건이 없는 비공식적인 [type variables](#typing-type-var)를 사용할 때 (e.g., `_T = TypeVar("_T"), _P = ParamSpec("_P")`)
1174 |
1175 | 단일 글자를 남용하지 않도록 주의해야합니다. 일반적으로 말해서 서술성은 이름의 가시성 범위에 비례해야합니다. 예를 들어 `i`는 5행 코드 블록에 적합한 이름일 수 있지만 중첩된 여러 범위 내에서는 너무 모호할 수 있습니다.
1176 |
1177 | - package/module 이름에서 dashes(`-`)를 사용할 때
1178 | - `__이중_선행_및_후행_밑줄__` 이름을 사용할 때 (Python에서 예약어)
1179 |
1180 | - 원본에 없는 추가 설명 : double leading and trailing underscore : (앞 뒤로 \_가 2개씩 있는것 e.g **name**, **init**)
1181 |
1182 | - 공격적인 단어
1183 | - 불필요하게 변수 타입을 포함하는 이름 (예 : `id_to_name_dict`)
1184 |
1185 |
1186 |
1187 | #### 3.16.2 Naming Conventions
1188 |
1189 | 모듈에 관련 클래스와 최상위 기능을 함께 배치합니다.
1190 |
1191 | - "Internal"는 모듈의 내부 또는 클래스 내에서 protected 또는 private를 의미합니다.
1192 | - 단일 밑줄(`_`)을 추가하면 모듈 변수와 함수를 보호하기 위한 몇 가지 지원이 있습니다. (linters는 보호된 멤버 접근에 플래그를 지정합니다.)
1193 | - 단일 언더스코어(`_`)를 접두사로 사용하는 것은 모듈 변수와 함수 보호를 위한 일부 지원을 제공합니다 (linters가 보호된 멤버 접근을 경고할 수 있습니다). 그러나 유닛 테스트가 테스트 중인 모듈의 보호된 상수에 접근하는 것은 괜찮습니다.
1194 | - 인스턴스 변수나 메소드에 이중 밑줄(`__` : dunder)을 추가하면 변수나 메소드가 해당 클래스에 대해 효과적으로 private 됩니다.
1195 | - 가독성과 테스트 가능성에 영향을 미치고 _실제로_ 비공개가 아니므로 사용을 권장하지 않습니다.
1196 | - 하나의 밑줄을 선호합니다.
1197 | - 모듈에 관련 클래스와 top-level 함수를 함께 배치합니다.
1198 | - 자바와는 다르게 하나의 모듈에 대해 하나의 클래스로 제한을 할 필요가 없습니다.
1199 | - CapWords(단어의 첫 글자를 대문자로 하는 방식)을 사용하지만 모듈의 이름이 \_with_under.py 같은 경우에는 소문자로 합니다.
1200 |
1201 | - 비록 몇몇 오래된 모듈의 이름이 CapWords.py일지라도 이제는 모듈의 이름을 class이름에 따라 짓게 되면 혼란스러우므로 권장하지 않습니다. (e.g "잠깐만, -- 내가 `import StringIO`를 한거야 아니면 `from StringIO import StringIO`를 한거야 ?" 같은 상황이 발생할 수 있습니다.)
1202 |
1203 | - 새로운 유닛 테스트 파일은 PEP 8을 준수하는 소문자와 언더스코어 방식의 메서드 이름을 따릅니다.
1204 | - 예를 들어, `test**`와 같은 형식을 사용합니다.
1205 | - 일관성을 위해(\*) 이전 모듈에서 CapWords 함수 이름을 따르는 경우, `test`로 시작하는 메서드 이름에 논리적 구성 요소를 구분하기 위해 언더스코어가 포함될 수 있습니다.
1206 | - 하나의 가능한 패턴은 `test_`입니다.
1207 |
1208 |
1209 |
1210 | #### 3.16.3 파일 네이밍
1211 |
1212 | - 파이썬 파일이름은 반드시 `.py`확장자를 가지고 (`-`)를 가지고 있으면 안됩니다.
1213 | - 이건 import와 유닛테스트를 할 수 있게 해줍니다.
1214 | - 만약 확장자 없이 실행 파일에 접근하려면 `exec "$0.py" "$@"` 가 들어 있는 심볼 링크나 간단한 bash wrapper를 사용하세요.
1215 |
1216 |
1217 |
1218 | #### 3.16.4 [Guido](https://en.wikipedia.org/wiki/Guido_van_Rossum)의 권고에 따른 가이드라인
1219 |
1220 | | 타입 | Public | Internal |
1221 | | -------------------- | -------------------- | --------------------------------- |
1222 | | 패키지 | `lower_with_under` | |
1223 | | 모듈 | `lower_with_under` | `_lower_with_under` |
1224 | | 클래스 | `CapWords` | `_CapWords` |
1225 | | 예외 | `CapWords` | |
1226 | | 함수 | `lower_with_under()` | `_lower_with_under()` |
1227 | | 글로벌/클래스 상수 | `CAPS_WITH_UNDER` | `_CAPS_WITH_UNDER` |
1228 | | 글로벌/클래스 변수 | `lower_with_under` | `_lower_with_under` |
1229 | | 인스턴스 변수 | `lower_with_under` | `_lower_with_under` (protected) |
1230 | | 메서드 이름 | `lower_with_under()` | `_lower_with_under()` (protected) |
1231 | | 함수/메서드 매개변수 | `lower_with_under` | |
1232 | | 지역 변수 | `lower_with_under` | |
1233 |
1234 |
1235 |
1236 | #### 3.16.5 수학 표기법
1237 |
1238 | - 수학적으로 복잡한 코드의 경우 일반적으로 코딩 스타일 가이드를 벗어나는 짧은 변수이더라도 참고서나 알고리즘에서 보편적으로 사용되는 정립된 표식은 허용됩니다.
1239 | - 이런 경우 주석이나 docstring으로 표식의 출처를 참조해주세요.
1240 | - 출처에 접근할 수 없는 경우 명확하게 명명규칙을 기술하세요.
1241 | - 공개 API의 경우 더 자주 사용되는 PEP8-compliant `descriptive_names`이 선호됩니다.
1242 |
1243 | ---
1244 |
1245 |
1246 | ### 3.17 Main
1247 |
1248 | - 파이썬에서 `pydoc`과 유닛 테스트는 모듈을 import할 수 있어야 합니다.
1249 | - 파일이 실행파일로써 사용되어야 하더라도 주된 기능은 `main()` 함수에 포함되어야 합니다.
1250 | - 당신의 코드에서 메인 프로그램이 모듈을 import 할 때 실행되지 않도록 메인 프로그램을 실행시키기 전에 `if __name__ == '__main__'`을 항상 확인해야 합니다.
1251 |
1252 | - [absl](https://github.com/abseil/abseil-py)를 사용할 때 `app.run`를 사용하세요.
1253 |
1254 | ```python
1255 | from absl import app
1256 | ...
1257 |
1258 | def main(argv: Sequence[str]):
1259 | # process non-flag arguments
1260 | ...
1261 |
1262 | if __name__ == '__main__':
1263 | app.run(main)
1264 | ```
1265 |
1266 | - 그렇지 않으면 다음을 사용하세요.
1267 |
1268 | ```python
1269 | def main():
1270 | ...
1271 |
1272 | if __name__ == '__main__':
1273 | main()
1274 | ```
1275 |
1276 | - top level에 있는 모든 코드는 모듈이 import될 때 실행될 것입니다.
1277 | - 파일을 `pydoc`으로 만들 때 실행하면 안되는 연산을 하거나 함수를 호출하는 것과 객체를 만드는 것을 조심하세요.
1278 |
1279 | ---
1280 |
1281 |
1282 | ### 3.18 함수 길이
1283 |
1284 | - 함수의 길이가 작고 필수기능으로만 작성된 함수를 선호하세요.
1285 |
1286 | - 우리는 길이가 긴 함수들이 가끔 필요하다는걸 알고있습니다. 그래서 함수 길이에 딱히 제한은 없습니다.
1287 | - 하지만 만약 함수가 40줄을 넘어가면 프로그램의 구조에 피해가 안가면서 줄일 수 있는지 생각해보세요.
1288 |
1289 | - 비록 작성한 길이가 긴 함수가 당장은 완벽하게 작동할지라도 누군가 몇 달 이내에 함수에 새로운 동작을 추가할수 도 있습니다.
1290 | - 이건 버그를 찾기 어렵게 할수 도 있습니다.
1291 | - 작성한 함수를 짧고 간단하게 하여 다른 사람들이 읽고 코드를 수정하기 쉽게 만드세요.
1292 |
1293 | - 작업을 할때 몇몇 길고 복잡한 함수를 발견할 수 있습니다. 절대 기존의 코드를 수정한다는 협박을 하지 마세요
1294 | - 만약 함수가 사용하기 어렵다고 판단되면, 에러를 디버깅 하기 힘들다는걸 알거나 몇몇 다른 문맥에서 이 에러들을 사용하기 원한다고 할때
1295 | - 그 함수를 작고 더욱 관리가 가능한 조각들로 나누는 것을 생각해 보세요.
1296 |
1297 | ---
1298 |
1299 |
1300 | ### 3.19 Type 주석 방법
1301 |
1302 |
1303 |
1304 | #### 3.19.1 일반적인 규칙
1305 |
1306 | - [PEP-484](https://peps.python.org/pep-0484/)을 읽으세요.
1307 |
1308 | - `self` 또는 `cls`에 주석을 달 필요는 일반적으로 없습니다. 올바른 타입 정보를 위해 필요한 경우에만 [`Self`](https://docs.python.org/3/library/typing.html#typing.Self)를 사용할 수 있습니다.
1309 |
1310 | ```python
1311 | from typing import Self
1312 | class BaseClass:
1313 | @classmethod
1314 | def create(cls) -> Self:
1315 | ...
1316 | def difference(self, other: Self) -> float:
1317 | ...
1318 | ```
1319 |
1320 | - 마찬가지로, `__init__`의 반환 값에 주석을 달 필요는 없습니다 (여기서 `None`만 유효한 옵션입니다).
1321 |
1322 | - 모든 변수나 반환되는 Type이 정해지지 않았다면 `Any`를 사용하세요.
1323 |
1324 | - 모듈에서 모든 함수에 주석을 달 필요는 없습니다.
1325 | - Public API에는 최소한의 주석을 답니다.
1326 | - 판단력을 사용하여 한편으로는 안전성과 명확성, 그리고 다른 한편으로는 유연성 사이의 균형을 잘 잡아야 합니다.
1327 | - Type 관련 오류(이전 버그 또는 복잡성)가 발생하기 쉬운 코드에 주석을 답니다.
1328 | - 이해하기 어려운 코드에 주석을 답니다.
1329 | - Type의 관점에서 코드가 안정화되면 주석을 답니다. 많은 경우에 너무 변하는 코드를 제외한 모든 심사숙고한 코드에 주석을 달 수 있습니다.
1330 |
1331 |
1332 |
1333 | #### 3.19.2 줄 바꿈
1334 |
1335 | - 기존의 [들여쓰기](#s3.4-indentation) 규칙을 따르세요.
1336 |
1337 | - 주석처리하고나서 많은 함수는 "한 줄에 하나의 파라미터"가 될 것입니다.
1338 | - 반환 타입이 별도의 줄에 표시되도록 보장하기 위해, 마지막 매개변수 뒤에 쉼표를 추가할 수 있습니다.
1339 |
1340 | ```python
1341 | def my_method(
1342 | self,
1343 | first_var: int,
1344 | second_var: Foo,
1345 | third_var: Bar | None,
1346 | ) -> int:
1347 | ...
1348 | ```
1349 |
1350 | - 한줄에 맞출 수 있다면 사용해도 좋지만, 예제처럼 변수와 예를 들어 변수 이름과 유형 주석 간에는 포함되지않은 사이에는 항상 끊는 것을 선호합니다.
1351 |
1352 | ```python
1353 | def my_method(self, first_var: int) -> int:
1354 | ...
1355 | ```
1356 |
1357 | - 함수 이름, 마지막 매개 변수 및 리턴 Type의 조합이 너무 길면 새 행에서 4만큼 들여 쓰기됩니다.
1358 | - 줄 바꿈을 사용할 때는 각 매개변수와 반환 타입을 별도의 줄에 배치하고, 닫는 괄호를 `def`와 정렬하는 것이 좋습니다.
1359 |
1360 | ```python
1361 | def my_method(
1362 | self,
1363 | other_arg: MyLongType | None,
1364 | ) -> tuple[MyLongType1, MyLongType1]:
1365 | ...
1366 | ```
1367 |
1368 | - 선택적으로, 반환 타입을 마지막 매개변수와 같은 줄에 배치할 수도 있습니다.
1369 |
1370 | - 괜찮은 예
1371 |
1372 | ```python
1373 | def my_method(
1374 | self,
1375 | first_var: int,
1376 | second_var: int) -> dict[OtherLongType, MyLongType]:
1377 | ...
1378 | ```
1379 |
1380 | - `pylint`를 사용하면 닫는 괄호를 새 줄로 이동하고 여는 줄과 맞출 수 있지만 읽기 어렵습니다.
1381 |
1382 | - 부적절한 예
1383 |
1384 | ```python
1385 | def my_method(self,
1386 | other_arg: MyLongType | None,
1387 | ) -> dict[OtherLongType, MyLongType]:
1388 | ...
1389 | ```
1390 |
1391 | - 위 예처럼, Type을 깨지 않는 것을 선호합니다.
1392 | - 하지만 때때로는 너무 길어서 한 줄에 담을 수 없습니다. (sub-type를 끊어지지 않도록 노력합니다.)
1393 |
1394 | ```python
1395 | def my_method(
1396 | self,
1397 | first_var: tuple[list[MyLongType1],
1398 | list[MyLongType2]],
1399 | second_var: list[dict[
1400 | MyLongType3, MyLongType4]],
1401 | ) -> None:
1402 | ...
1403 | ```
1404 |
1405 | - 단일 이름과 Type이 너무 길면 Type에 대한 [alias(별칭)](#s3.19.6-aliases)사용을 고려하세요.
1406 | - 최후의 수단은 다음에 4칸을 들여 쓰는 것입니다.
1407 |
1408 | - 올바른 예
1409 |
1410 | ```python
1411 | def my_function(
1412 | long_variable_name:
1413 | long_module_name.LongTypeName,
1414 | ) -> None:
1415 | ...
1416 | ```
1417 |
1418 | - 부적절한 예
1419 |
1420 | ```python
1421 | def my_function(
1422 | long_variable_name: long_module_name.
1423 | LongTypeName,
1424 | ) -> None:
1425 | ...
1426 | ```
1427 |
1428 |
1429 |
1430 | #### 3.19.3 전방선언
1431 |
1432 | - 아직 정의되지 않은 클래스 이름(예를 들어, 클래스 선언 내부에서 클래스 이름이 필요하거나 코드에서 나중에 정의된 클래스를 사용할 경우)을 사용해야 할 경우, `from __future__ import annotations`를 사용하거나 클래스 이름을 문자열로 사용하세요.
1433 |
1434 | - 올바른 예
1435 |
1436 | ```python
1437 | from __future__ import annotations
1438 |
1439 | class MyClass:
1440 | def __init__(self, stack: Sequence[MyClass], item: OtherClass) -> None:
1441 |
1442 | class OtherClass:
1443 | ...
1444 | ```
1445 |
1446 | ```python
1447 | class MyClass:
1448 | def __init__(self, stack: Sequence['MyClass'], item: 'OtherClass') -> None:
1449 |
1450 | class OtherClass:
1451 | ...
1452 | ```
1453 |
1454 |
1455 |
1456 | #### 3.19.4 기본 값
1457 |
1458 | - PEP-008에 따라 유형 주석과 기본값이 모두 있는 인수의 경우 "=" \_ only" 주위에 공백을 사용하십시오.
1459 | - [PEP-008](https://peps.python.org/pep-0008/#other-recommendations)에 따라 Type 주석과 기본 값이 모두 있는 인수의 경우 `=` _only_ 주위에 공백을 사용하세요,
1460 |
1461 | - 올바른 예
1462 |
1463 | ```python
1464 | def func(a: int = 0) -> int:
1465 | ...
1466 | ```
1467 |
1468 | - 부적절한 예
1469 |
1470 | ```python
1471 | def func(a:int=0) -> int:
1472 | ...
1473 | ```
1474 |
1475 |
1476 |
1477 | #### 3.19.5 NoneType
1478 |
1479 | - 파이썬형에서 노네타입(NoneType)은 퍼스트클래스형이며, 타이핑을 위해 노네타입(NoneType)은 노네타입(NoneType)의 별칭이다.
1480 | - 인자가 `None`이 될 수 있는 경우, 이를 선언해야 합니다!
1481 | - 새로운 Python 3.10+ 코드에서는 `|` 유니온 타입 표현식을 사용하는 것이 권장되며, 이전에는 `Optional`과 `Union` 구문을 사용할 수 있습니다.
1482 |
1483 | - 암시적인 대신 명시적인 `X | None`을 사용하세요.
1484 | - 이전 버전의 PEP 484에서는 `a: str = None`을 `a: str | None = None`으로 해석할 수 있었지만, 이제는 이것이 선호되는 동작이 아닙니다.
1485 |
1486 | - 올바른 예
1487 |
1488 | ```python
1489 | def modern_or_union(a: str | int | None, b: str | None = None) -> str:
1490 | ...
1491 | def union_optional(a: Union[str, int, None], b: Optional[str] = None) -> str:
1492 | ...
1493 | ```
1494 |
1495 | - 부적절한 예
1496 |
1497 | ```python
1498 | def nullable_union(a: Union[None, str]) -> str:
1499 | ...
1500 | def implicit_optional(a: str = None) -> str:
1501 | ...
1502 | ```
1503 |
1504 |
1505 |
1506 |
1507 | #### 3.19.6 Type Aliases
1508 |
1509 | - 복잡한 유형의 별칭을 선언할 수 있다. 가명의 이름은 CapWorded여야 한다. 별칭이 이 모듈에서만 사용되는 경우 \_Private여야 한다.
1510 |
1511 | - 어려운 Type을 별칭으로 선언할 수 있습니다. 별칭은 CapWorded여야 합니다. 별칭이 이 모듈에서만 사용하는 경우에는 \_Private여야 합니다.
1512 |
1513 | - TypeAlias 주석은 버전 3.10 이상에서만 지원된다는 점에 유의하세요.
1514 |
1515 | ```python
1516 | from typing import TypeAlias
1517 | _LossAndGradient: TypeAlias = tuple[tf.Tensor, tf.Tensor]
1518 | ComplexTFMap: TypeAlias = Mapping[str, _LossAndGradient]
1519 | ```
1520 |
1521 |
1522 |
1523 |
1524 | #### 3.19.7 Ignoring Types
1525 |
1526 | - `# type: ignore` 주석으로 Type 검사를 사용하지 않도록 설정 할 수 있습니다.
1527 |
1528 | - `pytype`에는 특정 오류에 대한 비활성화 옵션이 있습니다.(lint과 유사).
1529 |
1530 | ```python
1531 | # pytype: disable=attribute-error
1532 | ```
1533 |
1534 |
1535 |
1536 |
1537 | #### 3.19.8 내부 변수 작성
1538 |
1539 |
1540 |
1541 | - [_Annotated Assignments_](#annotated-assignments): 내부 변수의 타입을 추론하기 어렵거나 불가능한 경우, 주석이 달린 할당으로 타입을 명시하세요. 변수 이름과 값 사이에 콜론과 타입을 사용합니다 (기본값이 있는 함수 인수와 동일한 방식으로).
1542 |
1543 | ```python
1544 | a: Foo = SomeUndecoratedFunction()
1545 | ```
1546 |
1547 |
1548 |
1549 | - [_Type Comments_](#type-comments): 코드베이스에 여전히 남아 있을 수 있지만 (Python 3.6 이전에는 필요했음), 더 이상 `# type: ` 주석을 줄 끝에 추가하지 마세요.
1550 |
1551 | ```python
1552 | a = SomeUndecoratedFunction() # type: Foo
1553 | ```
1554 |
1555 |
1556 |
1557 |
1558 | #### 3.19.9 튜플 vs 리스트
1559 |
1560 | - 리스트 타입은 한가지 타입의 오프젝트만 포함할 수 있습니다. 튜플 타입은 반복되는 하나의 타입이나 서로 다른 타입을 넣을 수 있습니다.
1561 | - 서로 다른 타입의 수를 넣는 경우는 일반적으로 함수에서 타입을 반환할 때 사용됩니다.
1562 | - 리스트는 함수의 반환 타입으로 일반적으로 사용된다.
1563 |
1564 | ```python
1565 | a: list[int] = [1, 2, 3]
1566 | b: tuple[int, ...] = (1, 2, 3)
1567 | c: tuple[int, str, float] = (1, "2", 3.5)
1568 | ```
1569 |
1570 |
1571 |
1572 |
1573 |
1574 | #### 3.19.10 Type variables
1575 |
1576 | - 파이썬형 시스템은 일반성을 가지고 있다. 공장 기능인 TypeVar는 흔히 사용하는 방법입니다.
1577 |
1578 | - 파이선 Type에는 [generics](https://peps.python.org/pep-0484/#generics)를 가지고 있습니다.
1579 | - `TypeVar`와 `ParamSpec`과 같은 타입 변수는 제너릭을 사용하는 일반적인 방법입니다.
1580 |
1581 | ```python
1582 | from collections.abc import Callable
1583 | from typing import ParamSpec, TypeVar
1584 | _P = ParamSpec("_P")
1585 | _T = TypeVar("_T")
1586 | ...
1587 | def next(l: list[_T]) -> _T:
1588 | return l.pop()
1589 | def print_when_called(f: Callable[_P, _T]) -> Callable[_P, _T]:
1590 | def inner(*args: _P.args, **kwargs: _P.kwargs) -> _T:
1591 | print("Function was called")
1592 | return f(*args, **kwargs)
1593 | return inner
1594 | ```
1595 |
1596 | - `TypeVar`는 부자연스러울 수도 있습니다.
1597 |
1598 | ```python
1599 | AddableType = TypeVar("AddableType", int, float, str)
1600 | def add(a: AddableType, b: AddableType) -> AddableType:
1601 | return a + b
1602 | ```
1603 |
1604 | - `typing` 모듈의 흔히 미리 정의된 Type 변수는 `AnyStr`입니다. `bytes`, `str`일 수 있고 모두 같은 Type이어야 하는 여러 주석에 사용합니다.
1605 |
1606 | ```python
1607 | from typing import AnyStr
1608 | def check_length(x: AnyStr) -> AnyStr:
1609 | if len(x) <= 42:
1610 | return x
1611 | raise ValueError()
1612 | ```
1613 |
1614 | - 타입 변수는 설명적인 이름을 가져야 합니다. 단, 다음 모든 기준을 충족하는 경우에는 예외입니다.
1615 |
1616 | - 외부에서 보이지 않는 경우
1617 | - 제약 조건이 없는 경우
1618 |
1619 | - 올바른 예
1620 |
1621 | ```python
1622 | _T = TypeVar("_T")
1623 | _P = ParamSpec("_P")
1624 | AddableType = TypeVar("AddableType", int, float, str)
1625 | AnyFunction = TypeVar("AnyFunction", bound=Callable)
1626 | ```
1627 |
1628 | - 부적절한 예
1629 |
1630 | ```python
1631 | T = TypeVar("T")
1632 | P = ParamSpec("P")
1633 | _T = TypeVar("_T", int, float, str)
1634 | _F = TypeVar("_F", bound=Callable)
1635 | ```
1636 |
1637 |
1638 |
1639 |
1640 |
1641 |
1642 | #### 3.19.11 문자열 Type
1643 |
1644 | > 새로운 코드에서는 `typing.Text`를 사용하지 마세요. 이는 Python 2/3 호환성을 위한 것입니다.
1645 |
1646 | - 문자열/텍스트 데이터에는 `str`을 사용하세요. 이진 데이터와 관련된 코드에서는 `bytes`를 사용하세요.
1647 |
1648 | ```python
1649 | def deals_with_text_data(x: str) -> str:
1650 | ...
1651 | def deals_with_binary_data(x: bytes) -> bytes:
1652 | ...
1653 | ```
1654 |
1655 | - 함수의 모든 string Type이 항상 동일한 경우(예, 반환 Type이 위의 코드에서 인자 Type과 동일한 경우) [AnyStr](#s3.19.10-type-var)를 사용하세요.
1656 |
1657 | - 이렇게 사용하면 Python 3에 코드를 포팅하는 과정이 간단해집니다.
1658 |
1659 |
1660 |
1661 |
1662 | #### 3.19.12 Typing 추가
1663 |
1664 | - `typing` 또는 `collections.abc` 모듈에서 정적 분석 및 타입 검사를 지원하기 위해 사용하는 심볼(타입, 함수, 상수 등)은 항상 심볼 자체를 임포트하세요.
1665 | - 이렇게 하면 일반적인 주석이 더 간결해지고, 전 세계적으로 사용되는 타입 주석 관행에 맞출 수 있습니다.
1666 | - `typing` 및 `collections.abc` 모듈에서 여러 개의 특정 심볼을 한 줄에서 명시적으로 임포트할 수 있습니다.
1667 |
1668 | ```python
1669 | from collections.abc import Mapping, Sequence
1670 | from typing import Any, Generic, cast, TYPE_CHECKING
1671 | ```
1672 |
1673 | - 이 방식으로 임포트하면 로컬 네임스페이스에 항목이 추가되므로, `typing` 또는 `collections.abc`의 이름은 키워드와 유사하게 취급되어야 하며, Python 코드에서 정의되지 않아야 합니다. 타입 여부와 관계없이 말입니다.
1674 | - 모듈 내에서 타입과 기존 이름 간에 충돌이 있는 경우, `import x as y`를 사용하여 임포트하세요.
1675 |
1676 | ```python
1677 | from typing import Any as AnyType
1678 | ```
1679 |
1680 | - 가능한 경우, 주석으로 내장 타입을 사용하는 것이 좋습니다.
1681 | - Prefer to use built-in types as annotations where available.
1682 | - Python은 [PEP-585](https://peps.python.org/pep-0585/)를 통해 매개형 컨테이너 타입을 사용한 타입 주석을 지원하며, 이는 Python 3.9에서 도입되었습니다.
1683 |
1684 | ```python
1685 | def generate_foo_scores(foo: set[str]) -> list[float]:
1686 | ...
1687 | ```
1688 |
1689 |
1690 |
1691 |
1692 | #### 3.19.13 조건 Imports
1693 |
1694 | - 형식 확인에 필요한 추가 가져오기를 런타임에 피해야 하는 예외적인 경우에만 조건부 가져오기를 사용하십시오.
1695 |
1696 | - 이러한 패턴은 바람직하지 않습니다.
1697 | - 최고 수준의 수입을 허용하도록 코드 재인쇄와 같은 대안이 선호되어야 합니다.
1698 |
1699 | - Type 확인에 필요한 import 추가는 런타임에 피해야 하는 예외적인 경우에만 조건부 가져오기를 사용하세요.
1700 |
1701 | - 이러한 패턴은 바람직하지 않습니다.
1702 | - top level import을 허용하도록 코드 재구성과 같은 대안이 선호되어야 합니다.
1703 |
1704 | - Type 주석에만 필요한 impot는 `if TYPE_CHECKING:` 블록 내에 배치 할 수 있습니다.
1705 | - 조건부로 import한 Type을 문자열로 참조하여 주석 표현이 실제로 평가되는 Python 3.6과 정방향 호환 가능합니다.
1706 | - 입력에만 사용되는 속성만 정의되어야 합니다. 별칭이 포함되어야 하며 그렇지 않으면 모듈을 런타임에 가져오지 않기 때문에 런타임 오류가 발생합니다.
1707 | - 블록은 모든 정상 import 후여야 합니다.
1708 | - typing import 목록에 빈 줄이 없어야 합니다.
1709 | - 목록을 일반 import 목록인 것처럼 정렬하세요.
1710 |
1711 | ```python
1712 | import typing
1713 | if typing.TYPE_CHECKING:
1714 | import sketch
1715 | def f(x: "sketch.Sketch"): ...
1716 | ```
1717 |
1718 |
1719 |
1720 |
1721 | #### 3.19.14 Circular 종속
1722 |
1723 | - Circular 종속의 원인은 심오한 문제(code smells)를 작성하는 것입니다.
1724 |
1725 | - 그런 코드는 리팩터링에 적합합니다.
1726 | - 하지만 기술적으로 Circular 종속성을 유지하는 것은 가능하지만, 다양한 빌드 시스템은 다른 모듈에 의존해야 하기 때문에 그렇게 하도록 허락하지 않을 것입니다.
1727 |
1728 | - Circular 종속을 생성하는 모듈을 `Any`로 교체합니다.
1729 | - 의미있는 이름으로 [alias](#s3.19.6-aliases)를 지정하고 모듈의 실제 Type 이름을 사용하세요 (`Any`의 모든 속성은 `Any`입니다.).
1730 | - Alias의 정의는 마지막으로 import와 한 줄로 분리합니다.
1731 |
1732 | ```python
1733 | from typing import Any
1734 |
1735 | some_mod = Any # some_mod.py에서 이 모듈을 import 합니다.
1736 | ...
1737 |
1738 | def my_method(self, var: "some_mod.SomeType") -> None:
1739 | ...
1740 | ```
1741 |
1742 |
1743 |
1744 | #### 3.19.15 일반
1745 |
1746 | - 주석을 달때, 일반 Type를 지정하기를 선호하며 그렇지 [않을 때에는 `Any`로 가정합니다](https://peps.python.org/pep-0484/#the-any-type).
1747 |
1748 | - 올바른 예
1749 |
1750 | ```python
1751 | def get_names(employee_ids: Sequence[int]) -> Mapping[int, str]:
1752 | ...
1753 | ```
1754 |
1755 | - 부적절한 예
1756 |
1757 | ```python
1758 | # 이는 get_names(employee_ids: Sequence[Any]) -> Mapping[Any, Any]로 해석됩니다.
1759 | def get_names(employee_ids: Sequence) -> Mapping:
1760 | ```
1761 |
1762 | - 파라미터의 적합한 Type이 `Any`일 때, 명시적으로 표현되며, 많은 경우에 [`TypeVar`](#s3.19.10-type-var)가 더 적합할 수 있음을 기억해야합니다.
1763 |
1764 | - 부적절한 예
1765 |
1766 | ```python
1767 | def get_names(employee_ids: Sequence[Any]) -> Mapping[Any, str]:
1768 | """직원의 아이디를 이름과 연결하여 반환합니다."""
1769 | ```
1770 |
1771 | - 올바른 예
1772 |
1773 | ```python
1774 | _T = TypeVar('_T')
1775 | def get_names(employee_ids: Sequence[_T]) -> Mapping[_T, str]:
1776 | """직원의 아이디를 이름과 연결하여 반환합니다."""
1777 | ```
1778 |
1779 | ---
1780 |
--------------------------------------------------------------------------------
/Google Python Style Guide/4. 맺음말/4.1 맺음말.md:
--------------------------------------------------------------------------------
1 | 일관성을 유지하세요
2 |
3 | - 당신이 코드를 수정한다면 몇 분을 투자해서 코드를 살펴보고 스타일을 파악하세요.
4 | - 그들이 인덱스 변수 이름에 `_idx` 접미사를 사용하는 경우, 당신도 그렇게 해야 합니다. 만약 주석이 hash marks(`#`)으로 만든 박스 안에 들어있다면 당신의 주석도 그렇게 해야합니다.
5 |
6 | - 스타일 가이드라인의 요점은 코딩에서 공통된 어투를 갖는 것입니다. 그렇게 된다면 사람들은 당신의 코딩 형식보다는 당신의 코드에 집중할 수 있습니다
7 | - 우리는 여기서 사람들이 어휘를 알 수 있는 세계적인 코딩 스타일 규칙을 제공하지만 고유의 스타일도 중요합니다.
8 | - 파일에 코드를 추가했을 때 이 코드가 다른 코드와 비교하여 크게 달라 보이면 코드를 읽는 사람의 입장에서는 리듬이 깨집니다.
9 |
10 | - 그러나 일관성에는 한계가 있습니다.
11 | - 일관성은 주로 지역적으로 적용되며, 전역 스타일에서 명시되지 않은 선택에 더 강하게 적용됩니다.
12 | - 일관성을 구식 스타일을 고수하는 정당화의 근거로 삼기보다는 새로운 스타일의 장점이나 코드베이스가 시간이 지남에 따라 새로운 스타일로 수렴하는 경향을 고려하는 것이 좋습니다.
13 |
--------------------------------------------------------------------------------
/Google Python Style Guide/4. 맺음말/ReadMe.md:
--------------------------------------------------------------------------------
1 | 일관성을 유지하세요
2 |
3 | - 당신이 코드를 수정한다면 몇 분을 투자해서 코드를 살펴보고 스타일을 파악하세요.
4 | - 그들이 인덱스 변수 이름에 `_idx` 접미사를 사용하는 경우, 당신도 그렇게 해야 합니다. 만약 주석이 hash marks(`#`)으로 만든 박스 안에 들어있다면 당신의 주석도 그렇게 해야합니다.
5 |
6 | - 스타일 가이드라인의 요점은 코딩에서 공통된 어투를 갖는 것입니다. 그렇게 된다면 사람들은 당신의 코딩 형식보다는 당신의 코드에 집중할 수 있습니다
7 | - 우리는 여기서 사람들이 어휘를 알 수 있는 세계적인 코딩 스타일 규칙을 제공하지만 고유의 스타일도 중요합니다.
8 | - 파일에 코드를 추가했을 때 이 코드가 다른 코드와 비교하여 크게 달라 보이면 코드를 읽는 사람의 입장에서는 리듬이 깨집니다.
9 |
10 | - 그러나 일관성에는 한계가 있습니다.
11 | - 일관성은 주로 지역적으로 적용되며, 전역 스타일에서 명시되지 않은 선택에 더 강하게 적용됩니다.
12 | - 일관성을 구식 스타일을 고수하는 정당화의 근거로 삼기보다는 새로운 스타일의 장점이나 코드베이스가 시간이 지남에 따라 새로운 스타일로 수렴하는 경향을 고려하는 것이 좋습니다.
13 |
14 | ---
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Yosseulsin JOB : 요쓸신잡
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Google Python Style Guide 한글 번역
2 |
3 | - [**_`Google Python Style Guide`_(영문)**](http://google.github.io/styleguide/pyguide.html)을 번역하였습니다.
4 | - 많은 오타와 오역이 있을 수 있습니다. 계속해서 좋은 번역을 위한 [_`issues`_](https://github.com/Yosseulsin-JOB/Google-Python-Style-Guide-kor/issues)와 [_`pull requests`_](https://github.com/Yosseulsin-JOB/Google-Python-Style-Guide-kor/pulls) 부탁드립니다.
5 | - 번역은 [**_`구글 파이썬 스타일 가이드 페이지`_**](https://yosseulsin-job.github.io/Google-Python-Style-Guide-kor)와 [**_`여기(Github)`_**](https://github.com/Yosseulsin-JOB/Google-Python-Style-Guide-kor/blob/master/Google%20Python%20Style%20Guide%20kor.md)에서 보실 수 있습니다.
6 | - Contributors : [`0113bernoyoun`](https://github.com/0113bernoyoun), [`Sotaneum`](https://github.com/Sotaneum), [`denmark111`](https://github.com/denmark111), [`heumsi`](https://github.com/heumsi)
7 |
8 | ## Team 소개
9 |
10 | - [**_Yosseulsin JOB_**](https://github.com/Yosseulsin-JOB)은 요즘들 것의 쓸모있는 신선한 JOB일을 나누는 모임입니다.
11 | - 각 구성원들 개인 능력 향상을 위한 `토이 프로젝트`나 `컨퍼런스 참여` 등 `다양한 활동`을 `공유`나 같이 `참여`합니다.
12 |
13 | ## log
14 |
15 | - `2024.09.11` : [`8ee3431`](https://github.com/Yosseulsin-JOB/Google-Python-Style-Guide-kor/releases/tag/8ee3431) 기준 업데이트
16 |
17 | - `2023.10.08` : [`6e7639a`](https://github.com/Yosseulsin-JOB/Google-Python-Style-Guide-kor/releases/tag/6e7639a) 기준 업데이트
18 |
19 | - `2021.07.16` : [`4044bbd`](https://github.com/Yosseulsin-JOB/Google-Python-Style-Guide-kor/releases/tag/4044bbd) 기준 업데이트
20 |
21 | - `2020.08.09` : [`f87ee84`](https://github.com/Yosseulsin-JOB/Google-Python-Style-Guide-kor/releases/tag/f87ee84) 기준 업데이트
22 |
23 | - `2019.12.10` : [`6271f3f`](https://github.com/Yosseulsin-JOB/Google-Python-Style-Guide-kor/releases/tag/6271f3f) 기준 업데이트
24 |
--------------------------------------------------------------------------------
/script/build.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 | # pylint: disable=missing-module-docstring
3 | # pylint: disable=missing-class-docstring
4 | # pylint: disable=missing-function-docstring
5 |
6 |
7 |
8 | import os
9 | import re
10 |
11 | find_link = re.compile('\\[(\\w+)\\]\\(([\\w\\\\/_.:]+)\\)')
12 | find_nums = re.compile('([0-9]+)\\.([0-9]*).*')
13 |
14 | readme = []
15 | tree = []
16 |
17 | def get_files(folder):
18 | file_list = []
19 | filenames = os.listdir(folder)
20 | for filename in filenames:
21 | file_list.append(filename)
22 | return file_list
23 |
24 | def get_numbers(files):
25 | numbers = list(files.keys())
26 | numbers.sort()
27 | return numbers
28 |
29 | def get_file_list(path):
30 | files = get_files(path)
31 | file_list = {}
32 | for filename in files:
33 | nums = find_nums.search(filename)
34 | if not nums:
35 | continue
36 | num = int(nums.group(2) or nums.group(1))
37 | file_list.update({num: os.path.join(path, filename)})
38 | return file_list
39 |
40 | def file_list_foreach(files, f=print):
41 | for number in get_numbers(files):
42 | f(files[number], number, files)
43 |
44 | def write_readme(readme_path, data, override=False):
45 | write_type = 'w' if override is True else 'a'
46 | f = open(readme_path, write_type)
47 | f.write("".join(data))
48 | f.close()
49 |
50 | def insert_part_in_readme(part_path, number, all):
51 | part_tree = []
52 | target_readme = part_path.split(part_path.split('/')[-1])[0] + "ReadMe.md"
53 | f = open(part_path, 'r')
54 | lines = f.readlines()
55 | f.close()
56 | for i in range(0, len(lines)):
57 | syntax = lines[i].split(" ")[0]
58 | if syntax not in ["##", "###", "####"]:
59 | continue
60 | link = lines[i-2].replace('', "").replace("\n", "")
61 | title = lines[i].replace("# ", "").replace("#", "").replace("\n", "")
62 | link_in_title = find_link.search(title)
63 | if link_in_title:
64 | title = title.replace(link_in_title.group(), find_link.findall(title)[0][0])
65 | part_tree.append({"link":link, "title":title})
66 | if part_tree:
67 | tree.append(part_tree)
68 | # 파트가 시작하는 부분에 라인 추가 (d5e507c / #12)
69 | lines.append("\n---\n")
70 | write_readme(target_readme, lines, True if number == 1 else False)
71 |
72 | def tree_to_contents():
73 | contents = []
74 | for item in tree:
75 | if type(item) == dict:
76 | contents.append("- ["+item["title"]+"](#"+item["link"]+")")
77 | continue
78 | contents.append(" * ["+item[0]["title"]+"](#"+item[0]["link"]+")")
79 | for part in item[1:]:
80 | if part["title"].split(" ")[1] in ["정의", "장점", "단점", "결론"]:
81 | continue
82 | contents.append(" + ["+part["title"]+"](#"+part["link"]+")")
83 |
84 | return "\n".join(["\n", " Table of Contents
\n\n"]) + "\n".join(contents)+ "\n\n \n"
85 |
86 | def chapter_build(chapter_path, number, all):
87 | chapter_title = chapter_path.split("/")[-1]
88 | chapter_link = "s"+chapter_path.split("/")[-1].split(". ")[0]
89 | tree.append({"title":chapter_title, "link": chapter_link})
90 | chapter_header = [
91 | '\n\n',
92 | "\n",
93 | "## "+chapter_title +"\n\n",
94 | ]
95 | file_list_foreach(get_file_list(chapter_path), insert_part_in_readme)
96 | from_readme = chapter_path + "/ReadMe.md"
97 | f = open(from_readme, 'r')
98 | data = f.readlines()
99 | f.close()
100 | # 챕터가 시작하는 부분에
추가 (d5e507c / #12)
101 | readme.append("\n
\n" + "".join(chapter_header) + "".join(data))
102 |
103 | def build():
104 | to_readme = "./Google Python Style Guide kor.md"
105 |
106 | chapter_list = get_file_list('./Google Python Style Guide')
107 | file_list_foreach(chapter_list, chapter_build)
108 |
109 | title = "# Google Python Style Guide\n"
110 | Contents = tree_to_contents()
111 |
112 | write_readme(to_readme, title + Contents + "".join(readme), True)
113 |
114 | build()
115 |
--------------------------------------------------------------------------------
/script/update_original.py:
--------------------------------------------------------------------------------
1 | import os, sys, requests
2 | import urllib.request
3 | from github import Github
4 |
5 | MASTER_BRANCH = "master"
6 | MASTER_REF = "refs/heads/master"
7 | ORIGINAL_MARKDOWN_PATH = "Original.md"
8 | ACCESS_TOKEN = os.environ['ACCESS_TOKEN'] if "ACCESS_TOKEN" in os.environ else ""
9 | REPO_NAME = "Yosseulsin-JOB/Google-Python-Style-Guide-kor"
10 | RAW_MARKDOWN_URL = "https://raw.githubusercontent.com/google/styleguide/gh-pages/pyguide.md"
11 | GITHUB_COMMIT_API = "https://api.github.com/repos/google/styleguide/commits"
12 |
13 | def create_ref_name(commit):
14 | return 'refs/heads/original/' + commit['label']
15 |
16 |
17 | def create_branch_name(commit):
18 | return 'original/' + commit['label']
19 |
20 |
21 | def create_commit_title(commit):
22 | return 'merge ' + commit['label'] + ' 🛰'
23 |
24 |
25 | def create_pr_title(commit):
26 | return '['+commit['label']+'] 번역 요청 💬'
27 |
28 |
29 | def create_pr_body():
30 | return '''
31 | 새로운 번역이 왔습니다. 번역해주세요! 💤
32 | '''
33 |
34 | # 항상 루트에서 python ./script/update_original.py 로 실행해야 루트에 있는 Original.md 파일로 대체됩니다.
35 | def download_from_google_style_guide_original():
36 | urllib.request.urlretrieve(RAW_MARKDOWN_URL, ORIGINAL_MARKDOWN_PATH)
37 |
38 | # commit 이름과 링크를 가져옵니다.
39 | def get_commit_from_google_style_guide_original():
40 | response = requests.get(GITHUB_COMMIT_API, {'path': 'pyguide.md'});
41 | response.raise_for_status()
42 | commit_histories = response.json()
43 |
44 | if len(commit_histories) == 0 :
45 | raise Exception(
46 | "주소가 달라졌거나 selector 포맷이 변경되었습니다. 업데이트하세요. > ( https://github.com/Yosseulsin-JOB/Google-Python-Style-Guide-kor/blob/master/script/update_original.py )")
47 |
48 | commit_history = commit_histories[0];
49 | return {"label": commit_history['sha'][0:7], 'url': commit_history['html_url']}
50 |
51 |
52 | def get_repo():
53 | if ACCESS_TOKEN == "":
54 | raise Exception(
55 | "'ACCESS_TOKEN'값을 지정해 주세요. 이 값이 없으면 PR 생성이 불가합니다. ( https://github.com/Yosseulsin-JOB/Google-Python-Style-Guide-kor/settings/secrets/actions )")
56 | return Github(ACCESS_TOKEN).get_repo(REPO_NAME)
57 |
58 |
59 | def create_branch(repo, commit):
60 | ref = create_ref_name(commit)
61 | branch = repo.get_branch(branch=MASTER_BRANCH)
62 |
63 | try:
64 | repo.create_git_ref(ref=ref, sha=branch.commit.sha)
65 | except:
66 | return False
67 | return True
68 |
69 |
70 | def create_commit(repo, commit):
71 | branch = create_branch_name(commit)
72 | title = create_commit_title(commit)
73 | text = open(ORIGINAL_MARKDOWN_PATH, "r").read()
74 | contents = repo.get_contents(ORIGINAL_MARKDOWN_PATH, ref=MASTER_REF)
75 |
76 | repo.update_file(contents.path, title, text, contents.sha, branch=branch)
77 |
78 |
79 | def create_pull_request(repo, commit):
80 | body = create_pr_body()
81 | head = create_branch_name(commit)
82 | title = create_pr_title(commit)
83 |
84 | repo.create_pull(title=title, body=body, head=head, base=MASTER_BRANCH)
85 |
86 |
87 | if __name__ == "__main__":
88 |
89 | print("원본 데이터 > 다운로드 시작")
90 |
91 | # 스타일 가이드를 최신 버전을 가져옵니다.
92 | download_from_google_style_guide_original()
93 |
94 | print("원본 데이터 > 다운로드 완료")
95 | print("원본 데이터 > commit 정보 가져오기 시작")
96 |
97 | # 최신 버전의 commit id와 주소를 가져옵니다.
98 | commit = get_commit_from_google_style_guide_original()
99 |
100 | print("원본 데이터 > commit 정보 가져오기 완료")
101 | print("\n==================================")
102 | print("commit id : " + commit['label'])
103 | print("url : " + commit['url'])
104 | print("==================================\n")
105 | print("Github > 연동 작업 시작")
106 |
107 | # 스타일 가이드 한글판 레포를 가져옵니다.
108 | repo = get_repo()
109 |
110 | print("Github > 연동 작업 완료")
111 | print("Github > branch 생성 작업 시작")
112 |
113 | # 브랜치를 생성합니다.
114 | branch = create_branch(repo, commit)
115 |
116 | # 브랜치를 생성할 수 없는 상태라면 이미 생성된 것으로 더이상의 작업을 진행하지 않습니다.
117 | if branch is False:
118 | print('Github > branch 생성 작업 실패')
119 | print("\n==================================")
120 | print("이미 생성된 작업 요청과 동일한 Commit 입니다. 🚨")
121 | print("==================================\n")
122 | sys.exit(0)
123 |
124 | print("Github > branch 생성 작업 완료")
125 | print("Github > add 및 commit 작업 시작")
126 |
127 | # 업데이트 된 파일을 commit합니다.
128 | create_commit(repo, commit)
129 |
130 | print("Github > add 및 commit 작업 완료")
131 | print("Github > PR 작업 시작")
132 |
133 | # Pull Request를 생성합니다.
134 | create_pull_request(repo, commit)
135 |
136 | print("Github > PR 작업 완료")
137 |
--------------------------------------------------------------------------------
/script/update_original_requirements.txt:
--------------------------------------------------------------------------------
1 | requests==2.32.0
2 | PyGithub==1.51
3 |
--------------------------------------------------------------------------------