mirror of
https://github.com/google/styleguide.git
synced 2024-03-22 13:11:43 +08:00
Project import generated by Copybara.
PiperOrigin-RevId: 510217476
This commit is contained in:
parent
f924e89a56
commit
e065b55718
429
pyguide.md
429
pyguide.md
|
@ -75,7 +75,7 @@ See README.md for details.
|
||||||
+ [3.19.7 Ignoring Types](#s3.19.7-ignoring-types)
|
+ [3.19.7 Ignoring Types](#s3.19.7-ignoring-types)
|
||||||
+ [3.19.8 Typing Variables](#s3.19.8-typing-variables)
|
+ [3.19.8 Typing Variables](#s3.19.8-typing-variables)
|
||||||
+ [3.19.9 Tuples vs Lists](#s3.19.9-tuples-vs-lists)
|
+ [3.19.9 Tuples vs Lists](#s3.19.9-tuples-vs-lists)
|
||||||
+ [3.19.10 TypeVars](#s3.19.10-typevars)
|
+ [3.19.10 Type variables](#s3.19.10-typevars)
|
||||||
+ [3.19.11 String types](#s3.19.11-string-types)
|
+ [3.19.11 String types](#s3.19.11-string-types)
|
||||||
+ [3.19.12 Imports For Typing](#s3.19.12-imports-for-typing)
|
+ [3.19.12 Imports For Typing](#s3.19.12-imports-for-typing)
|
||||||
+ [3.19.13 Conditional Imports](#s3.19.13-conditional-imports)
|
+ [3.19.13 Conditional Imports](#s3.19.13-conditional-imports)
|
||||||
|
@ -97,7 +97,7 @@ of *dos and don'ts* for Python programs.
|
||||||
|
|
||||||
To help you format code correctly, we've created a [settings file for Vim](google_python_style.vim). For Emacs, the default settings should be fine.
|
To help you format code correctly, we've created a [settings file for Vim](google_python_style.vim). For Emacs, the default settings should be fine.
|
||||||
|
|
||||||
Many teams use the [yapf](https://github.com/google/yapf/)
|
Many teams use the [Black](https://github.com/psf/black) or [Pyink](https://github.com/google/pyink)
|
||||||
auto-formatter to avoid arguing over formatting.
|
auto-formatter to avoid arguing over formatting.
|
||||||
|
|
||||||
|
|
||||||
|
@ -161,7 +161,8 @@ Suppress warnings if they are inappropriate so that other issues are not hidden.
|
||||||
To suppress warnings, you can set a line-level comment:
|
To suppress warnings, you can set a line-level comment:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
dict = 'something awful' # Bad Idea... pylint: disable=redefined-builtin
|
def do_PUT(self): # WSGI name, so pylint: disable=invalid-name
|
||||||
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
`pylint`
|
`pylint`
|
||||||
|
@ -185,7 +186,7 @@ pylint --list-msgs
|
||||||
To get more information on a particular message, use:
|
To get more information on a particular message, use:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
pylint --help-msg=C6409
|
pylint --help-msg=invalid-name
|
||||||
```
|
```
|
||||||
|
|
||||||
Prefer `pylint: disable` to the deprecated older form `pylint: disable-msg`.
|
Prefer `pylint: disable` to the deprecated older form `pylint: disable-msg`.
|
||||||
|
@ -195,7 +196,7 @@ beginning of the function. Always include a comment explaining why you are
|
||||||
deleting it. "Unused." is sufficient. For example:
|
deleting it. "Unused." is sufficient. For example:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def viking_cafe_order(spam: str, beans: str, eggs: Optional[str] = None) -> str:
|
def viking_cafe_order(spam: str, beans: str, eggs: str | None = None) -> str:
|
||||||
del beans, eggs # Unused by vikings.
|
del beans, eggs # Unused by vikings.
|
||||||
return spam + spam + spam
|
return spam + spam + spam
|
||||||
```
|
```
|
||||||
|
@ -347,7 +348,7 @@ No:
|
||||||
|
|
||||||
The directory the main binary is located in should not be assumed to be in
|
The directory the main binary is located in should not be assumed to be in
|
||||||
`sys.path` despite that happening in some environments. This being the case,
|
`sys.path` despite that happening in some environments. This being the case,
|
||||||
code should assume that `import jodie` refers to a third party or top level
|
code should assume that `import jodie` refers to a third-party or top-level
|
||||||
package named `jodie`, not a local `jodie.py`.
|
package named `jodie`, not a local `jodie.py`.
|
||||||
|
|
||||||
|
|
||||||
|
@ -494,7 +495,7 @@ Avoid mutable global state.
|
||||||
<a id="global-variables-definition"></a>
|
<a id="global-variables-definition"></a>
|
||||||
#### 2.5.1 Definition
|
#### 2.5.1 Definition
|
||||||
|
|
||||||
Module level values or class attributes that can get mutated during program
|
Module-level values or class attributes that can get mutated during program
|
||||||
execution.
|
execution.
|
||||||
|
|
||||||
<a id="s2.5.2-pros"></a>
|
<a id="s2.5.2-pros"></a>
|
||||||
|
@ -568,8 +569,8 @@ variables defined in enclosing scopes.
|
||||||
|
|
||||||
Allows definition of utility classes and functions that are only used inside of
|
Allows definition of utility classes and functions that are only used inside of
|
||||||
a very limited scope. Very
|
a very limited scope. Very
|
||||||
[ADT](http://www.google.com/url?sa=D&q=http://en.wikipedia.org/wiki/Abstract_data_type)-y.
|
[ADT](https://en.wikipedia.org/wiki/Abstract_data_type)-y. Commonly used for
|
||||||
Commonly used for implementing decorators.
|
implementing decorators.
|
||||||
|
|
||||||
<a id="s2.6.3-cons"></a>
|
<a id="s2.6.3-cons"></a>
|
||||||
<a id="263-cons"></a>
|
<a id="263-cons"></a>
|
||||||
|
@ -973,7 +974,7 @@ definition.
|
||||||
Yes: def foo(a, b=None):
|
Yes: def foo(a, b=None):
|
||||||
if b is None:
|
if b is None:
|
||||||
b = []
|
b = []
|
||||||
Yes: def foo(a, b: Optional[Sequence] = None):
|
Yes: def foo(a, b: Sequence | None = None):
|
||||||
if b is None:
|
if b is None:
|
||||||
b = []
|
b = []
|
||||||
Yes: def foo(a, b: Sequence = ()): # Empty tuple OK since tuples are immutable.
|
Yes: def foo(a, b: Sequence = ()): # Empty tuple OK since tuples are immutable.
|
||||||
|
@ -1197,8 +1198,8 @@ experienced Lisp and Scheme (and Haskell and ML and ...) programmers.
|
||||||
<a id="lexical-scoping-cons"></a>
|
<a id="lexical-scoping-cons"></a>
|
||||||
#### 2.16.3 Cons
|
#### 2.16.3 Cons
|
||||||
|
|
||||||
Can lead to confusing bugs. Such as this example based on
|
Can lead to confusing bugs, such as this example based on
|
||||||
[PEP-0227](http://www.google.com/url?sa=D&q=http://www.python.org/dev/peps/pep-0227/):
|
[PEP-0227](https://peps.python.org/pep-0227/):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
i = 4
|
i = 4
|
||||||
|
@ -1300,11 +1301,11 @@ decorator runs (at import time, perhaps from `pydoc` or other tools). A
|
||||||
decorator that is called with valid parameters should (as much as possible) be
|
decorator that is called with valid parameters should (as much as possible) be
|
||||||
guaranteed to succeed in all cases.
|
guaranteed to succeed in all cases.
|
||||||
|
|
||||||
Decorators are a special case of "top level code" - see [main](#s3.17-main) for
|
Decorators are a special case of "top-level code" - see [main](#s3.17-main) for
|
||||||
more discussion.
|
more discussion.
|
||||||
|
|
||||||
Never use `staticmethod` unless forced to in order to integrate with an API
|
Never use `staticmethod` unless forced to in order to integrate with an API
|
||||||
defined in an existing library. Write a module level function instead.
|
defined in an existing library. Write a module-level function instead.
|
||||||
|
|
||||||
Use `classmethod` only when writing a named constructor, or a class-specific
|
Use `classmethod` only when writing a named constructor, or a class-specific
|
||||||
routine that modifies necessary global state such as a process-wide cache.
|
routine that modifies necessary global state such as a process-wide cache.
|
||||||
|
@ -1323,8 +1324,8 @@ or `__eq__` are implemented as Python methods) and their atomicity should not be
|
||||||
relied upon. Neither should you rely on atomic variable assignment (since this
|
relied upon. Neither should you rely on atomic variable assignment (since this
|
||||||
in turn depends on dictionaries).
|
in turn depends on dictionaries).
|
||||||
|
|
||||||
Use the Queue module's `Queue` data type as the preferred way to communicate
|
Use the `queue` module's `Queue` data type as the preferred way to communicate
|
||||||
data between threads. Otherwise, use the threading module and its locking
|
data between threads. Otherwise, use the `threading` module and its locking
|
||||||
primitives. Prefer condition variables and `threading.Condition` instead of
|
primitives. Prefer condition variables and `threading.Condition` instead of
|
||||||
using lower-level locks.
|
using lower-level locks.
|
||||||
|
|
||||||
|
@ -1460,11 +1461,11 @@ Use other `from __future__` import statements as you see fit.
|
||||||
### 2.21 Type Annotated Code
|
### 2.21 Type Annotated Code
|
||||||
|
|
||||||
You can annotate Python code with type hints according to
|
You can annotate Python code with type hints according to
|
||||||
[PEP-484](https://www.python.org/dev/peps/pep-0484/), and type-check the code at
|
[PEP-484](https://peps.python.org/pep-0484/), and type-check the code at build
|
||||||
build time with a type checking tool like [pytype](https://github.com/google/pytype).
|
time with a type checking tool like [pytype](https://github.com/google/pytype).
|
||||||
|
|
||||||
Type annotations can be in the source or in a
|
Type annotations can be in the source or in a
|
||||||
[stub pyi file](https://www.python.org/dev/peps/pep-0484/#stub-files). Whenever
|
[stub pyi file](https://peps.python.org/pep-0484/#stub-files). Whenever
|
||||||
possible, annotations should be in the source. Use pyi files for third-party or
|
possible, annotations should be in the source. Use pyi files for third-party or
|
||||||
extension modules.
|
extension modules.
|
||||||
|
|
||||||
|
@ -1483,7 +1484,7 @@ def func(a: int) -> list[int]:
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also declare the type of a variable using similar
|
You can also declare the type of a variable using similar
|
||||||
[PEP-526](https://www.python.org/dev/peps/pep-0526/) syntax:
|
[PEP-526](https://peps.python.org/pep-0526/) syntax:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
a: SomeType = some_func()
|
a: SomeType = some_func()
|
||||||
|
@ -1554,23 +1555,53 @@ Explicit exceptions to the 80 character limit:
|
||||||
|
|
||||||
- Long import statements.
|
- Long import statements.
|
||||||
- URLs, pathnames, or long flags in comments.
|
- URLs, pathnames, or long flags in comments.
|
||||||
- Long string module level constants not containing whitespace that would be
|
- Long string module-level constants not containing whitespace that would be
|
||||||
inconvenient to split across lines such as URLs or pathnames.
|
inconvenient to split across lines such as URLs or pathnames.
|
||||||
- Pylint disable comments. (e.g.: `# pylint: disable=invalid-name`)
|
- Pylint disable comments. (e.g.: `# pylint: disable=invalid-name`)
|
||||||
|
|
||||||
Do not use backslash line continuation except for `with` statements requiring
|
Do not use a backslash for
|
||||||
three or more context managers.
|
[explicit line continuation](https://docs.python.org/3/reference/lexical_analysis.html#explicit-line-joining).
|
||||||
|
|
||||||
Make use of Python's
|
Instead, make use of Python's
|
||||||
[implicit line joining inside parentheses, brackets and braces](http://docs.python.org/reference/lexical_analysis.html#implicit-line-joining).
|
[implicit line joining inside parentheses, brackets and braces](http://docs.python.org/reference/lexical_analysis.html#implicit-line-joining).
|
||||||
If necessary, you can add an extra pair of parentheses around an expression.
|
If necessary, you can add an extra pair of parentheses around an expression.
|
||||||
|
|
||||||
|
Note that this rule doesn't prohibit backslash-escaped newlines within strings
|
||||||
|
(see [below](#strings)).
|
||||||
|
|
||||||
```python
|
```python
|
||||||
Yes: foo_bar(self, width, height, color='black', design=None, x='foo',
|
Yes: foo_bar(self, width, height, color='black', design=None, x='foo',
|
||||||
emphasis=None, highlight=0)
|
emphasis=None, highlight=0)
|
||||||
|
```
|
||||||
|
|
||||||
if (width == 0 and height == 0 and
|
```python
|
||||||
|
|
||||||
|
Yes: if (width == 0 and height == 0 and
|
||||||
color == 'red' and emphasis == 'strong'):
|
color == 'red' and emphasis == 'strong'):
|
||||||
|
|
||||||
|
(bridge_questions.clarification_on
|
||||||
|
.average_airspeed_of.unladen_swallow) = 'African or European?'
|
||||||
|
|
||||||
|
with (
|
||||||
|
very_long_first_expression_function() as spam,
|
||||||
|
very_long_second_expression_function() as beans,
|
||||||
|
third_thing() as eggs,
|
||||||
|
):
|
||||||
|
place_order(eggs, beans, spam, beans)
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
|
||||||
|
No: if width == 0 and height == 0 and \
|
||||||
|
color == 'red' and emphasis == 'strong':
|
||||||
|
|
||||||
|
bridge_questions.clarification_on \
|
||||||
|
.average_airspeed_of.unladen_swallow = 'African or European?'
|
||||||
|
|
||||||
|
with very_long_first_expression_function() as spam, \
|
||||||
|
very_long_second_expression_function() as beans, \
|
||||||
|
third_thing() as eggs:
|
||||||
|
place_order(eggs, beans, spam, beans)
|
||||||
```
|
```
|
||||||
|
|
||||||
When a literal string won't fit on a single line, use parentheses for implicit
|
When a literal string won't fit on a single line, use parentheses for implicit
|
||||||
|
@ -1581,6 +1612,37 @@ x = ('This will build a very long long '
|
||||||
'long long long long long long string')
|
'long long long long long long string')
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Prefer to break lines at the highest possible syntactic level. If you must break
|
||||||
|
a line twice, break it at the same syntactic level both times.
|
||||||
|
|
||||||
|
```python
|
||||||
|
Yes: bridgekeeper.answer(
|
||||||
|
name="Arthur", quest=questlib.find(owner="Arthur", perilous=True))
|
||||||
|
|
||||||
|
answer = (a_long_line().of_chained_methods()
|
||||||
|
.that_eventually_provides().an_answer())
|
||||||
|
|
||||||
|
if (
|
||||||
|
config is None
|
||||||
|
or 'editor.language' not in config
|
||||||
|
or config['editor.language'].use_spaces is False
|
||||||
|
):
|
||||||
|
use_tabs()
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
No: bridgekeeper.answer(name="Arthur", quest=questlib.find(
|
||||||
|
owner="Arthur", perilous=True))
|
||||||
|
|
||||||
|
answer = a_long_line().of_chained_methods().that_eventually_provides(
|
||||||
|
).an_answer()
|
||||||
|
|
||||||
|
if (config is None or 'editor.language' not in config or config[
|
||||||
|
'editor.language'].use_spaces is False):
|
||||||
|
use_tabs()
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
Within comments, put long URLs on their own line if necessary.
|
Within comments, put long URLs on their own line if necessary.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -1594,29 +1656,6 @@ No: # See details at
|
||||||
# v2.0/csv_file_name_extension_full_specification.html
|
# v2.0/csv_file_name_extension_full_specification.html
|
||||||
```
|
```
|
||||||
|
|
||||||
It is permissible to use backslash continuation when defining a `with` statement
|
|
||||||
with three or more context managers. For two context managers, use a nested
|
|
||||||
`with` statement:
|
|
||||||
|
|
||||||
```python
|
|
||||||
Yes: with very_long_first_expression_function() as spam, \
|
|
||||||
very_long_second_expression_function() as beans, \
|
|
||||||
third_thing() as eggs:
|
|
||||||
place_order(eggs, beans, spam, beans)
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
No: with VeryLongFirstExpressionFunction() as spam, \
|
|
||||||
VeryLongSecondExpressionFunction() as beans:
|
|
||||||
PlaceOrder(beans, spam)
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
Yes: with very_long_first_expression_function() as spam:
|
|
||||||
with very_long_second_expression_function() as beans:
|
|
||||||
place_order(beans, spam)
|
|
||||||
```
|
|
||||||
|
|
||||||
Make note of the indentation of the elements in the line continuation examples
|
Make note of the indentation of the elements in the line continuation examples
|
||||||
above; see the [indentation](#s3.4-indentation) section for explanation.
|
above; see the [indentation](#s3.4-indentation) section for explanation.
|
||||||
|
|
||||||
|
@ -1753,151 +1792,7 @@ No: # Stuff on first line forbidden.
|
||||||
Trailing commas in sequences of items are recommended only when the closing
|
Trailing commas in sequences of items are recommended only when the closing
|
||||||
container token `]`, `)`, or `}` does not appear on the same line as the final
|
container token `]`, `)`, or `}` does not appear on the same line as the final
|
||||||
element. The presence of a trailing comma is also used as a hint to our Python
|
element. The presence of a trailing comma is also used as a hint to our Python
|
||||||
code auto-formatter [YAPF](https://pypi.org/project/yapf/) to direct it to auto-format the container
|
code auto-formatter
|
||||||
of items to one item per line when the `,` after the final element is present.
|
|
||||||
|
|
||||||
```python
|
|
||||||
Yes: golomb3 = [0, 1, 3]
|
|
||||||
Yes: golomb4 = [
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
4,
|
|
||||||
6,
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
No: golomb4 = [
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
4,
|
|
||||||
6
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
<a id="s3.5-blank-lines"></a>
|
|
||||||
<a id="35-blank-lines"></a>
|
|
||||||
|
|
||||||
<a id="blank-lines"></a>
|
|
||||||
### 3.5 Blank Lines
|
|
||||||
|
|
||||||
Two blank lines between top-level definitions, be they function or class
|
|
||||||
definitions. One blank line between method definitions and between the docstring
|
|
||||||
of a `class` and the first method. No blank line following a `def` line. Use
|
|
||||||
single blank lines as you judge appropriate within functions or methods.
|
|
||||||
|
|
||||||
Blank lines need not be anchored to the definition. For example, related
|
|
||||||
comments immediately preceding function, class, and method definitions can make
|
|
||||||
sense. Consider if your comment might be more useful as part of the docstring.
|
|
||||||
|
|
||||||
<a id="s3.6-whitespace"></a>
|
|
||||||
<a id="36-whitespace"></a>
|
|
||||||
|
|
||||||
<a id="whitespace"></a>
|
|
||||||
### 3.6 Whitespace
|
|
||||||
|
|
||||||
Follow standard typographic rules for the use of spaces around punctuation.
|
|
||||||
|
|
||||||
No whitespace inside parentheses, brackets or braces.
|
|
||||||
|
|
||||||
```python
|
|
||||||
Yes: spam(ham[1], {'eggs': 2}, [])
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
No: spam( ham[ 1 ], { 'eggs': 2 }, [ ] )
|
|
||||||
```
|
|
||||||
|
|
||||||
No whitespace before a comma, semicolon, or colon. Do use whitespace after a
|
|
||||||
comma, semicolon, or colon, except at the end of the line.
|
|
||||||
|
|
||||||
```python
|
|
||||||
Yes: if x == 4:
|
|
||||||
print(x, y)
|
|
||||||
x, y = y, x
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
No: if x == 4 :
|
|
||||||
print(x , y)
|
|
||||||
x , y = y , x
|
|
||||||
```
|
|
||||||
|
|
||||||
No whitespace before the open paren/bracket that starts an argument list,
|
|
||||||
indexing or slicing.
|
|
||||||
|
|
||||||
```python
|
|
||||||
Yes: spam(1)
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
No: spam (1)
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
Yes: dict['key'] = list[index]
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
No: dict ['key'] = list [index]
|
|
||||||
```
|
|
||||||
|
|
||||||
No trailing whitespace.
|
|
||||||
|
|
||||||
Surround binary operators with a single space on either side for assignment
|
|
||||||
(`=`), comparisons (`==, <, >, !=, <>, <=, >=, in, not in, is, is not`), and
|
|
||||||
Booleans (`and, or, not`). Use your better judgment for the insertion of spaces
|
|
||||||
around arithmetic operators (`+`, `-`, `*`, `/`, `//`, `%`, `**`, `@`).
|
|
||||||
|
|
||||||
```python
|
|
||||||
Yes: x == 1
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
No: x<1
|
|
||||||
```
|
|
||||||
|
|
||||||
Never use spaces around `=` when passing keyword arguments or defining a default
|
|
||||||
parameter value, with one exception:
|
|
||||||
[when a type annotation is present](#typing-default-values), *do* use spaces
|
|
||||||
around the `=` for the default parameter value.
|
|
||||||
|
|
||||||
```python
|
|
||||||
Yes: def complex(real, imag=0.0): return Magic(r=real, i=imag)
|
|
||||||
Yes: def complex(real, imag: float = 0.0): return Magic(r=real, i=imag)
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
No: def complex(real, imag = 0.0): return Magic(r = real, i = imag)
|
|
||||||
No: def complex(real, imag: float=0.0): return Magic(r = real, i = imag)
|
|
||||||
```
|
|
||||||
|
|
||||||
Don't use spaces to vertically align tokens on consecutive lines, since it
|
|
||||||
becomes a maintenance burden (applies to `:`, `#`, `=`, etc.):
|
|
||||||
|
|
||||||
```python
|
|
||||||
Yes:
|
|
||||||
foo = 1000 # comment
|
|
||||||
long_name = 2 # comment that should not be aligned
|
|
||||||
|
|
||||||
dictionary = {
|
|
||||||
'foo': 1,
|
|
||||||
'long_name': 2,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
No:
|
|
||||||
foo = 1000 # comment
|
|
||||||
long_name = 2 # comment that should not be aligned
|
|
||||||
|
|
||||||
dictionary = {
|
|
||||||
'foo' : 1,
|
|
||||||
'long_name': 2,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
<a id="Python_Interpreter"></a>
|
<a id="Python_Interpreter"></a>
|
||||||
<a id="s3.7-shebang-line"></a>
|
<a id="s3.7-shebang-line"></a>
|
||||||
<a id="37-shebang-line"></a>
|
<a id="37-shebang-line"></a>
|
||||||
|
@ -1908,7 +1803,7 @@ No:
|
||||||
Most `.py` files do not need to start with a `#!` line. Start the main file of a
|
Most `.py` files do not need to start with a `#!` line. Start the main file of a
|
||||||
program with
|
program with
|
||||||
`#!/usr/bin/env python3` (to support virtualenvs) or `#!/usr/bin/python3` per
|
`#!/usr/bin/env python3` (to support virtualenvs) or `#!/usr/bin/python3` per
|
||||||
[PEP-394](https://www.python.org/dev/peps/pep-0394/).
|
[PEP-394](https://peps.python.org/pep-0394/).
|
||||||
|
|
||||||
This line is used by the kernel to find the Python interpreter, but is ignored by Python when importing modules. It is only necessary on a file intended to be executed directly.
|
This line is used by the kernel to find the Python interpreter, but is ignored by Python when importing modules. It is only necessary on a file intended to be executed directly.
|
||||||
|
|
||||||
|
@ -1933,15 +1828,14 @@ Python uses *docstrings* to document code. A docstring is a string that is the
|
||||||
first statement in a package, module, class or function. These strings can be
|
first statement in a package, module, class or function. These strings can be
|
||||||
extracted automatically through the `__doc__` member of the object and are used
|
extracted automatically through the `__doc__` member of the object and are used
|
||||||
by `pydoc`.
|
by `pydoc`.
|
||||||
(Try running `pydoc` on your module to see how it looks.) Always use the three
|
(Try running `pydoc` on your module to see how it looks.) Always use the
|
||||||
double-quote `"""` format for docstrings (per
|
three-double-quote `"""` format for docstrings (per
|
||||||
[PEP 257](https://www.google.com/url?sa=D&q=http://www.python.org/dev/peps/pep-0257/)).
|
[PEP 257](https://peps.python.org/pep-0257/)). A docstring should be organized
|
||||||
A docstring should be organized as a summary line (one physical line not
|
as a summary line (one physical line not exceeding 80 characters) terminated by
|
||||||
exceeding 80 characters) terminated by a period, question mark, or exclamation
|
a period, question mark, or exclamation point. When writing more (encouraged),
|
||||||
point. When writing more (encouraged), this must be followed by a blank line,
|
this must be followed by a blank line, followed by the rest of the docstring
|
||||||
followed by the rest of the docstring starting at the same cursor position as
|
starting at the same cursor position as the first quote of the first line. There
|
||||||
the first quote of the first line. There are more formatting guidelines for
|
are more formatting guidelines for docstrings below.
|
||||||
docstrings below.
|
|
||||||
|
|
||||||
<a id="s3.8.2-comments-in-modules"></a>
|
<a id="s3.8.2-comments-in-modules"></a>
|
||||||
<a id="382-modules"></a>
|
<a id="382-modules"></a>
|
||||||
|
@ -1950,12 +1844,12 @@ docstrings below.
|
||||||
<a id="module-docs"></a>
|
<a id="module-docs"></a>
|
||||||
#### 3.8.2 Modules
|
#### 3.8.2 Modules
|
||||||
|
|
||||||
Every file should contain license boilerplate. Choose the appropriate boilerplate for the license used by the project (for example, Apache 2.0, BSD, LGPL, GPL)
|
Every file should contain license boilerplate. Choose the appropriate boilerplate for the license used by the project (for example, Apache 2.0, BSD, LGPL, GPL).
|
||||||
|
|
||||||
Files should start with a docstring describing the contents and usage of the
|
Files should start with a docstring describing the contents and usage of the
|
||||||
module.
|
module.
|
||||||
```python
|
```python
|
||||||
"""A one line summary of the module or program, terminated by a period.
|
"""A one-line summary of the module or program, terminated by a period.
|
||||||
|
|
||||||
Leave one blank line. The rest of this docstring should contain an
|
Leave one blank line. The rest of this docstring should contain an
|
||||||
overall description of the module or program. Optionally, it may also
|
overall description of the module or program. Optionally, it may also
|
||||||
|
@ -2081,8 +1975,9 @@ aptly described using a one-line docstring.
|
||||||
part of the API).
|
part of the API).
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def fetch_smalltable_rows(table_handle: smalltable.Table,
|
def fetch_smalltable_rows(
|
||||||
keys: Sequence[Union[bytes, str]],
|
table_handle: smalltable.Table,
|
||||||
|
keys: Sequence[bytes | str],
|
||||||
require_all_keys: bool = False,
|
require_all_keys: bool = False,
|
||||||
) -> Mapping[bytes, tuple[str, ...]]:
|
) -> Mapping[bytes, tuple[str, ...]]:
|
||||||
"""Fetches rows from a Smalltable.
|
"""Fetches rows from a Smalltable.
|
||||||
|
@ -2118,8 +2013,9 @@ def fetch_smalltable_rows(table_handle: smalltable.Table,
|
||||||
Similarly, this variation on `Args:` with a line break is also allowed:
|
Similarly, this variation on `Args:` with a line break is also allowed:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def fetch_smalltable_rows(table_handle: smalltable.Table,
|
def fetch_smalltable_rows(
|
||||||
keys: Sequence[Union[bytes, str]],
|
table_handle: smalltable.Table,
|
||||||
|
keys: Sequence[bytes | str],
|
||||||
require_all_keys: bool = False,
|
require_all_keys: bool = False,
|
||||||
) -> Mapping[bytes, tuple[str, ...]]:
|
) -> Mapping[bytes, tuple[str, ...]]:
|
||||||
"""Fetches rows from a Smalltable.
|
"""Fetches rows from a Smalltable.
|
||||||
|
@ -2179,7 +2075,11 @@ class SampleClass:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, likes_spam: bool = False):
|
def __init__(self, likes_spam: bool = False):
|
||||||
"""Inits SampleClass with blah."""
|
"""Initializes the instance based on spam preference.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
likes_spam: Defines if instance exhibits this preference.
|
||||||
|
"""
|
||||||
self.likes_spam = likes_spam
|
self.likes_spam = likes_spam
|
||||||
self.eggs = 0
|
self.eggs = 0
|
||||||
|
|
||||||
|
@ -2293,6 +2193,7 @@ Yes: x = f'name: {name}; score: {n}'
|
||||||
x = '%s, %s!' % (imperative, expletive)
|
x = '%s, %s!' % (imperative, expletive)
|
||||||
x = '{}, {}'.format(first, second)
|
x = '{}, {}'.format(first, second)
|
||||||
x = 'name: %s; score: %d' % (name, n)
|
x = 'name: %s; score: %d' % (name, n)
|
||||||
|
x = 'name: %(name)s; score: %(score)d' % {'name':name, 'score':n}
|
||||||
x = 'name: {}; score: {}'.format(name, n)
|
x = 'name: {}; score: {}'.format(name, n)
|
||||||
x = a + b
|
x = a + b
|
||||||
```
|
```
|
||||||
|
@ -2309,7 +2210,7 @@ be optimized on CPython, that is an implementation detail. The conditions under
|
||||||
which an optimization applies are not easy to predict and may change. Instead,
|
which an optimization applies are not easy to predict and may change. Instead,
|
||||||
add each substring to a list and `''.join` the list after the loop terminates,
|
add each substring to a list and `''.join` the list after the loop terminates,
|
||||||
or write each substring to an `io.StringIO` buffer. These techniques
|
or write each substring to an `io.StringIO` buffer. These techniques
|
||||||
consistently have amortized-linear run time complexity.
|
consistently have amortized-linear run-time complexity.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
Yes: items = ['<table>']
|
Yes: items = ['<table>']
|
||||||
|
@ -2388,6 +2289,11 @@ Don't do this.
|
||||||
will collapse common leading spaces in each line.""")
|
will collapse common leading spaces in each line.""")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note that using a backslash here does not violate the prohibition against
|
||||||
|
[explicit line continuation](#line-length); in this case, the backslash is
|
||||||
|
[escaping a newline](https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals)
|
||||||
|
in a string literal.
|
||||||
|
|
||||||
<a id="s3.10.1-logging"></a>
|
<a id="s3.10.1-logging"></a>
|
||||||
<a id="3101-logging"></a>
|
<a id="3101-logging"></a>
|
||||||
<a id="logging"></a>
|
<a id="logging"></a>
|
||||||
|
@ -2644,7 +2550,7 @@ grouped from most generic to least generic:
|
||||||
```
|
```
|
||||||
|
|
||||||
5. **Deprecated:** application-specific imports that are part of the same
|
5. **Deprecated:** application-specific imports that are part of the same
|
||||||
top level
|
top-level
|
||||||
sub-package as this file. For example:
|
sub-package as this file. For example:
|
||||||
|
|
||||||
|
|
||||||
|
@ -2782,8 +2688,8 @@ Always use a `.py` filename extension. Never use dashes.
|
||||||
- counters or iterators (e.g. `i`, `j`, `k`, `v`, et al.)
|
- counters or iterators (e.g. `i`, `j`, `k`, `v`, et al.)
|
||||||
- `e` as an exception identifier in `try/except` statements.
|
- `e` as an exception identifier in `try/except` statements.
|
||||||
- `f` as a file handle in `with` statements
|
- `f` as a file handle in `with` statements
|
||||||
- private [`TypeVar`s](#typing-type-var) with no constraints (e.g. `_T`,
|
- private [type variables](#typing-type-var) with no constraints (e.g.
|
||||||
`_U`, `_V`)
|
`_T = TypeVar("_T")`, `_P = ParamSpec("_P")`)
|
||||||
|
|
||||||
Please be mindful not to abuse single-character naming. Generally speaking,
|
Please be mindful not to abuse single-character naming. Generally speaking,
|
||||||
descriptiveness should be proportional to the name's scope of visibility.
|
descriptiveness should be proportional to the name's scope of visibility.
|
||||||
|
@ -2826,11 +2732,11 @@ Always use a `.py` filename extension. Never use dashes.
|
||||||
a class. ("wait -- did I write `import StringIO` or `from StringIO import
|
a class. ("wait -- did I write `import StringIO` or `from StringIO import
|
||||||
StringIO`?")
|
StringIO`?")
|
||||||
|
|
||||||
- Underscores may appear in *unittest* method names starting with `test` to
|
- New *unit test* files follow PEP 8 compliant lower\_with\_under method
|
||||||
separate logical components of the name, even if those components use
|
names, for example, `test_<method_under_test>_<state>`. For consistency(\*)
|
||||||
CapWords. One possible pattern is `test<MethodUnderTest>_<state>`; for
|
with legacy modules that follow CapWords function names, underscores may
|
||||||
example `testPop_EmptyStack` is okay. There is no One Correct Way to name
|
appear in method names starting with `test` to separate logical components
|
||||||
test methods.
|
of the name. One possible pattern is `test<MethodUnderTest>_<state>`.
|
||||||
|
|
||||||
<a id="s3.16.3-file-naming"></a>
|
<a id="s3.16.3-file-naming"></a>
|
||||||
<a id="3163-file-naming"></a>
|
<a id="3163-file-naming"></a>
|
||||||
|
@ -3015,8 +2921,7 @@ the function into smaller and more manageable pieces.
|
||||||
<a id="typing-general"></a>
|
<a id="typing-general"></a>
|
||||||
#### 3.19.1 General Rules
|
#### 3.19.1 General Rules
|
||||||
|
|
||||||
* Familiarize yourself with
|
* Familiarize yourself with [PEP-484](https://peps.python.org/pep-0484/).
|
||||||
[PEP-484](https://www.python.org/dev/peps/pep-0484/).
|
|
||||||
|
|
||||||
* In methods, only annotate `self`, or `cls` if it is necessary for proper
|
* In methods, only annotate `self`, or `cls` if it is necessary for proper
|
||||||
type information. e.g.,
|
type information. e.g.,
|
||||||
|
@ -3061,7 +2966,7 @@ def my_method(
|
||||||
self,
|
self,
|
||||||
first_var: int,
|
first_var: int,
|
||||||
second_var: Foo,
|
second_var: Foo,
|
||||||
third_var: Optional[Bar],
|
third_var: Bar | None,
|
||||||
) -> int:
|
) -> int:
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
@ -3084,7 +2989,7 @@ parenthesis with the `def`:
|
||||||
Yes:
|
Yes:
|
||||||
def my_method(
|
def my_method(
|
||||||
self,
|
self,
|
||||||
other_arg: Optional[MyLongType],
|
other_arg: MyLongType | None,
|
||||||
) -> tuple[MyLongType1, MyLongType1]:
|
) -> tuple[MyLongType1, MyLongType1]:
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
@ -3107,7 +3012,7 @@ opening one, but this is less readable.
|
||||||
```python
|
```python
|
||||||
No:
|
No:
|
||||||
def my_method(self,
|
def my_method(self,
|
||||||
other_arg: Optional[MyLongType],
|
other_arg: MyLongType | None,
|
||||||
) -> dict[OtherLongType, MyLongType]:
|
) -> dict[OtherLongType, MyLongType]:
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
@ -3185,8 +3090,7 @@ class OtherClass:
|
||||||
<a id="typing-default-values"></a>
|
<a id="typing-default-values"></a>
|
||||||
#### 3.19.4 Default Values
|
#### 3.19.4 Default Values
|
||||||
|
|
||||||
As per
|
As per [PEP-008](https://peps.python.org/pep-0008/#other-recommendations), use
|
||||||
[PEP-008](https://www.python.org/dev/peps/pep-0008/#other-recommendations), use
|
|
||||||
spaces around the `=` *only* for arguments that have both a type annotation and
|
spaces around the `=` *only* for arguments that have both a type annotation and
|
||||||
a default value.
|
a default value.
|
||||||
|
|
||||||
|
@ -3211,18 +3115,18 @@ def func(a:int=0) -> int:
|
||||||
|
|
||||||
In the Python type system, `NoneType` is a "first class" type, and for typing
|
In the Python type system, `NoneType` is a "first class" type, and for typing
|
||||||
purposes, `None` is an alias for `NoneType`. If an argument can be `None`, it
|
purposes, `None` is an alias for `NoneType`. If an argument can be `None`, it
|
||||||
has to be declared! You can use `Union`, but if there is only one other type,
|
has to be declared! You can use `|` union type expressions (recommended in new
|
||||||
use `Optional`.
|
Python 3.10+ code), or the older `Optional` and `Union` syntaxes.
|
||||||
|
|
||||||
Use explicit `Optional` instead of implicit `Optional`. Earlier versions of PEP
|
Use explicit `X | None` instead of implicit. Earlier versions of PEP 484 allowed
|
||||||
484 allowed `a: str = None` to be interpreted as `a: Optional[str] = None`, but
|
`a: str = None` to be interpreted as `a: str | None = None`, but that is no
|
||||||
that is no longer the preferred behavior.
|
longer the preferred behavior.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
Yes:
|
Yes:
|
||||||
def func(a: Optional[str], b: Optional[str] = None) -> str:
|
def modern_or_union(a: str | int | None, b: str | None = None) -> str:
|
||||||
...
|
...
|
||||||
def multiple_nullable_union(a: Union[None, str, int]) -> str:
|
def union_optional(a: Union[str, int, None], b: Optional[str] = None) -> str:
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -3245,19 +3149,13 @@ def implicit_optional(a: str = None) -> str:
|
||||||
You can declare aliases of complex types. The name of an alias should be
|
You can declare aliases of complex types. The name of an alias should be
|
||||||
CapWorded. If the alias is used only in this module, it should be \_Private.
|
CapWorded. If the alias is used only in this module, it should be \_Private.
|
||||||
|
|
||||||
For example, if the name of the module together with the name of the type is too
|
Note that the `: TypeAlias` annotation is only supported in versions 3.10+.
|
||||||
long:
|
|
||||||
|
|
||||||
<!-- Annotate below with `typing.TypeAlias` for 3.10. -->
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
_LossAndGradient = tuple[tf.Tensor, tf.Tensor]
|
_LossAndGradient: TypeAlias = tuple[tf.Tensor, tf.Tensor]
|
||||||
ComplexTFMap = Mapping[str, _LossAndGradient]
|
ComplexTFMap: TypeAlias = Mapping[str, _LossAndGradient]
|
||||||
```
|
```
|
||||||
|
|
||||||
Other examples are complex nested types and multiple return variables from a
|
|
||||||
function (as a tuple).
|
|
||||||
|
|
||||||
<a id="s3.19.7-ignoring-types"></a>
|
<a id="s3.19.7-ignoring-types"></a>
|
||||||
<a id="s3.19.7-ignore"></a>
|
<a id="s3.19.7-ignore"></a>
|
||||||
<a id="3197-ignoring-types"></a>
|
<a id="3197-ignoring-types"></a>
|
||||||
|
@ -3325,23 +3223,31 @@ c: tuple[int, str, float] = (1, "2", 3.5)
|
||||||
<a id="typing-type-var"></a>
|
<a id="typing-type-var"></a>
|
||||||
|
|
||||||
<a id="typevars"></a>
|
<a id="typevars"></a>
|
||||||
#### 3.19.10 TypeVars
|
#### 3.19.10 Type variables
|
||||||
|
|
||||||
The Python type system has
|
The Python type system has
|
||||||
[generics](https://www.python.org/dev/peps/pep-0484/#generics). The factory
|
[generics](https://peps.python.org/pep-0484/#generics). A type variable, such as
|
||||||
function `TypeVar` is a common way to use them.
|
`TypeVar` and `ParamSpec`, is a common way to use them.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from typing import TypeVar
|
from collections.abc import Callable
|
||||||
|
from typing import ParamSpec, TypeVar
|
||||||
|
_P = ParamSpec("_P")
|
||||||
_T = TypeVar("_T")
|
_T = TypeVar("_T")
|
||||||
...
|
...
|
||||||
def next(l: list[_T]) -> _T:
|
def next(l: list[_T]) -> _T:
|
||||||
return l.pop()
|
return l.pop()
|
||||||
|
|
||||||
|
def print_when_called(f: Callable[_P, _T]) -> Callable[_P, _T]:
|
||||||
|
def inner(*args: P.args, **kwargs: P.kwargs) -> R:
|
||||||
|
print('Function was called')
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
return inner
|
||||||
```
|
```
|
||||||
|
|
||||||
A TypeVar can be constrained:
|
A `TypeVar` can be constrained:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
AddableType = TypeVar("AddableType", int, float, str)
|
AddableType = TypeVar("AddableType", int, float, str)
|
||||||
|
@ -3360,8 +3266,8 @@ def check_length(x: AnyStr) -> AnyStr:
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
```
|
```
|
||||||
|
|
||||||
A TypeVar must have a descriptive name, unless it meets all of the following
|
A type variable must have a descriptive name, unless it meets all of the
|
||||||
criteria:
|
following criteria:
|
||||||
|
|
||||||
* not externally visible
|
* not externally visible
|
||||||
* not constrained
|
* not constrained
|
||||||
|
@ -3369,6 +3275,7 @@ criteria:
|
||||||
```python
|
```python
|
||||||
Yes:
|
Yes:
|
||||||
_T = TypeVar("_T")
|
_T = TypeVar("_T")
|
||||||
|
_P = ParamSpec("_P")
|
||||||
AddableType = TypeVar("AddableType", int, float, str)
|
AddableType = TypeVar("AddableType", int, float, str)
|
||||||
AnyFunction = TypeVar("AnyFunction", bound=Callable)
|
AnyFunction = TypeVar("AnyFunction", bound=Callable)
|
||||||
```
|
```
|
||||||
|
@ -3376,6 +3283,7 @@ Yes:
|
||||||
```python
|
```python
|
||||||
No:
|
No:
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
P = ParamSpec("P")
|
||||||
_T = TypeVar("_T", int, float, str)
|
_T = TypeVar("_T", int, float, str)
|
||||||
_F = TypeVar("_F", bound=Callable)
|
_F = TypeVar("_F", bound=Callable)
|
||||||
```
|
```
|
||||||
|
@ -3418,7 +3326,7 @@ line from the `typing` and `collections.abc` modules. Ex:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from collections.abc import Mapping, Sequence
|
from collections.abc import Mapping, Sequence
|
||||||
from typing import Any, Union
|
from typing import Any, Generic
|
||||||
```
|
```
|
||||||
|
|
||||||
Given that this way of importing adds items to the local namespace, names in
|
Given that this way of importing adds items to the local namespace, names in
|
||||||
|
@ -3460,7 +3368,7 @@ def generate_foo_scores(foo: Set[str]) -> List[float]:
|
||||||
|
|
||||||
Use conditional imports only in exceptional cases where the additional imports
|
Use conditional imports only in exceptional cases where the additional imports
|
||||||
needed for type checking must be avoided at runtime. This pattern is
|
needed for type checking must be avoided at runtime. This pattern is
|
||||||
discouraged; alternatives such as refactoring the code to allow top level
|
discouraged; alternatives such as refactoring the code to allow top-level
|
||||||
imports should be preferred.
|
imports should be preferred.
|
||||||
|
|
||||||
Imports that are needed only for type annotations can be placed within an `if
|
Imports that are needed only for type annotations can be placed within an `if
|
||||||
|
@ -3496,8 +3404,8 @@ because each module has to depend on the other.
|
||||||
|
|
||||||
Replace modules that create circular dependency imports with `Any`. Set an
|
Replace modules that create circular dependency imports with `Any`. Set an
|
||||||
[alias](#typing-aliases) with a meaningful name, and use the real type name from
|
[alias](#typing-aliases) with a meaningful name, and use the real type name from
|
||||||
this module (any attribute of Any is Any). Alias definitions should be separated
|
this module (any attribute of `Any` is `Any`). Alias definitions should be
|
||||||
from the last import by one line.
|
separated from the last import by one line.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
@ -3517,21 +3425,18 @@ def my_method(self, var: "some_mod.SomeType") -> None:
|
||||||
#### 3.19.15 Generics
|
#### 3.19.15 Generics
|
||||||
|
|
||||||
When annotating, prefer to specify type parameters for generic types; otherwise,
|
When annotating, prefer to specify type parameters for generic types; otherwise,
|
||||||
[the generics' parameters will be assumed to be `Any`](https://www.python.org/dev/peps/pep-0484/#the-any-type).
|
[the generics' parameters will be assumed to be `Any`](https://peps.python.org/pep-0484/#the-any-type).
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Yes:
|
# Yes:
|
||||||
def get_names(employee_ids: list[int]) -> dict[int, Any]:
|
def get_names(employee_ids: Sequence[int]) -> Mapping[int, str]:
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# No:
|
# No:
|
||||||
# These are both interpreted as get_names(employee_ids: list[Any]) -> dict[Any, Any]
|
# This is interpreted as get_names(employee_ids: Sequence[Any]) -> Mapping[Any, Any]
|
||||||
def get_names(employee_ids: list) -> Dict:
|
def get_names(employee_ids: Sequence) -> Mapping:
|
||||||
...
|
|
||||||
|
|
||||||
def get_names(employee_ids: List) -> Dict:
|
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -3541,14 +3446,14 @@ appropriate:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# No:
|
# No:
|
||||||
def get_names(employee_ids: list[Any]) -> dict[Any, str]:
|
def get_names(employee_ids: Sequence[Any]) -> Mapping[Any, str]:
|
||||||
"""Returns a mapping from employee ID to employee name for given IDs."""
|
"""Returns a mapping from employee ID to employee name for given IDs."""
|
||||||
```
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Yes:
|
# Yes:
|
||||||
_T = TypeVar('_T')
|
_T = TypeVar('_T')
|
||||||
def get_names(employee_ids: list[_T]) -> dict[_T, str]:
|
def get_names(employee_ids: Sequence[_T]) -> Mapping[_T, str]:
|
||||||
"""Returns a mapping from employee ID to employee name for given IDs."""
|
"""Returns a mapping from employee ID to employee name for given IDs."""
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user