mirror of
https://github.com/google/styleguide.git
synced 2024-03-22 13:11:43 +08:00
Project import generated by Copybara.
PiperOrigin-RevId: 347693939
This commit is contained in:
parent
2e797961e9
commit
5120fd6b14
271
pyguide.md
271
pyguide.md
|
@ -83,9 +83,6 @@ See README.md for details.
|
|||
+ [2.14.2 Pros](#s2.14.2-pros)
|
||||
+ [2.14.3 Cons](#s2.14.3-cons)
|
||||
+ [2.14.4 Decision](#s2.14.4-decision)
|
||||
* [2.15 Deprecated Language Features](#s2.15-deprecated-language-features)
|
||||
+ [2.15.1 Definition](#s2.15.1-definition)
|
||||
+ [2.15.2 Decision](#s2.15.2-decision)
|
||||
* [2.16 Lexical Scoping](#s2.16-lexical-scoping)
|
||||
+ [2.16.1 Definition](#s2.16.1-definition)
|
||||
+ [2.16.2 Pros](#s2.16.2-pros)
|
||||
|
@ -128,8 +125,9 @@ See README.md for details.
|
|||
+ [3.8.4 Classes](#s3.8.4-comments-in-classes)
|
||||
+ [3.8.5 Block and Inline Comments](#s3.8.5-block-and-inline-comments)
|
||||
+ [3.8.6 Punctuation, Spelling, and Grammar](#s3.8.6-punctuation-spelling-and-grammar)
|
||||
* [3.9 Classes](#s3.9-classes)
|
||||
* [3.10 Strings](#s3.10-strings)
|
||||
+ [3.10.1 Logging](#s3.10.1-logging)
|
||||
+ [3.10.2 Error Messages](#s3.10.2-error-messages)
|
||||
* [3.11 Files and Sockets](#s3.11-files-and-sockets)
|
||||
* [3.12 TODO Comments](#s3.12-todo-comments)
|
||||
* [3.13 Imports formatting](#s3.13-imports-formatting)
|
||||
|
@ -220,8 +218,8 @@ Catches easy-to-miss errors like typos, using-vars-before-assignment, etc.
|
|||
#### 2.1.3 Cons
|
||||
|
||||
`pylint`
|
||||
isn't perfect. To take advantage of it, we'll need to sometimes: a) Write around
|
||||
it b) Suppress its warnings or c) Improve it.
|
||||
isn't perfect. To take advantage of it, sometimes we'll need to write around it,
|
||||
suppress its warnings or fix it.
|
||||
|
||||
<a id="s2.1.4-decision"></a>
|
||||
<a id="214-decision"></a>
|
||||
|
@ -432,8 +430,8 @@ Exceptions are allowed but must be used carefully.
|
|||
<a id="exceptions-definition"></a>
|
||||
#### 2.4.1 Definition
|
||||
|
||||
Exceptions are a means of breaking out of the normal flow of control of a code
|
||||
block to handle errors or other exceptional conditions.
|
||||
Exceptions are a means of breaking out of normal control flow to handle errors
|
||||
or other exceptional conditions.
|
||||
|
||||
<a id="s2.4.2-pros"></a>
|
||||
<a id="242-pros"></a>
|
||||
|
@ -444,7 +442,7 @@ block to handle errors or other exceptional conditions.
|
|||
The control flow of normal operation code is not cluttered by error-handling
|
||||
code. It also allows the control flow to skip multiple frames when a certain
|
||||
condition occurs, e.g., returning from N nested functions in one step instead of
|
||||
having to carry-through error codes.
|
||||
having to plumb error codes through.
|
||||
|
||||
<a id="s2.4.3-cons"></a>
|
||||
<a id="243-cons"></a>
|
||||
|
@ -629,9 +627,8 @@ Commonly used for implementing decorators.
|
|||
<a id="nested-classes-functions-cons"></a>
|
||||
#### 2.6.3 Cons
|
||||
|
||||
Instances of nested or local classes cannot be pickled. Nested functions and
|
||||
classes cannot be directly tested. Nesting can make your outer function longer
|
||||
and less readable.
|
||||
Nested functions and classes cannot be directly tested. Nesting can make the
|
||||
outer function longer and less readable.
|
||||
|
||||
<a id="s2.6.4-decision"></a>
|
||||
<a id="264-decision"></a>
|
||||
|
@ -789,8 +786,7 @@ means a dictionary). This is also an advantage.
|
|||
Use default iterators and operators for types that support them, like lists,
|
||||
dictionaries, and files. The built-in types define iterator methods, too. Prefer
|
||||
these methods to methods that return lists, except that you should not mutate a
|
||||
container while iterating over it. Never use Python 2 specific iteration methods
|
||||
such as `dict.iter*()` unless necessary.
|
||||
container while iterating over it.
|
||||
|
||||
```python
|
||||
Yes: for key in adict: ...
|
||||
|
@ -859,7 +855,8 @@ functions.
|
|||
<a id="lambdas"></a>
|
||||
### 2.10 Lambda Functions
|
||||
|
||||
Okay for one-liners.
|
||||
Okay for one-liners. Prefer generator expressions over `map()` or `filter()`
|
||||
with a `lambda`.
|
||||
|
||||
<a id="s2.10.1-definition"></a>
|
||||
<a id="2101-definition"></a>
|
||||
|
@ -868,8 +865,6 @@ Okay for one-liners.
|
|||
#### 2.10.1 Definition
|
||||
|
||||
Lambdas define anonymous functions in an expression, as opposed to a statement.
|
||||
They are often used to define callbacks or operators for higher-order functions
|
||||
like `map()` and `filter()`.
|
||||
|
||||
<a id="s2.10.2-pros"></a>
|
||||
<a id="2102-pros"></a>
|
||||
|
@ -949,19 +944,21 @@ true-expression, if-expression, else-expression. Use a complete if statement
|
|||
when things get more complicated.
|
||||
|
||||
```python
|
||||
one_line = 'yes' if predicate(value) else 'no'
|
||||
slightly_split = ('yes' if predicate(value)
|
||||
Yes:
|
||||
one_line = 'yes' if predicate(value) else 'no'
|
||||
slightly_split = ('yes' if predicate(value)
|
||||
else 'no, nein, nyet')
|
||||
the_longest_ternary_style_that_can_be_done = (
|
||||
the_longest_ternary_style_that_can_be_done = (
|
||||
'yes, true, affirmative, confirmed, correct'
|
||||
if predicate(value)
|
||||
else 'no, false, negative, nay')
|
||||
```
|
||||
|
||||
```python
|
||||
bad_line_breaking = ('yes' if predicate(value) else
|
||||
No:
|
||||
bad_line_breaking = ('yes' if predicate(value) else
|
||||
'no')
|
||||
portion_too_long = ('yes'
|
||||
portion_too_long = ('yes'
|
||||
if some_long_module.some_long_predicate_function(
|
||||
really_long_variable_name)
|
||||
else 'no, false, negative, nay')
|
||||
|
@ -1079,8 +1076,8 @@ future without breaking the interface.
|
|||
<a id="properties-cons"></a>
|
||||
#### 2.13.3 Cons
|
||||
|
||||
Must inherit from `object` in Python 2. Can hide side-effects much like operator
|
||||
overloading. Can be confusing for subclasses.
|
||||
Can hide side-effects much like operator overloading. Can be confusing for
|
||||
subclasses.
|
||||
|
||||
<a id="s2.13.4-decision"></a>
|
||||
<a id="2134-decision"></a>
|
||||
|
@ -1089,8 +1086,8 @@ overloading. Can be confusing for subclasses.
|
|||
#### 2.13.4 Decision
|
||||
|
||||
Use properties in new code to access or set data where you would normally have
|
||||
used simple, lightweight accessor or setter methods. Properties should be
|
||||
created with the `@property` [decorator](#s2.17-function-and-method-decorators).
|
||||
used lightweight accessor or setter methods. Properties should be created with
|
||||
the `@property` [decorator](#s2.17-function-and-method-decorators).
|
||||
|
||||
Inheritance with properties can be non-obvious if the property itself is not
|
||||
overridden. Thus one must make sure that accessor methods are called indirectly
|
||||
|
@ -1234,53 +1231,6 @@ Use the "implicit" false if possible, e.g., `if foo:` rather than `if foo !=
|
|||
|
||||
- Note that `'0'` (i.e., `0` as string) evaluates to true.
|
||||
|
||||
<a id="s2.15-deprecated-language-features"></a>
|
||||
<a id="215-deprecated-language-features"></a>
|
||||
|
||||
<a id="deprecated-features"></a>
|
||||
### 2.15 Deprecated Language Features
|
||||
|
||||
Use string methods instead of the `string` module where possible. Use function
|
||||
call syntax instead of `apply`. Use list comprehensions and `for` loops instead
|
||||
of `filter` and `map` when the function argument would have been an inlined
|
||||
lambda anyway. Use `for` loops instead of `reduce`.
|
||||
|
||||
<a id="s2.15.1-definition"></a>
|
||||
<a id="2151-definition"></a>
|
||||
|
||||
<a id="deprecated-features-definition"></a>
|
||||
#### 2.15.1 Definition
|
||||
|
||||
Current versions of Python provide alternative constructs that people find
|
||||
generally preferable.
|
||||
|
||||
<a id="s2.15.2-decision"></a>
|
||||
<a id="2152-decision"></a>
|
||||
|
||||
<a id="deprecated-features-decision"></a>
|
||||
#### 2.15.2 Decision
|
||||
|
||||
We do not use any Python version which does not support these features, so there
|
||||
is no reason not to use the new styles.
|
||||
|
||||
```python
|
||||
Yes: words = foo.split(':')
|
||||
|
||||
[x[1] for x in my_list if x[2] == 5]
|
||||
|
||||
map(math.sqrt, data) # Ok. No inlined lambda expression.
|
||||
|
||||
fn(*args, **kwargs)
|
||||
```
|
||||
|
||||
```python
|
||||
No: words = string.split(foo, ':')
|
||||
|
||||
map(lambda x: x[1], filter(lambda x: x[2] == 5, my_list))
|
||||
|
||||
apply(fn, args, kwargs)
|
||||
```
|
||||
|
||||
<a id="s2.16-lexical-scoping"></a>
|
||||
<a id="216-lexical-scoping"></a>
|
||||
|
||||
|
@ -1506,8 +1456,7 @@ longer but is straightforward.
|
|||
Avoid these features in your code.
|
||||
|
||||
Standard library modules and classes that internally use these features are okay
|
||||
to use (for example, `abc.ABCMeta`, `collections.namedtuple`, `dataclasses`, and
|
||||
`enum`).
|
||||
to use (for example, `abc.ABCMeta`, `dataclasses`, and `enum`).
|
||||
|
||||
<a id="s2.20-modern-python"></a>
|
||||
<a id="220-modern-python"></a>
|
||||
|
@ -2039,10 +1988,10 @@ No:
|
|||
|
||||
Most `.py` files do not need to start with a `#!` line. Start the main file of a
|
||||
program with
|
||||
`#!/usr/bin/python` with an optional single digit `2` or `3` suffix per
|
||||
[PEP-394](https://www.google.com/url?sa=D&q=http://www.python.org/dev/peps/pep-0394/).
|
||||
`#!/usr/bin/env python3` (to support virtualenvs) or `#!/usr/bin/python3` per
|
||||
[PEP-394](https://www.python.org/dev/peps/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 that will 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.
|
||||
|
||||
<a id="s3.8-comments-and-docstrings"></a>
|
||||
<a id="s3.8-comments"></a>
|
||||
|
@ -2337,48 +2286,18 @@ using a comma when you should be using a semicolon, it is very important that
|
|||
source code maintain a high level of clarity and readability. Proper
|
||||
punctuation, spelling, and grammar help with that goal.
|
||||
|
||||
<a id="s3.9-classes"></a>
|
||||
<a id="39-classes"></a>
|
||||
|
||||
<a id="classes"></a>
|
||||
### 3.9 Classes
|
||||
|
||||
Classes need not explicitly inherit from `object` (unless for compatibility with
|
||||
Python 2).
|
||||
|
||||
```python
|
||||
Modern:
|
||||
class SampleClass:
|
||||
pass
|
||||
|
||||
|
||||
class OuterClass:
|
||||
|
||||
class InnerClass:
|
||||
pass
|
||||
```
|
||||
|
||||
```python
|
||||
Ancient:
|
||||
class SampleClass(object):
|
||||
pass
|
||||
|
||||
|
||||
class OuterClass(object):
|
||||
|
||||
class InnerClass(object):
|
||||
pass
|
||||
```
|
||||
|
||||
<a id="s3.10-strings"></a>
|
||||
<a id="310-strings"></a>
|
||||
|
||||
<a id="strings"></a>
|
||||
### 3.10 Strings
|
||||
|
||||
Use the `format` method or the `%` operator for formatting strings, even when
|
||||
the parameters are all strings. Use your best judgment to decide between `+` and
|
||||
`%` (or `format`) though.
|
||||
Use an
|
||||
[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
|
||||
parameters are all strings. Use your best judgment to decide between `+` and `%`
|
||||
(or `format`) though. Do not use `%` or the `format` method for pure
|
||||
concatenation.
|
||||
|
||||
```python
|
||||
Yes: x = a + b
|
||||
|
@ -2386,7 +2305,7 @@ Yes: x = a + b
|
|||
x = '{}, {}'.format(first, second)
|
||||
x = 'name: %s; score: %d' % (name, n)
|
||||
x = 'name: {}; score: {}'.format(name, n)
|
||||
x = f'name: {name}; score: {n}' # Python 3.6+
|
||||
x = f'name: {name}; score: {n}'
|
||||
```
|
||||
|
||||
```python
|
||||
|
@ -2396,11 +2315,14 @@ No: x = '%s%s' % (a, b) # use + in this case
|
|||
x = 'name: ' + name + '; score: ' + str(n)
|
||||
```
|
||||
|
||||
Avoid using the `+` and `+=` operators to accumulate a string within a loop.
|
||||
Since strings are immutable, this creates unnecessary temporary objects and
|
||||
results in quadratic rather than linear running time. Instead, add each
|
||||
substring to a list and `''.join` the list after the loop terminates (or, write
|
||||
each substring to an `io.BytesIO` buffer).
|
||||
Avoid using the `+` and `+=` operators to accumulate a string within a loop. In
|
||||
some conditions, accumulating a string with addition can lead to quadratic
|
||||
rather than linear running time. Although common accumulations of this sort may
|
||||
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,
|
||||
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
|
||||
consistently have amortized-linear run time complexity.
|
||||
|
||||
```python
|
||||
Yes: items = ['<table>']
|
||||
|
@ -2479,6 +2401,104 @@ Don't do this.
|
|||
will collapse common leading spaces in each line.""")
|
||||
```
|
||||
|
||||
<a id="s3.10.1-logging"></a>
|
||||
<a id="3101-logging"></a>
|
||||
<a id="logging"></a>
|
||||
|
||||
<a id="logging"></a>
|
||||
#### 3.10.1 Logging
|
||||
|
||||
For logging functions that expect a pattern-string (with %-placeholders) as
|
||||
their first argument: Always call them with a string literal (not an f-string!)
|
||||
as their first argument with pattern-parameters as subsequent arguments. Some
|
||||
logging implementations collect the unexpanded pattern-string as a queryable
|
||||
field. It also prevents spending time rendering a message that no logger is
|
||||
configured to output.
|
||||
|
||||
```python
|
||||
Yes:
|
||||
import tensorflow as tf
|
||||
logger = tf.get_logger()
|
||||
logger.info('TensorFlow Version is: %s', tf.__version__)
|
||||
```
|
||||
|
||||
```python
|
||||
Yes:
|
||||
import os
|
||||
from absl import logging
|
||||
|
||||
logging.info('Current $PAGER is: %s', os.getenv('PAGER', default=''))
|
||||
|
||||
homedir = os.getenv('HOME')
|
||||
if homedir is None or not os.access(homedir, os.W_OK):
|
||||
logging.error('Cannot write to home directory, $HOME=%r', homedir)
|
||||
```
|
||||
|
||||
```python
|
||||
No:
|
||||
import os
|
||||
from absl import logging
|
||||
|
||||
logging.info('Current $PAGER is:')
|
||||
logging.info(os.getenv('PAGER', default=''))
|
||||
|
||||
homedir = os.getenv('HOME')
|
||||
if homedir is None or not os.access(homedir, os.W_OK):
|
||||
logging.error(f'Cannot write to home directory, $HOME={homedir!r}')
|
||||
```
|
||||
|
||||
<a id="s3.10.2-error-messages"></a>
|
||||
<a id="3102-error-messages"></a>
|
||||
<a id="error-messages"></a>
|
||||
|
||||
<a id="error-messages"></a>
|
||||
#### 3.10.2 Error Messages
|
||||
|
||||
Error messages (such as: message strings on exceptions like `ValueError`, or
|
||||
messages shown to the user) should follow three guidelines:
|
||||
|
||||
1. The message needs to precisely match the actual error condition.
|
||||
|
||||
2. Interpolated pieces need to always be clearly identifiable as such.
|
||||
|
||||
3. They should allow simple automated processing (e.g. grepping).
|
||||
|
||||
```python
|
||||
Yes:
|
||||
if not 0 <= p <= 1:
|
||||
raise ValueError(f'Not a probability: {p!r}')
|
||||
|
||||
try:
|
||||
os.rmdir(workdir)
|
||||
except OSError as error:
|
||||
logging.warning('Could not remove directory (reason: %r): %r',
|
||||
error, workdir)
|
||||
```
|
||||
|
||||
```python
|
||||
No:
|
||||
if p < 0 or p > 1: # PROBLEM: also false for float('nan')!
|
||||
raise ValueError(f'Not a probability: {p!r}')
|
||||
|
||||
try:
|
||||
os.rmdir(workdir)
|
||||
except OSError:
|
||||
# PROBLEM: Message makes an assumption that might not be true:
|
||||
# Deletion might have failed for some other reason, misleading
|
||||
# whoever has to debug this.
|
||||
logging.warning('Directory already was deleted: %s', workdir)
|
||||
|
||||
try:
|
||||
os.rmdir(workdir)
|
||||
except OSError:
|
||||
# PROBLEM: The message is harder to grep for than necessary, and
|
||||
# not universally non-confusing for all possible values of `workdir`.
|
||||
# Imagine someone calling a library function with such code
|
||||
# using a name such as workdir = 'deleted'. The warning would read:
|
||||
# "The deleted directory could not be deleted."
|
||||
logging.warning('The %s directory could not be deleted.', workdir)
|
||||
```
|
||||
|
||||
<a id="s3.11-files-and-sockets"></a>
|
||||
<a id="311-files-and-sockets"></a>
|
||||
<a id="files-and-sockets"></a>
|
||||
|
@ -2758,6 +2778,9 @@ Always use a `.py` filename extension. Never use dashes.
|
|||
|
||||
- offensive terms
|
||||
|
||||
- names that needlessly include the type of the variable (for example:
|
||||
`id_to_name_dict`)
|
||||
|
||||
<a id="s3.16.2-naming-conventions"></a>
|
||||
<a id="3162-naming-convention"></a>
|
||||
|
||||
|
@ -2771,8 +2794,8 @@ Always use a `.py` filename extension. Never use dashes.
|
|||
variables and functions (linters will flag protected member access). While
|
||||
prepending a double underscore (`__` aka "dunder") to an instance variable
|
||||
or method effectively makes the variable or method private to its class
|
||||
(using name mangling) we discourage its use as it impacts readability and
|
||||
testability and isn't *really* private.
|
||||
(using name mangling); we discourage its use as it impacts readability and
|
||||
testability, and isn't *really* private.
|
||||
|
||||
- Place related classes and top-level functions together in a
|
||||
module.
|
||||
|
@ -3399,8 +3422,8 @@ def f(x: "sketch.Sketch"): ...
|
|||
|
||||
Circular dependencies that are caused by typing are code smells. Such code is a
|
||||
good candidate for refactoring. Although technically it is possible to keep
|
||||
circular dependencies, the [build system](#typing-build-deps) will not let you
|
||||
do so because each module has to depend on the other.
|
||||
circular dependencies, various build systems will not let you do so
|
||||
because each module has to depend on the other.
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue
Block a user