diff --git a/pyguide.md b/pyguide.md
index f1fe105..02cbbe2 100644
--- a/pyguide.md
+++ b/pyguide.md
@@ -272,7 +272,7 @@ package twice.
Exemptions from this rule:
-* Symbols from the following modules and used to support static analysis and
+* Symbols from the following modules are used to support static analysis and
type checking:
* [`typing` module](#typing-imports)
* [`collections.abc` module](#typing-imports)
@@ -524,7 +524,7 @@ global variables must be done through public module-level functions. See
[Naming](#s3.16-naming) below.
While module-level constants are technically variables, they are permitted and
-encouraged. For example: `MAX_HOLY_HANDGRENADE_COUNT = 3`. Constants must be
+encouraged. For example: `_MAX_HOLY_HANDGRENADE_COUNT = 3`. Constants must be
named using all caps with underscores. See [Naming](#s3.16-naming) below.
@@ -710,8 +710,8 @@ operators is generic. It can be used with any type that supports the operation.
#### 2.8.3 Cons
-You can't tell the type of objects by reading the method names (e.g. `has_key()`
-means a dictionary). This is also an advantage.
+You can't tell the type of objects by reading the method names (unless the
+variable has type annotations). This is also an advantage.
@@ -726,7 +726,6 @@ container while iterating over it.
```python
Yes: for key in adict: ...
- if key not in adict: ...
if obj in alist: ...
for line in afile: ...
for k, v in adict.items(): ...
@@ -734,7 +733,6 @@ Yes: for key in adict: ...
```python
No: for key in adict.keys(): ...
- if not adict.has_key(key): ...
for line in afile.readlines(): ...
```
@@ -964,7 +962,7 @@ Yes: def foo(a, b=None):
Yes: def foo(a, b: Optional[Sequence] = None):
if b is None:
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.
...
```
@@ -978,7 +976,7 @@ No: def foo(a, b=time.time()): # The time the module was loaded???
...
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.
...
```
@@ -1294,7 +1292,7 @@ more discussion.
Never use `staticmethod` unless forced to in order to integrate with an API
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.
@@ -1659,27 +1657,27 @@ No: if (x):
Indent your code blocks with *4 spaces*.
-Never use tabs or mix tabs and spaces. In cases of implied line continuation,
-you should align wrapped elements either vertically, as per the examples in the
-[line length](#s3.2-line-length) section; or using a hanging indent of 4 spaces,
-in which case there should be nothing after the open parenthesis or bracket on
-the first line.
+Never use tabs. Implied line continuation should align wrapped elements
+vertically (see [line length examples](#s3.2-line-length)), or use a hanging
+4-space indent. Closing (round, square or curly) brackets can be placed at the
+end of the expression, or on separate lines, but then should be indented the
+same as the line with the corresponding opening bracket.
```python
-Yes: # Aligned with opening delimiter
+Yes: # Aligned with opening delimiter.
foo = long_function_name(var_one, var_two,
var_three, var_four)
meal = (spam,
beans)
- # Aligned with opening delimiter in a dictionary
+ # Aligned with opening delimiter in a dictionary.
foo = {
'long_dictionary_key': value1 +
value2,
...
}
- # 4-space hanging indent; nothing on first line
+ # 4-space hanging indent; nothing on first line.
foo = long_function_name(
var_one, var_two, var_three,
var_four)
@@ -1687,7 +1685,18 @@ Yes: # Aligned with opening delimiter
spam,
beans)
- # 4-space hanging indent in a dictionary
+ # 4-space hanging indent; nothing on first line,
+ # closing parenthesis on a new line.
+ foo = long_function_name(
+ var_one, var_two, var_three,
+ var_four
+ )
+ meal = (
+ spam,
+ beans,
+ )
+
+ # 4-space hanging indent in a dictionary.
foo = {
'long_dictionary_key':
long_dictionary_value,
@@ -1696,18 +1705,18 @@ Yes: # Aligned with opening delimiter
```
```python
-No: # Stuff on first line forbidden
+No: # Stuff on first line forbidden.
foo = long_function_name(var_one, var_two,
var_three, var_four)
meal = (spam,
beans)
- # 2-space hanging indent forbidden
+ # 2-space hanging indent forbidden.
foo = long_function_name(
var_one, var_two, var_three,
var_four)
- # No hanging indent in a dictionary
+ # No hanging indent in a dictionary.
foo = {
'long_dictionary_key':
long_dictionary_value,
@@ -1939,7 +1948,7 @@ overall description of the module or program. Optionally, it may also
contain a brief description of exported classes and functions and/or usage
examples.
- Typical usage example:
+Typical usage example:
foo = ClassFoo()
bar = foo.FunctionBar()
@@ -2512,25 +2521,27 @@ documentation must explain clearly how resource lifetime is managed.
Use `TODO` comments for code that is temporary, a short-term solution, or
good-enough but not perfect.
-A `TODO` comment begins with the string `TODO` in all caps and a parenthesized
-name, e-mail address, or other identifier
-of the person or issue with the best context about the problem. This is followed
-by an explanation of what there is to do.
+A `TODO` comment begins with the word `TODO` in all caps, and a parenthesized
+context identifier. Ideally a bug reference, sometimes a username. A bug
+reference like `TODO(https://crbug.com/bug_id_number):` is
+preferable, because bugs are tracked and have follow-up comments, whereas
+individuals move around and may lose context over time. The `TODO` is followed by an explanation of
+what there is to do.
The purpose is to have a consistent `TODO` format that can be searched to find
out how to get more details. A `TODO` is not a commitment that the person
-referenced will fix the problem. Thus when you create a
-`TODO`, it is almost always your name
-that is given.
+referenced will fix the problem. Thus when you create a `TODO` with a username,
+it is almost always your *own* username that is given.
```python
-# TODO(kl@gmail.com): Use a "*" here for string repetition.
-# TODO(Zeke) Change this to use relations.
+# TODO(crbug.com/192795): Investigate cpufreq optimizations.
+# TODO(yourusername): File an issue and use a '*' for repetition.
```
If your `TODO` is of the form "At a future date do something" make sure that you
either include a very specific date ("Fix by November 2009") or a very specific
-event ("Remove this code when all clients can handle XML responses.").
+event ("Remove this code when all clients can handle XML responses.") that
+future code maintainers will comprehend.
@@ -2710,7 +2721,7 @@ change in complexity.
`send_acronym_via_https`.
-Function names, variable names, and filenames should be descriptive; eschew
+Function names, variable names, and filenames should be descriptive; avoid
abbreviation. In particular, do not use abbreviations that are ambiguous or
unfamiliar to readers outside your project, and do not abbreviate by deleting
letters within a word.
@@ -2969,7 +2980,7 @@ the function into smaller and more manageable pieces.
```python
@classmethod
- def create(cls: Type[T]) -> T:
+ def create(cls: Type[_T]) -> _T:
return cls()
```
@@ -2999,12 +3010,16 @@ the function into smaller and more manageable pieces.
Try to follow the existing [indentation](#indentation) rules.
After annotating, many function signatures will become "one parameter per line".
+To ensure the return type is also given its own line, a comma can be placed
+after the last parameter.
```python
-def my_method(self,
- first_var: int,
- second_var: Foo,
- third_var: Optional[Bar]) -> int:
+def my_method(
+ self,
+ first_var: int,
+ second_var: Foo,
+ third_var: Optional[Bar],
+) -> int:
...
```
@@ -3018,23 +3033,27 @@ def my_method(self, first_var: int) -> int:
```
If the combination of the function name, the last parameter, and the return type
-is too long, indent by 4 in a new line.
-
-```python
-def my_method(
- self, first_var: int) -> tuple[MyLongType1, MyLongType1]:
- ...
-```
-
-When the return type does not fit on the same line as the last parameter, the
-preferred way is to indent the parameters by 4 on a new line and align the
-closing parenthesis with the `def`.
+is too long, indent by 4 in a new line. When using line breaks, prefer putting
+each parameter and the return type on their own lines and aligning the closing
+parenthesis with the `def`:
```python
Yes:
def my_method(
- self, other_arg: Optional[MyLongType]
-) -> dict[OtherLongType, MyLongType]:
+ self,
+ other_arg: Optional[MyLongType],
+) -> tuple[MyLongType1, MyLongType1]:
+ ...
+```
+
+Optionally, the return type may be put on the same line as the last parameter:
+
+```python
+Okay:
+def my_method(
+ self,
+ first_var: int,
+ second_var: int) -> dict[OtherLongType, MyLongType]:
...
```
@@ -3045,7 +3064,7 @@ opening one, but this is less readable.
```python
No:
def my_method(self,
- other_arg: Optional[MyLongType]
+ other_arg: Optional[MyLongType],
) -> dict[OtherLongType, MyLongType]:
...
```
@@ -3059,7 +3078,8 @@ def my_method(
first_var: tuple[list[MyLongType1],
list[MyLongType2]],
second_var: list[dict[
- MyLongType3, MyLongType4]]) -> None:
+ MyLongType3, MyLongType4]],
+) -> None:
...
```
@@ -3176,8 +3196,8 @@ long:
```python
-_ShortName = module_with_long_name.TypeWithLongName
-ComplexMap = Mapping[str, list[tuple[int, int]]]
+_LossAndGradient = tuple[tf.Tensor, tf.Tensor]
+ComplexTFMap = Mapping[str, _LossAndGradient]
```
Other examples are complex nested types and multiple return variables from a