├── .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('' % (last_name, first_name)) 39 | items.append('
%s, %s
') 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 += '' % (last_name, first_name) 49 | employee_table += '
%s, %s
' 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('' % (last_name, first_name)) 765 | items.append('
%s, %s
') 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 += '' % (last_name, first_name) 775 | employee_table += '
%s, %s
' 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 | --------------------------------------------------------------------------------