From 5b06d2d794ee09b3aaf9297e61d734e763a07971 Mon Sep 17 00:00:00 2001 From: Google Python team Date: Sun, 18 Nov 2018 18:21:51 -0800 Subject: [PATCH] Project import generated by Copybara. PiperOrigin-RevId: 222009069 --- pyguide.md | 261 ++++++++++++++++++++++++++++------------------------- 1 file changed, 138 insertions(+), 123 deletions(-) diff --git a/pyguide.md b/pyguide.md index 0ed0c39..d7a72a5 100644 --- a/pyguide.md +++ b/pyguide.md @@ -59,7 +59,7 @@ Make sure you run `pylint` on your code. Suppress warnings if they are inappropriate so that other issues are not hidden. To suppress warnings, you can set a line-level comment: -```python {.good} +```python dict = 'something awful' # Bad Idea... pylint: disable=redefined-builtin ``` @@ -90,7 +90,7 @@ Unused argument warnings can be suppressed by deleting the variables at the beginning of the function. Always include a comment explaining why you are deleting it. "Unused." is sufficient. For example: -```python {.good} +```python def viking_cafe_order(spam, beans, eggs=None): del beans, eggs # Unused by vikings. return spam + spam + spam @@ -140,7 +140,7 @@ name with no prefix. For example the module `sound.effects.echo` may be imported as follows: -```python {.good} +```python from sound.effects import echo ... echo.EchoFilter(input, output, delay=0.7, atten=4) @@ -176,7 +176,7 @@ All new code should import each module by its full package name. Imports should be as follows: -```python {.good} +```python # Reference in code with complete name. import absl.flags @@ -228,7 +228,7 @@ Exceptions must follow certain conditions: statement. For example: - ```python {.good} + ```python Yes: def connect_to_next_port(self, minimum): """Connects to the next available port. @@ -250,7 +250,7 @@ Exceptions must follow certain conditions: return port ``` - ```python {.bad} + ```python No: def connect_to_next_port(self, minimum): """Connects to the next available port. @@ -289,7 +289,7 @@ Exceptions must follow certain conditions: - When capturing an exception, use `as` rather than a comma. For example: - ```python {.good} + ```python try: raise Error() except Error as error: @@ -402,7 +402,7 @@ expression, `for` clause, filter expression. Multiple `for` clauses or filter expressions are not permitted. Use loops instead when things get more complicated. -```python {.good} +```python Yes: result = [mapping_expr for value in iterable if filter_expr] @@ -436,7 +436,7 @@ Yes: if jelly_bean.color == 'black') ``` -```python {.bad} +```python No: result = [complicated_transform( x, some_argument=x+1) @@ -486,7 +486,7 @@ 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. -```python {.good} +```python Yes: for key in adict: ... if key not in adict: ... if obj in alist: ... @@ -494,7 +494,7 @@ Yes: for key in adict: ... for k, v in dict.iteritems(): ... ``` -```python {.bad} +```python No: for key in adict.keys(): ... if not adict.has_key(key): ... for line in afile.readlines(): ... @@ -636,7 +636,7 @@ Okay to use with the following caveat: Do not use mutable objects as default values in the function or method definition. -```python {.good} +```python Yes: def foo(a, b=None): if b is None: b = [] @@ -647,7 +647,7 @@ Yes: def foo(a, b: Sequence = ()): # Empty tuple OK since tuples are immutable ... ``` -```python {.bad} +```python No: def foo(a, b=[]): ... No: def foo(a, b=time.time()): # The time the module was loaded??? @@ -697,7 +697,7 @@ overridden. Thus one must make sure that accessor methods are called indirectly to ensure methods overridden in subclasses are called by the property (using the Template Method DP). -```python {.good} +```python Yes: import math class Square(object): @@ -792,7 +792,7 @@ Use the "implicit" false if at all possible, e.g., `if foo:` rather than known to be an integer (and is not the result of `len()`) against the integer 0. - ```python {.good} + ```python Yes: if not users: print('no users') @@ -807,7 +807,7 @@ Use the "implicit" false if at all possible, e.g., `if foo:` rather than x = [] ``` - ```python {.bad} + ```python No: if len(users) == 0: print('no users') @@ -844,7 +844,7 @@ generally preferable. 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 {.good} +```python Yes: words = foo.split(':') [x[1] for x in my_list if x[2] == 5] @@ -854,7 +854,7 @@ Yes: words = foo.split(':') fn(*args, **kwargs) ``` -```python {.bad} +```python No: words = string.split(foo, ':') map(lambda x: x[1], filter(lambda x: x[2] == 5, my_list)) @@ -880,7 +880,7 @@ occurs, the name is treated as a global variable. An example of the use of this feature is: -```python {.good} +```python def get_adder(summand1): """Returns a function that adds numbers to a given number.""" def adder(summand2): @@ -901,7 +901,7 @@ experienced Lisp and Scheme (and Haskell and ML and ...) programmers. 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/): -```python {.bad} +```python i = 4 def foo(x): def bar(): @@ -939,7 +939,7 @@ converting ordinary methods into dynamically computed attributes. However, the decorator syntax allows for user-defined decorators as well. Specifically, for some function `my_decorator`, this: -```python {.good} +```python class C(object): @my_decorator def method(self): @@ -949,7 +949,7 @@ class C(object): is equivalent to: -```python {.good} +```python class C(object): def method(self): # method body ... @@ -1085,7 +1085,7 @@ Use of `from __future__ import` statements is encouraged. All new code should contain the following and existing code should be updated to be compatible when possible: -```python {.good} +```python from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -1135,13 +1135,13 @@ modules. Type annotations (or "type hints") are for function or method arguments and return values: -```python {.good} +```python def func(a: int) -> List[int]: ``` You can also declare the type of a variable using a special comment: -```python {.good} +```python a = SomeFunc() # type: SomeType ``` @@ -1196,7 +1196,7 @@ Make use of Python's [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. -```python {.good} +```python Yes: foo_bar(self, width, height, color='black', design=None, x='foo', emphasis=None, highlight=0) @@ -1207,19 +1207,19 @@ Yes: foo_bar(self, width, height, color='black', design=None, x='foo', When a literal string won't fit on a single line, use parentheses for implicit line joining. -```python {.good} +```python x = ('This will build a very long long ' 'long long long long long long string') ``` Within comments, put long URLs on their own line if necessary. -```python {.good} +```python Yes: # See details at # http://www.example.com/us/developer/documentation/api/content/v2.0/csv_file_name_extension_full_specification.html ``` -```python {.bad} +```python No: # See details at # http://www.example.com/us/developer/documentation/api/content/\ # v2.0/csv_file_name_extension_full_specification.html @@ -1229,20 +1229,20 @@ It is permissible to use backslash continuation when defining a `with` statement whose expressions span three or more lines. For two lines of expressions, use a nested `with` statement: -```python {.good} +```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 {.bad} +```python No: with VeryLongFirstExpressionFunction() as spam, \ VeryLongSecondExpressionFunction() as beans: PlaceOrder(eggs, beans, spam, beans) ``` -```python {.good} +```python Yes: with very_long_first_expression_function() as spam: with very_long_second_expression_function() as beans: place_order(beans, spam) @@ -1261,7 +1261,7 @@ It is fine, though not required, to use parentheses around tuples. Do not use them in return statements or conditional statements unless using parentheses for implied line continuation or to indicate a tuple. -```python {.good} +```python Yes: if foo: bar() while x: @@ -1278,7 +1278,7 @@ Yes: if foo: for (x, y) in dict.items(): ... ``` -```python {.bad} +```python No: if (x): bar() if not(x): @@ -1299,7 +1299,7 @@ you should align wrapped elements either vertically, as per the examples in the in which case there should be nothing after the open parenthesis or bracket on the first line. -```python {.good} +```python Yes: # Aligned with opening delimiter foo = long_function_name(var_one, var_two, var_three, var_four) @@ -1329,7 +1329,7 @@ Yes: # Aligned with opening delimiter } ``` -```python {.bad} +```python No: # Stuff on first line forbidden foo = long_function_name(var_one, var_two, var_three, var_four) @@ -1360,7 +1360,7 @@ 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 of items to one item per line when the `,` after the final element is present. -```python {.good} +```python Yes: golomb3 = [0, 1, 3] Yes: golomb4 = [ 0, @@ -1370,7 +1370,7 @@ Yes: golomb4 = [ ] ``` -```python {.bad} +```python No: golomb4 = [ 0, 1, @@ -1396,24 +1396,24 @@ Follow standard typographic rules for the use of spaces around punctuation. No whitespace inside parentheses, brackets or braces. -```python {.good} +```python Yes: spam(ham[1], {eggs: 2}, []) ``` -```python {.bad} +```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 {.good} +```python Yes: if x == 4: print(x, y) x, y = y, x ``` -```python {.bad} +```python No: if x == 4 : print(x , y) x , y = y , x @@ -1422,20 +1422,20 @@ No: if x == 4 : No whitespace before the open paren/bracket that starts an argument list, indexing or slicing. -```python {.good} +```python Yes: spam(1) ``` -```python {.bad} +```python No: spam (1) ``` -```python {.good} +```python Yes: dict['key'] = list[index] ``` -```python {.bad} +```python No: dict ['key'] = list [index] ``` @@ -1444,11 +1444,11 @@ Surround binary operators with a single space on either side for assignment Booleans (`and, or, not`). Use your better judgment for the insertion of spaces around arithmetic operators (`+`, `-`, `*`, `/`, `//`, `%`, `**`, `@`). -```python {.good} +```python Yes: x == 1 ``` -```python {.bad} +```python No: x<1 ``` @@ -1457,12 +1457,12 @@ Only use spaces around the '=' sign defining a default parameter value [when a type annotation is present](#typing-default-values), do not use spaces around '=' for default parameter values otherwise. -```python {.good} +```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 {.bad} +```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) ``` @@ -1470,7 +1470,7 @@ 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 {.good} +```python Yes: foo = 1000 # comment long_name = 2 # comment that should not be aligned @@ -1481,7 +1481,7 @@ Yes: } ``` -```python {.bad} +```python No: foo = 1000 # comment long_name = 2 # comment that should not be aligned @@ -1592,7 +1592,7 @@ Sections should be indented two spaces, except for the heading. [*Raises:*](#doc-function-raises) {#doc-function-raises} : List all exceptions that are relevant to the interface. -```python {.good} +```python def fetch_bigtable_rows(big_table, keys, other_silly_variable=None): """Fetches rows from a Bigtable. @@ -1633,7 +1633,7 @@ If your class has public attributes, they should be documented here in an `Attributes` section and follow the same formatting as a [function's `Args`](#doc-function-args) section. -```python {.good} +```python class SampleClass(object): """Summary of class here. @@ -1664,7 +1664,7 @@ review](http://en.wikipedia.org/wiki/Code_review), you should comment it now. Complicated operations get a few lines of comments before the operations commence. Non-obvious ones get comments at the end of the line. -```python {.good} +```python # We use a weighted dictionary search to find out where i is in # the array. We extrapolate position based on the largest num # in the array and the array size and then do binary search to @@ -1679,7 +1679,7 @@ code. On the other hand, never describe the code. Assume the person reading the code knows Python (though not what you're trying to do) better than you do. -```python {.bad} +```python # BAD COMMENT: Now go through the b array and make sure whenever i occurs # the next element is i+1 ``` @@ -1709,7 +1709,7 @@ punctuation, spelling, and grammar help with that goal. If a class inherits from no other base classes, explicitly inherit from `object`. This also applies to nested classes. -```python {.good} +```python Yes: class SampleClass(object): pass @@ -1725,7 +1725,7 @@ Yes: class SampleClass(object): ``` -```python {.bad} +```python No: class SampleClass: pass @@ -1750,7 +1750,7 @@ Use the `format` method or the `%` operator for formatting strings, even when the parameters are all strings. Use your best judgement to decide between `+` and `%` (or `format`) though. -```python {.good} +```python Yes: x = a + b x = '%s, %s!' % (imperative, expletive) x = '{}, {}'.format(first, second) @@ -1759,7 +1759,7 @@ Yes: x = a + b x = f'name: {name}; score: {n}' # Python 3.6+ ``` -```python {.bad} +```python No: x = '%s%s' % (a, b) # use + in this case x = '{}{}'.format(a, b) # use + in this case x = first + ', ' + second @@ -1772,7 +1772,7 @@ 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 a `io.BytesIO` buffer). -```python {.good} +```python Yes: items = [''] for last_name, first_name in employee_list: items.append('' % (last_name, first_name)) @@ -1780,7 +1780,7 @@ Yes: items = ['
%s, %s
'] employee_table = ''.join(items) ``` -```python {.bad} +```python No: employee_table = '
' for last_name, first_name in employee_list: employee_table += '' % (last_name, first_name) @@ -1792,14 +1792,14 @@ or `"` and stick with it. It is okay to use the other quote character on a string to avoid the need to `\\` escape within the string. `gpylint` enforces this. -```python {.good} +```python Yes: Python('Why are you hiding your eyes?') Gollum("I'm scared of lint errors.") Narrator('"Good!" thought a happy Python reviewer.') ``` -```python {.bad} +```python No: Python("Why are you hiding your eyes?") Gollum('The lint. It burns. It burns us.') @@ -1812,13 +1812,13 @@ use `'''` for all non-docstring multi-line strings if and only if they also use often cleaner to use implicit line joining since multi-line strings do not flow with the indentation of the rest of the program: -```python {.good} +```python Yes: print("This is much nicer.\n" "Do it this way.\n") ``` -```python {.bad} +```python No: print("""This is pretty ugly. Don't do this. @@ -1858,7 +1858,7 @@ file is poor practice, for several reasons: The preferred way to manage files is using the ["with" statement](http://docs.python.org/reference/compound_stmts.html#the-with-statement): -```python {.good} +```python with open("hello.txt") as hello_file: for line in hello_file: print(line) @@ -1867,7 +1867,7 @@ with open("hello.txt") as hello_file: For file-like objects that do not support the "with" statement, use `contextlib.closing()`: -```python {.good} +```python import contextlib with contextlib.closing(urllib.urlopen("http://www.python.org/")) as front_page: @@ -1890,7 +1890,7 @@ The main purpose is to have a consistent `TODO` format that can be searched to find out how to get more details upon request. 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. -```python {.good} +```python # TODO(kl@gmail.com): Use a "*" here for string repetition. # TODO(Zeke) Change this to use relations. ``` @@ -1907,12 +1907,12 @@ Imports should be on separate lines. E.g.: -```python {.good} +```python Yes: import os import sys ``` -```python {.bad} +```python No: import os, sys ``` @@ -1923,7 +1923,7 @@ grouped with the order being most generic to least generic: 1. Python standard library imports. For example: - ```python {.good} + ```python import sys ``` @@ -1931,7 +1931,7 @@ grouped with the order being most generic to least generic: module or package imports. For example: - ```python {.good} + ```python import tensorflow as tf ``` @@ -1939,7 +1939,7 @@ grouped with the order being most generic to least generic: sub-package imports. For example: - ```python {.good} + ```python from otherproject.ai import mind ``` @@ -1948,7 +1948,7 @@ grouped with the order being most generic to least generic: sub-package as this file. For example: - ```python {.good} + ```python from myproject.backend.hgwells import time_machine ``` @@ -1962,7 +1962,7 @@ Within each grouping, imports should be sorted lexicographically, ignoring case, according to each module's full package path. Code may optionally place a blank line between import sections. -```python {.good} +```python import collections import queue import sys @@ -1997,13 +1997,13 @@ the entire statement fits on one line. In particular, you can never do so with `try`/`except` since the `try` and `except` can't both fit on the same line, and you can only do so with an `if` if there is no `else`. -```python {.good} +```python Yes: if foo: bar(foo) ``` -```python {.bad} +```python No: if foo: bar(foo) @@ -2204,7 +2204,7 @@ In Python, `pydoc` as well as unit tests require modules to be importable. Your code should always check `if __name__ == '__main__'` before executing your main program so that the main program is not executed when the module is imported. -```python {.good} +```python def main(): ... @@ -2269,7 +2269,7 @@ Try to follow the existing [indentation](#indentation) rules. After annotating, many function signatures will become "one parameter per line". -```python {.good} +```python def my_method(self, first_var: int, second_var: Foo, @@ -2281,7 +2281,7 @@ Always prefer breaking between variables, and not for example between variable names and type annotations. However, if everything fits on the same line, go for it. -```python {.good} +```python def my_method(self, first_var: int) -> int: ... ``` @@ -2289,7 +2289,7 @@ 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 {.good} +```python def my_method( self, first_var: int) -> Tuple[MyLongType1, MyLongType1]: ... @@ -2299,7 +2299,7 @@ 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. -```python {.good} +```python Yes: def my_method( self, **kw_args: Optional[MyLongType] @@ -2310,7 +2310,7 @@ def my_method( `pylint` allows you to move the closing parenthesis to a new line and align with the opening one, but this is less readable. -```python {.bad} +```python No: def my_method(self, **kw_args: Optional[MyLongType] @@ -2321,7 +2321,7 @@ def my_method(self, As in the examples above, prefer not to break types. However, sometimes they are too long to be on a single line (try to keep sub-types unbroken). -```python {.good} +```python def my_method( self, first_var: Tuple[List[MyLongType1], @@ -2335,7 +2335,7 @@ If a single name and type is too long, consider using an [alias](#typing-aliases) for the type. The last resort is to break after the colon and indent by 4. -```python {.good} +```python Yes: def my_function( long_variable_name: @@ -2344,7 +2344,7 @@ def my_function( ... ``` -```python {.bad} +```python No: def my_function( long_variable_name: long_module_name. @@ -2361,7 +2361,7 @@ If you need to use a class name from the same module that is not yet defined -- for example, if you need the class inside the class declaration, or if you use a class that is defined below -- use a string for the class name. -```python {.good} +```python class MyClass(object): def __init__(self, @@ -2377,12 +2377,12 @@ when combining an argument annotation with a default value, use spaces around the = sign (but only for those arguments that have both an annotation and a default). -```python {.good} +```python Yes: def func(a: int = 0) -> int: ... ``` -```python {.bad} +```python No: def func(a:int=0) -> int: ... @@ -2401,7 +2401,7 @@ Use explicit `Optional` instead of implicit `Optional`. Earlier versions of PEP 484 allowed `a: Text = None` to be interpretted as `a: Optional[Text] = None`, but that is no longer the preferred behavior. -```python {.good} +```python Yes: def func(a: Optional[Text], b: Optional[Text] = None) -> Text: ... @@ -2409,7 +2409,7 @@ def multiple_nullable_union(a: Union[None, Text, int]) -> Text ... ``` -```python {.bad} +```python No: def nullable_union(a: Union[None, Text]) -> Text: ... @@ -2428,7 +2428,7 @@ returned tuples). If the alias is used only in this module, it should be For example, if the name of module together with the type is too long: -```python {.good} +```python SomeType = module_with_long_name.TypeWithLongName ``` @@ -2444,7 +2444,7 @@ You can disable type checking on a line with the special comment `pytype` has a disable option for specific errors (similar to lint): -```python {.good} +```python # pytype: disable=attribute-error ``` @@ -2455,7 +2455,7 @@ You can disable type checking on a line with the special comment If an internal variable has a type that is hard or impossible to infer, you can supply it as a special comment: -```python {.good} +```python a = SomeUndecoratedFunction() # type: Foo ``` @@ -2466,7 +2466,7 @@ Unlike Lists, which can only have a single type, Tuples can have either a single repeated type or a set number of elements with different types. The latter is commonly used as return type from a function. -```python {.good} +```python a = [1, 2, 3] # type: List[int] b = (1, 2, 3) # type: Tuple[int, ...] c = (1, "2", 3.5) # type: Tuple[int, Text, float] @@ -2482,7 +2482,7 @@ function `TypeVar` is a common way to use them. Example: -```python {.good} +```python from typing import List, TypeVar T = TypeVar("T") ... @@ -2492,7 +2492,7 @@ def next(l: List[T]) -> T: A TypeVar can be constrained: -```python {.good} +```python AddableType = TypeVar("AddableType", int, float, Text) def add(a: AddableType, b: AddableType) -> AddableType: return a + b @@ -2502,7 +2502,7 @@ A common predefined type variable in the `typing` module is `AnyStr`. Use it for multiple annotations that can be `bytes` or `unicode` and must all be the same type. -```python {.good} +```python from typing import AnyStr def check_length(x: AnyStr) -> AnyStr: if len(x) <= 42: @@ -2514,40 +2514,55 @@ def check_length(x: AnyStr) -> AnyStr: #### 3.19.11 Strings types -When annotating functions that take or return strings, avoid using `str`, -because it means different things in Python 2 and Python 3. In Python 2, `str` -is `bytes`; in Python 3, it is `unicode`. Whenever possible, it is best to be -explicit: +The proper type for annotating strings depends on what versions of Python the +code is intended for. -```python {.bad} +For Python 3 only code, prefer to use `str`. `Text` is also acceptable. Be +consistent in using one or the other. + +For Python 2 compatible code, use `Text`. In some rare cases, `str` may make +sense; typically to aid compatiblity when the return types aren't the same +between the two Python versions. Avoid using `unicode`: it doesn't exist in +Python 3. + +The reason this discreprency exists is because `str` means different things +depending on the Python version. + +```python No: -def f(x: str) -> str: +def py2_code(x: str) -> unicode: ... ``` -For code that deals with byte arrays, use `bytes`. +For code that deals with binary data, use `bytes`. -```python {.good} -def f(x: bytes) -> bytes: +```python +def deals_with_binary_data(x: bytes) -> bytes: ... ``` -For code that processes text data (`str` or `unicode` in Python 2, `str` in -Python 3), use `Text`. +For Python 2 compatible code that processes text data (`str` or `unicode` in +Python 2, `str` in Python 3), use `Text`. For Python 3 only code that process +text data, prefer `str`. -```python {.good} +```python from typing import Text ... -def f(x: Text) -> Text: +def py2_compatible(x: Text) -> Text: + ... +def py3_only(x: str) -> str: ... ``` -If the type can be either byte arrays or text, use `Union`. +If the type can be either bytes or text, use `Union`, with the appropriate text +type. -```python {.good} +```python from typing import Text, Union ... -def f(x: Union[bytes, Text]) -> Union[bytes, Text]: +def py2_compatible(x: Union[bytes, Text]) -> Union[bytes, Text]: + ... +def py3_only(x: Union[bytes, str]) -> Union[bytes, str]: ... ``` @@ -2565,7 +2580,7 @@ For classes from the `typing` module, always import the class itself. You are explicitly allowed to import multiple specific classes on one line from the `typing` module. Ex: -```python {.good} +```python from typing import Any, Dict, Optional ``` @@ -2575,7 +2590,7 @@ not be defined in your Python code, typed or not. If there is a collision between a type and an existing name in a module, import it using `import x as y`. -```python {.good} +```python from typing import Any as AnyType ``` @@ -2601,7 +2616,7 @@ Imports that are needed only for type annotations can be placed within an - There should be no empty lines in the typing imports list. - Sort this list as if it were a regular imports list. -```python {.good} +```python import typing if typing.TYPE_CHECKING: import sketch @@ -2622,7 +2637,7 @@ Replace modules that create circular dependency imports with `Any`. Set an this module (any attribute of Any is Any). Alias definitions should be separated from the last import by one line. -```python {.good} +```python from typing import Any some_mod = Any # some_mod.py imports this module. @@ -2640,12 +2655,12 @@ def my_method(self, var: some_mod.SomeType) -> None: 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). -```python {.good} +```python def get_names(employee_ids: List[int]) -> Dict[int, Any]: ... ``` -```python {.bad} +```python # These are both interpreted as get_names(employee_ids: List[Any]) -> Dict[Any, Any] def get_names(employee_ids: list) -> Dict: ... @@ -2658,12 +2673,12 @@ If the best type parameter for a generic is `Any`, make it explicit, but remember that in many cases [`TypeVar`](#typing-type-var) might be more appropriate: -```python {.bad} +```python def get_names(employee_ids: List[Any]) -> Dict[Any, Text]: """Returns a mapping from employee ID to employee name for given IDs.""" ``` -```python {.good} +```python T = TypeVar('T') def get_names(employee_ids: List[T]) -> Dict[T, Text]: """Returns a mapping from employee ID to employee name for given IDs."""
%s, %s