mirror of
https://github.com/google/styleguide.git
synced 2024-03-22 13:11:43 +08:00
Project import generated by Copybara.
PiperOrigin-RevId: 440926376
This commit is contained in:
parent
af78b49ac4
commit
d2ca0a820a
139
pyguide.md
139
pyguide.md
|
@ -213,8 +213,8 @@ that the arguments are actually unused.
|
||||||
|
|
||||||
Use `import` statements for packages and modules only, not for individual
|
Use `import` statements for packages and modules only, not for individual
|
||||||
classes or functions. Classes imported from the
|
classes or functions. Classes imported from the
|
||||||
[typing module](#typing-imports),
|
[`typing` module](#typing-imports), [`collections.abc` module](#typing-imports),
|
||||||
[typing_extensions module](https://github.com/python/typing/tree/master/typing_extensions),
|
[`typing_extensions` module](https://github.com/python/typing/tree/master/typing_extensions),
|
||||||
and redirects from the
|
and redirects from the
|
||||||
[six.moves module](https://six.readthedocs.io/#module-six.moves)
|
[six.moves module](https://six.readthedocs.io/#module-six.moves)
|
||||||
are exempt from this rule.
|
are exempt from this rule.
|
||||||
|
@ -254,8 +254,9 @@ Module names can still collide. Some module names are inconveniently long.
|
||||||
* Use `import x` for importing packages and modules.
|
* Use `import x` for importing packages and modules.
|
||||||
* Use `from x import y` where `x` is the package prefix and `y` is the module
|
* Use `from x import y` where `x` is the package prefix and `y` is the module
|
||||||
name with no prefix.
|
name with no prefix.
|
||||||
* Use `from x import y as z` if two modules named `y` are to be imported or if
|
* Use `from x import y as z` if two modules named `y` are to be imported, if
|
||||||
`y` is an inconveniently long name.
|
`y` conflicts with a top-level name defined in the current module, or if `y`
|
||||||
|
is an inconveniently long name.
|
||||||
* Use `import y as z` only when `z` is a standard abbreviation (e.g., `np` for
|
* Use `import y as z` only when `z` is a standard abbreviation (e.g., `np` for
|
||||||
`numpy`).
|
`numpy`).
|
||||||
|
|
||||||
|
@ -313,7 +314,7 @@ Yes:
|
||||||
import absl.flags
|
import absl.flags
|
||||||
from doctor.who import jodie
|
from doctor.who import jodie
|
||||||
|
|
||||||
FLAGS = absl.flags.FLAGS
|
_FOO = absl.flags.DEFINE_string(...)
|
||||||
```
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -322,7 +323,7 @@ Yes:
|
||||||
from absl import flags
|
from absl import flags
|
||||||
from doctor.who import jodie
|
from doctor.who import jodie
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
_FOO = flags.DEFINE_string(...)
|
||||||
```
|
```
|
||||||
|
|
||||||
*(assume this file lives in `doctor/who/` where `jodie.py` also exists)*
|
*(assume this file lives in `doctor/who/` where `jodie.py` also exists)*
|
||||||
|
@ -416,7 +417,7 @@ Exceptions must follow certain conditions:
|
||||||
# guarantee this specific behavioral reaction to API misuse.
|
# guarantee this specific behavioral reaction to API misuse.
|
||||||
raise ValueError(f'Min. port must be at least 1024, not {minimum}.')
|
raise ValueError(f'Min. port must be at least 1024, not {minimum}.')
|
||||||
port = self._find_next_open_port(minimum)
|
port = self._find_next_open_port(minimum)
|
||||||
if not port:
|
if port is None:
|
||||||
raise ConnectionError(
|
raise ConnectionError(
|
||||||
f'Could not connect to service on port {minimum} or higher.')
|
f'Could not connect to service on port {minimum} or higher.')
|
||||||
assert port >= minimum, (
|
assert port >= minimum, (
|
||||||
|
@ -509,13 +510,14 @@ assignments to global variables are done when the module is first imported.
|
||||||
|
|
||||||
Avoid global variables.
|
Avoid global variables.
|
||||||
|
|
||||||
While they are technically variables, module-level constants are permitted and
|
If needed, global variables should be declared at the module level and made
|
||||||
encouraged. For example: `_MAX_HOLY_HANDGRENADE_COUNT = 3`. Constants must be
|
internal to the module by prepending an `_` to the name. External access to
|
||||||
named using all caps with underscores. See [Naming](#s3.16-naming) below.
|
global variables must be done through public module-level functions. See
|
||||||
|
[Naming](#s3.16-naming) below.
|
||||||
|
|
||||||
If needed, globals should be declared at the module level and made internal to
|
While module-level constants are technically variables, they are permitted and
|
||||||
the module by prepending an `_` to the name. External access must be done
|
encouraged. For example: `MAX_HOLY_HANDGRENADE_COUNT = 3`. Constants must be
|
||||||
through public module-level functions. See [Naming](#s3.16-naming) below.
|
named using all caps with underscores. See [Naming](#s3.16-naming) below.
|
||||||
|
|
||||||
<a id="s2.6-nested"></a>
|
<a id="s2.6-nested"></a>
|
||||||
<a id="26-nested"></a>
|
<a id="26-nested"></a>
|
||||||
|
@ -955,11 +957,14 @@ Yes: def foo(a, b: Sequence = ()): # Empty tuple OK since tuples are immutable
|
||||||
```
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
from absl import flags
|
||||||
|
_FOO = flags.DEFINE_string(...)
|
||||||
|
|
||||||
No: def foo(a, b=[]):
|
No: def foo(a, b=[]):
|
||||||
...
|
...
|
||||||
No: def foo(a, b=time.time()): # The time the module was loaded???
|
No: def foo(a, b=time.time()): # The time the module was loaded???
|
||||||
...
|
...
|
||||||
No: def foo(a, b=FLAGS.my_thing): # sys.argv has not yet been parsed...
|
No: def foo(a, b=_FOO.value): # sys.argv has not yet been parsed...
|
||||||
...
|
...
|
||||||
No: def foo(a, b: Mapping = {}): # Could still get passed to unchecked code
|
No: def foo(a, b: Mapping = {}): # Could still get passed to unchecked code
|
||||||
...
|
...
|
||||||
|
@ -1471,7 +1476,7 @@ Type annotations (or "type hints") are for function or method arguments and
|
||||||
return values:
|
return values:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def func(a: int) -> List[int]:
|
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
|
||||||
|
@ -2026,7 +2031,7 @@ aptly described using a one-line docstring.
|
||||||
([example](http://numpy.org/doc/stable/reference/generated/numpy.linalg.qr.html)),
|
([example](http://numpy.org/doc/stable/reference/generated/numpy.linalg.qr.html)),
|
||||||
which frequently documents a tuple return value as if it were multiple
|
which frequently documents a tuple return value as if it were multiple
|
||||||
return values with individual names (never mentioning the tuple). Instead,
|
return values with individual names (never mentioning the tuple). Instead,
|
||||||
describe such a return value as: "Returns a tuple (mat_a, mat_b), where
|
describe such a return value as: "Returns: A tuple (mat_a, mat_b), where
|
||||||
mat_a is ..., and ...". The auxiliary names in the docstring need not
|
mat_a is ..., and ...". The auxiliary names in the docstring need not
|
||||||
necessarily correspond to any internal names used in the function body (as
|
necessarily correspond to any internal names used in the function body (as
|
||||||
those are not part of the API).
|
those are not part of the API).
|
||||||
|
@ -2044,7 +2049,7 @@ aptly described using a one-line docstring.
|
||||||
def fetch_smalltable_rows(table_handle: smalltable.Table,
|
def fetch_smalltable_rows(table_handle: smalltable.Table,
|
||||||
keys: Sequence[Union[bytes, str]],
|
keys: Sequence[Union[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.
|
||||||
|
|
||||||
Retrieves rows pertaining to the given keys from the Table instance
|
Retrieves rows pertaining to the given keys from the Table instance
|
||||||
|
@ -2081,7 +2086,7 @@ Similarly, this variation on `Args:` with a line break is also allowed:
|
||||||
def fetch_smalltable_rows(table_handle: smalltable.Table,
|
def fetch_smalltable_rows(table_handle: smalltable.Table,
|
||||||
keys: Sequence[Union[bytes, str]],
|
keys: Sequence[Union[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.
|
||||||
|
|
||||||
Retrieves rows pertaining to the given keys from the Table instance
|
Retrieves rows pertaining to the given keys from the Table instance
|
||||||
|
@ -2215,23 +2220,20 @@ punctuation, spelling, and grammar help with that goal.
|
||||||
Use an
|
Use an
|
||||||
[f-string](https://docs.python.org/3/reference/lexical_analysis.html#f-strings),
|
[f-string](https://docs.python.org/3/reference/lexical_analysis.html#f-strings),
|
||||||
the `%` operator, or the `format` method for formatting strings, even when the
|
the `%` operator, or the `format` method for formatting strings, even when the
|
||||||
parameters are all strings. Use your best judgment to decide between `+` and `%`
|
parameters are all strings. Use your best judgment to decide between `+` and
|
||||||
(or `format`) though. Do not use `%` or the `format` method for pure
|
string formatting.
|
||||||
concatenation.
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
Yes: x = a + b
|
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: {}; score: {}'.format(name, n)
|
x = 'name: {}; score: {}'.format(name, n)
|
||||||
x = f'name: {name}; score: {n}'
|
x = a + b
|
||||||
```
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
No: x = '%s%s' % (a, b) # use + in this case
|
No: x = first + ', ' + second
|
||||||
x = '{}{}'.format(a, b) # use + in this case
|
|
||||||
x = first + ', ' + second
|
|
||||||
x = 'name: ' + name + '; score: ' + str(n)
|
x = 'name: ' + name + '; score: ' + str(n)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -2524,7 +2526,7 @@ event ("Remove this code when all clients can handle XML responses.").
|
||||||
### 3.13 Imports formatting
|
### 3.13 Imports formatting
|
||||||
|
|
||||||
Imports should be on separate lines; there are
|
Imports should be on separate lines; there are
|
||||||
[exceptions for `typing` imports](#typing-imports).
|
[exceptions for `typing` and `collections.abc` imports](#typing-imports).
|
||||||
|
|
||||||
E.g.:
|
E.g.:
|
||||||
|
|
||||||
|
@ -2692,7 +2694,8 @@ change in complexity.
|
||||||
|
|
||||||
`module_name`, `package_name`, `ClassName`, `method_name`, `ExceptionName`,
|
`module_name`, `package_name`, `ClassName`, `method_name`, `ExceptionName`,
|
||||||
`function_name`, `GLOBAL_CONSTANT_NAME`, `global_var_name`, `instance_var_name`,
|
`function_name`, `GLOBAL_CONSTANT_NAME`, `global_var_name`, `instance_var_name`,
|
||||||
`function_parameter_name`, `local_var_name`.
|
`function_parameter_name`, `local_var_name`, `query_proper_noun_for_thing`,
|
||||||
|
`send_acronym_via_https`.
|
||||||
|
|
||||||
|
|
||||||
Function names, variable names, and filenames should be descriptive; eschew
|
Function names, variable names, and filenames should be descriptive; eschew
|
||||||
|
@ -2713,6 +2716,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`,
|
||||||
|
`_U`, `_V`)
|
||||||
|
|
||||||
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.
|
||||||
|
@ -2949,6 +2954,8 @@ the function into smaller and more manageable pieces.
|
||||||
* 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., `@classmethod def create(cls: Type[T]) -> T: return
|
type information. e.g., `@classmethod def create(cls: Type[T]) -> T: return
|
||||||
cls()`
|
cls()`
|
||||||
|
* Similarly, don't feel compelled to annotate the return value of `__init__`
|
||||||
|
(where `None` is the only valid option).
|
||||||
* If any other variable or a returned type should not be expressed, use `Any`.
|
* If any other variable or a returned type should not be expressed, use `Any`.
|
||||||
* You are not required to annotate all the functions in a module.
|
* You are not required to annotate all the functions in a module.
|
||||||
- At least annotate your public APIs.
|
- At least annotate your public APIs.
|
||||||
|
@ -2993,7 +3000,7 @@ is too long, indent by 4 in a new line.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def my_method(
|
def my_method(
|
||||||
self, first_var: int) -> Tuple[MyLongType1, MyLongType1]:
|
self, first_var: int) -> tuple[MyLongType1, MyLongType1]:
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -3005,7 +3012,7 @@ closing parenthesis with the `def`.
|
||||||
Yes:
|
Yes:
|
||||||
def my_method(
|
def my_method(
|
||||||
self, other_arg: Optional[MyLongType]
|
self, other_arg: Optional[MyLongType]
|
||||||
) -> Dict[OtherLongType, MyLongType]:
|
) -> dict[OtherLongType, MyLongType]:
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -3017,7 +3024,7 @@ opening one, but this is less readable.
|
||||||
No:
|
No:
|
||||||
def my_method(self,
|
def my_method(self,
|
||||||
other_arg: Optional[MyLongType]
|
other_arg: Optional[MyLongType]
|
||||||
) -> Dict[OtherLongType, MyLongType]:
|
) -> dict[OtherLongType, MyLongType]:
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -3027,9 +3034,9 @@ too long to be on a single line (try to keep sub-types unbroken).
|
||||||
```python
|
```python
|
||||||
def my_method(
|
def my_method(
|
||||||
self,
|
self,
|
||||||
first_var: Tuple[List[MyLongType1],
|
first_var: tuple[list[MyLongType1],
|
||||||
List[MyLongType2]],
|
list[MyLongType2]],
|
||||||
second_var: List[Dict[
|
second_var: list[dict[
|
||||||
MyLongType3, MyLongType4]]) -> None:
|
MyLongType3, MyLongType4]]) -> None:
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
@ -3146,7 +3153,7 @@ long:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
_ShortName = module_with_long_name.TypeWithLongName
|
_ShortName = module_with_long_name.TypeWithLongName
|
||||||
ComplexMap = Mapping[str, List[Tuple[int, int]]]
|
ComplexMap = Mapping[str, list[tuple[int, int]]]
|
||||||
```
|
```
|
||||||
|
|
||||||
Other examples are complex nested types and multiple return variables from a
|
Other examples are complex nested types and multiple return variables from a
|
||||||
|
@ -3207,9 +3214,9 @@ have a single repeated type or a set number of elements with different types.
|
||||||
The latter is commonly used as the return type from a function.
|
The latter is commonly used as the return type from a function.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
a = [1, 2, 3] # type: List[int]
|
a = [1, 2, 3] # type: list[int]
|
||||||
b = (1, 2, 3) # type: Tuple[int, ...]
|
b = (1, 2, 3) # type: tuple[int, ...]
|
||||||
c = (1, "2", 3.5) # type: Tuple[int, str, float]
|
c = (1, "2", 3.5) # type: tuple[int, str, float]
|
||||||
```
|
```
|
||||||
|
|
||||||
<a id="s3.19.10-typevars"></a>
|
<a id="s3.19.10-typevars"></a>
|
||||||
|
@ -3227,10 +3234,10 @@ function `TypeVar` is a common way to use them.
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from typing import List, TypeVar
|
from typing import TypeVar
|
||||||
T = TypeVar("T")
|
_T = TypeVar("_T")
|
||||||
...
|
...
|
||||||
def next(l: List[T]) -> T:
|
def next(l: list[_T]) -> _T:
|
||||||
return l.pop()
|
return l.pop()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -3254,6 +3261,26 @@ def check_length(x: AnyStr) -> AnyStr:
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
A TypeVar must have a descriptive name, unless it meets all of the following
|
||||||
|
criteria:
|
||||||
|
|
||||||
|
* not externally visible
|
||||||
|
* not constrained
|
||||||
|
|
||||||
|
```python
|
||||||
|
Yes:
|
||||||
|
_T = TypeVar("_T")
|
||||||
|
AddableType = TypeVar("AddableType", int, float, str)
|
||||||
|
AnyFunction = TypeVar("AnyFunction", bound=Callable)
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
No:
|
||||||
|
T = TypeVar("T")
|
||||||
|
_T = TypeVar("_T", int, float, str)
|
||||||
|
_F = TypeVar("_F", bound=Callable)
|
||||||
|
```
|
||||||
|
|
||||||
<a id="s3.19.11-string-types"></a>
|
<a id="s3.19.11-string-types"></a>
|
||||||
<a id="s3.19.11-strings"></a>
|
<a id="s3.19.11-strings"></a>
|
||||||
<a id="31911-string-types"></a>
|
<a id="31911-string-types"></a>
|
||||||
|
@ -3314,19 +3341,21 @@ return type is the same as the argument type in the code above, use
|
||||||
<a id="typing-imports"></a>
|
<a id="typing-imports"></a>
|
||||||
#### 3.19.12 Imports For Typing
|
#### 3.19.12 Imports For Typing
|
||||||
|
|
||||||
For classes from the `typing` module, always import the class itself. You are
|
For classes from the `typing` and `collections.abc` modules for use in
|
||||||
explicitly allowed to import multiple specific classes on one line from the
|
annotations, always import the class itself. This keeps common annotations more
|
||||||
`typing` module. Ex:
|
concise and matches typing practices used around the world. You are explicitly
|
||||||
|
allowed to import multiple specific classes on one line from the `typing` and
|
||||||
|
`collections.abc` modules. Ex:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from typing import Any, Dict, Optional
|
from collections.abc import Mapping, Sequence
|
||||||
|
from typing import Any, Union
|
||||||
```
|
```
|
||||||
|
|
||||||
Given that this way of importing from `typing` adds items to the local
|
Given that this way of importing adds items to the local namespace, names in
|
||||||
namespace, any names in `typing` should be treated similarly to keywords, and
|
`typing` or `collections.abc` should be treated similarly to keywords, and not
|
||||||
not be defined in your Python code, typed or not. If there is a collision
|
be defined in your Python code, typed or not. If there is a collision between a
|
||||||
between a type and an existing name in a module, import it using `import x as
|
type and an existing name in a module, import it using `import x as y`.
|
||||||
y`.
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from typing import Any as AnyType
|
from typing import Any as AnyType
|
||||||
|
@ -3400,12 +3429,12 @@ 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://www.python.org/dev/peps/pep-0484/#the-any-type).
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_names(employee_ids: List[int]) -> Dict[int, Any]:
|
def get_names(employee_ids: list[int]) -> dict[int, Any]:
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# These are both interpreted as get_names(employee_ids: List[Any]) -> Dict[Any, Any]
|
# These are both interpreted as get_names(employee_ids: list[Any]) -> dict[Any, Any]
|
||||||
def get_names(employee_ids: list) -> Dict:
|
def get_names(employee_ids: list) -> Dict:
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@ -3418,13 +3447,13 @@ remember that in many cases [`TypeVar`](#typing-type-var) might be more
|
||||||
appropriate:
|
appropriate:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_names(employee_ids: List[Any]) -> Dict[Any, str]:
|
def get_names(employee_ids: list[Any]) -> dict[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
|
||||||
T = TypeVar('T')
|
_T = TypeVar('_T')
|
||||||
def get_names(employee_ids: List[T]) -> Dict[T, str]:
|
def get_names(employee_ids: list[_T]) -> dict[_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