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 = ['