Redundancy-elimination within the "Style Rules".
diff --git a/PythonStyleGuide.wiki b/PythonStyleGuide.wiki index ac62057..265cf1a 100644 --- a/PythonStyleGuide.wiki +++ b/PythonStyleGuide.wiki
@@ -38,27 +38,11 @@ Programs are much easier to maintain when all files have a consistent style. Here is the canonical Melange Python style. - # [PythonStyleGuide#Semicolons Semicolons]: _*Avoid*_ - # [PythonStyleGuide#Line_length Line length]: _*80* columns maximum_ - # [PythonStyleGuide#Parentheses Parentheses]: _*Use sparingly*_ # [PythonStyleGuide#Indentation Indentation]: _*2* spaces (*no tabs*),_ *differs from [http://www.python.org/dev/peps/pep-0008/ PEP8]* - # [PythonStyleGuide#Blank_lines Blank lines]: _*2* for functions and classes, *1* for methods_ - # [PythonStyleGuide#Whitespace Whitespace]: _Sparingly within a line_ # [PythonStyleGuide#Python_Interpreter Python Interpreter]: _Variable, either omitted, `#!/usr/bin/python`, or `#!/usr/bin/python2.7`_ - # [PythonStyleGuide#Comments Comments]: _`__doc__` strings, block, inline_ - * [PythonStyleGuide#Doc_strings `__doc__` Strings] - * [PythonStyleGuide#Modules Modules] - * [PythonStyleGuide#Functions_and_Methods Functions and Methods] - * [PythonStyleGuide#Classes Classes] - * [PythonStyleGuide#Block_and_Inline_Comments Block and Inline Comments] - # [PythonStyleGuide#Classes Classes]: _Inherit from object_ - # [PythonStyleGuide#Strings Strings]: _Avoid repeated use of `+` and `+=`_ - # [PythonStyleGuide#TODO_style TODO style]: `TODO(username):` _use a consistent style_ + # [PythonStyleGuide#Copyright_And_License_Notices Copyright And License Notices]: _Include in every file._ # [PythonStyleGuide#Imports_grouping_and_order Imports grouping, order and sorting]: _One per line, grouped and ordered by packages, sorted alphabetically_ - # [PythonStyleGuide#Statements Statements]: _One per line, avoid [PythonStyleGuide#Semicolons Semicolons]_ - # [PythonStyleGuide#Access_control Access control]: _`foo` if lightweight, `GetFoo()` and `SetFoo()` otherwise_ # [PythonStyleGuide#Naming Naming]: _`foo_bar.py` not `foo-bar.py`,_ *some differ from [http://www.python.org/dev/peps/pep-0008/ PEP8]* - # [PythonStyleGuide#Main Main]: `if __name__ == '__main__':` # [PythonStyleGuide#Conclusion Conclusion]: _Look at what's around you!_ = Python Language Rules = @@ -115,98 +99,6 @@ = Python Style Rules = -== Semicolons == - -Do not terminate your lines with semi-colons and do not use semi-colons -to put two commands on the same line. - -== Line length == - -Maximum line length is 80 characters. - -*Exception:* lines importing modules may end up longer than 80 characters. - -Make use of Python's implicit line joining inside parentheses, brackets -and braces. If necessary, you can add an extra pair of parentheses around -an expression. - -*Yes:* - -{{{ -fooBar(self, width, height, color='black', design=None, x='foo', - emphasis=None, highlight=0) - - -if ((width == 0) and (height == 0) - and (color == 'red') and (emphasis == 'strong')): -}}} - -When a literal string won't fit on a single line, use parentheses for -implicit line joining. - -{{{ -x = ('This will build a very long long ' - 'long long long long long long string') -}}} - -Make note of the indentation of the elements in the line continuation -examples above; see the -[PythonStyleGuide#Indentation indentation section] for explanation. - -== Parentheses == - -Use parentheses sparingly. Do not use them: - - * in `return` statements - * in conditional statements unless using parentheses for implied line continuation (see above) - * around tuples, unless they are necessary syntactically or for clarity - -It is, however, fine to use parentheses: - - * for implied line continuation - * around sub-expressions in a larger expression (including the sub-expressions that are part of a conditional statement) - -In fact, parentheses around sub-expressions is preferred to relying solely -on operator precedence. - -*Yes:* - -{{{ -if foo: - -while x: - -if x and y: - -if not x: - -if (x < 3) and (not y): - -return foo - -for x, y in dict.items(): - -x, (y, z) = funcThatReturnsNestedTuples() -}}} - -*No:* - -{{{ -if (x): - -while (x): - -if not(x): - -if ((x < 3) and (not y)): - -return (foo) - -for (x, y) in dict.items(): - -(x, (y, z)) = funcThatReturnsNestedTuples() -}}} - == Indentation == _Note that this differs from @@ -247,109 +139,18 @@ var_four) }}} -== Blank lines == - -Two blank lines between top-level definitions, be they function or class -definitions. One blank line between method definitions and between the -class line and the first method. One blank line between -[PythonStyleGuide#Doc_strings `__doc__` strings] and the code that follows -them. Use single blank lines as you judge appropriate within functions or -methods. -Always have a single blank line at the end of the file, this suppresses the "\ No newline at end of file" message that is generated by most diff tools. - -== Whitespace == - -No whitespace inside parentheses, brackets or braces. - -*Yes:* `spam(ham[1], {eggs: 2}, [])` - -*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. - -*Yes:* - -{{{ -if x == 4: - -print x, y - -x, y = y, x -}}} - -*No:* - -{{{ -if x == 4 : - -print x , y - -x , y = y , x -}}} - -No whitespace before the open paren/bracket that starts an argument -list, indexing or slicing. - -*Yes:* `spam(1)` - -*No:* `spam (1)` - -*Yes:* `dict['key'] = list[index]` - -*No:* `dict ['key'] = list [index]` - -Surround binary operators with a single space on either side for -assignment (`=`), comparisons (`==`, `<`, `>`, `!=`, `<>`, `<=`, `>=`, -`in`, `not in`, `is`, `is not`), and booleans (`and`, `or`, `not`). Use -your better judgment for the insertion of spaces around arithmetic -operators but always be consistent about whitespace on either side of -a binary operator. - -*Yes:* `x == 1` - -*No:* `x<1` - -Don't use spaces around the '`=`' sign when used to indicate a keyword -argument or a default parameter value. - -*Yes:* `def Complex(real, imag=0.0): return Magic(r=real, i=imag)` - -*No:* `def Complex(real, imag = 0.0): return Magic(r = real, i = imag)` - === Python Interpreter == Modules which are not intended for direct execution (and which have no effect if executed) should not include a shebang line. Modules intended for direct execution should begin with a shebang line specifying the Python interpreter used to execute the program, most likely `#!/usr/bin/python` or `#!/usr/bin/python2.7`. -== Comments == +== Copyright And License Notices == -=== Doc strings === - -Python has a unique commenting style using `__doc__` strings. A `__doc__` -string is a string that is the first statement in a package, module, -class or function. These strings can be extracted automatically through -the `__doc__()` member of the object and are used by `pydoc`. (Try -running `pydoc` on your module to see how it looks.) Our convention for -`__doc__` strings is to use the three double-quote format for strings. -A `__doc__` string should be organized as a summary line (one physical -line, [PythonStyleGuide#Line_length 80 characters or less]) terminated -by a period, followed by a blank line, followed by the rest of the -`__doc__` string starting at the same cursor position as the first quote -of the first line. There are more formatting guidelines for `__doc__` -strings below. - -=== Modules === - -Every file should contain a block comment with a copyright notice and -license statement at the top of the file. - -==== Copyright and license notices ==== +Every module should feature the following either at the top or just below +the module's shebang and blank-comment-following-shebang lines. {{{ -#!/usr/bin/python2.5 -# # Copyright [current year] the Melange authors. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -365,272 +166,6 @@ # limitations under the License. }}} -This should be followed by a `__doc__` string describing the contents -of the module. Author information is then included after this string. -If an optional email is provided, then the entire author string -added to the `__authors__` list needs to be an -[http://www.ietf.org/rfc/rfc2821.txt RFC 2821 compliant] email address. - -==== Module header and authors ==== - -{{{ -"""A one line summary of the module or script, terminated by a period. - -Leave one blank line. The rest of this __doc__ string should contain an -overall description of the module or script. Optionally, it may also -contain a brief description of exported classes and functions. - - ClassFoo: One line summary. - functionBar(): One line summary. -""" - -__authors__ = [ - # alphabetical order by last name, please - '"John Smith" <johnsmith@example.com>', - '"Joe Paranoid" <joeisgone@example.com>', # email address is required -] -}}} - -If a new contributor is not yet present in the -[http://soc.googlecode.com/svn/trunk/AUTHORS AUTHORS file], that contributor -should be added to that file as part of the first commit from that -contributor. - -=== Functions and Methods === - -Any function or method which is not both obvious and very short needs -a `__doc__` string. Additionally, any externally accessible function -or method regardless of length or simplicity needs a `__doc__` string. -The `__doc__` string should include what the function does and have -detailed descriptions of the input ("`Args:`") and output -("`Returns:`", "`Raises:`", or "`Yields:`"). The `__doc__` string -should give enough information to write a call to the function without -looking at a single line of the function's code. The `__doc__` string -should specify the expected types where specific types are required, -and it should mention any default argument values. A "`Raises:`" section -should list all exceptions that can be raised by the function. The -`__doc__` string for generator functions should use "`Yields:`" rather -than "`Returns:`". - -The function or method `__doc__` string should not, generally, describe -implementation details unless it's some complicated algorithm. For -tricky code, block/inline comments within the code are more appropriate. - -{{{ -def fetchRows(table, keys): - """Fetch rows from a table. - - Args: - table: An open table.Table instance. - keys: A sequence of strings representing the key of each table - row to fetch. - - Returns: - A dict mapping keys to the corresponding table row data - fetched. Each row is represented as a tuple of strings. For - example: - - {'Serak': ('Rigel VII', 'Preparer'), - 'Zim': ('Irk', 'Invader'), - 'Lrrr': ('Omicron Persei 8', 'Emperor')} - - If a key from the keys argument is missing from the dictionary, - then that row was not found in the table. - - Raises: - IOError: An error occurred accessing the table.Table object. - """ - pass -}}} - -=== Classes === - -Classes should have a `__doc__` string below the class definition -describing the class. If your class has public attributes they should -be documented here in an `Attributes:` section. - -{{{ -class SampleClass(object): - - """Summary of class here. - - Longer class information.... - Longer class information.... - - Attributes: - likes_spam: A boolean indicating if we like SPAM or not. - eggs: An integer count of the eggs we have laid. - """ - - def __init__(self, likes_spam=False): - """Inits SampleClass with blah. - - Args: - likes_spam: Initial indication of if the SampleClass - instance likes SPAM or not (default is False) - """ - self.likes_spam = likes_spam - self.eggs = 0 - - def publicMethod(self): - """Perform operation blah.""" - pass -}}} - -=== Block and Inline Comments === - -The final place to have comments is in tricky parts of the code. If -you're going to have to explain it at the next 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. - -{{{ -# We use a weighted dictionary search to find out where i is in -# the array. We extrapolate position based on the largest number -# in the array and the array size and then do binary search to -# get the exact number. - -if i & (i-1) == 0: # true iff i is a power of 2 -}}} - -These comments should be separated from the code to improve legibility. -Block comments should be preceded by a blank line. In general, -end-of-line comments should be at least 2 spaces away from the code. These -end-of-line comments _can_ be lined up if there are many in a row (or -in a function), but this is not required. - -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. - -{{{ -# BAD COMMENT: Now go through the b array and make sure whenever i occurs -# the next element is i+1 -}}} - -== Classes == - -If a class inherits from no other base classes, explicitly inherit from -`object`. This also applies to nested classes. - -*No:* - -{{{ -class SampleClass: - pass - -class OuterClass: - class InnerClass: - pass -}}} - -*Yes:* - -{{{ -class SampleClass(object): - pass - -class OuterClass(object): - class InnerClass(object): - pass - -class ChildClass(ParentClass): - """Explicitly inherits from another class already.""" - pass -}}} - -Inheriting from `object` is needed to make properties work properly, and -it will protect our code from one particular flavor of things that might -break once we switch to Python 3000. It also defines special methods that -implement the default semantics of objects including `__new__`, -`__init__`, `__delattr__`, `__getattribute__`, `__setattr__`, `__hash__`, -`__repr__`, and `__str__`. - -== Strings == - -Use the `%` operator for formatting strings, even when the parameters -are all strings. Use your best judgement to decide between `+` and `%` -though. - -*No:* - -{{{ -x = '%s%s' % (a, b) # use + in this case -x = imperative + ', ' + expletive + '!' -x = 'name: ' + name + '; score: ' + str(n) -}}} - -*Yes:* - -{{{ -x = a + b -x = '%s, %s!' % (imperative, expletive) -x = 'name: %s; score: %d' % (name, 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 sub-string to a `list` and `''.join()` that list after -the loop terminates. - -*No:* - -{{{ -employee_table = '<table>' -for last_name, first_name in employee_list: - employee_table += '<tr><td>%s, %s</td></tr>' % (last_name, first_name) -employee_table += '</table>' -}}} - -*Yes:* - -{{{ -items = ['<table>'] -for last_name, first_name in employee_list: - items.append('<tr><td>%s, %s</td></tr>' % (last_name, first_name)) -items.append('</table>') -employee_table = ''.join(items) -}}} - -Use `"""` for multi-line strings rather than `'''`. Note, however, that -it is often cleaner to use implicit line joining since multi-line -strings do not flow with the indentation of the rest of the program: - -*No:* -{{{ - print """This is pretty ugly. -Don't do this. -""" -}}} - -*Yes:* - -{{{ - print ("This is much nicer.\n" - "Do it this way.\n") -}}} - -== TODO style == - -Use `TODO` comments for code that is temporary, a short-term solution, -or good-enough but not perfect. - -`TODO`s should include the string `TODO` in all caps, followed by your -`username` in parentheses: `TODO(username)`. A colon is optional. The -main purpose is to have a consistent `TODO` format searchable by `username`. - -{{{ -# TODO(someuser): Use a "*" here for concatenation operator. -# TODO(anotheruser) change this to use relations. -}}} - -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 2008") -or a very specific event ("Remove this code after the Foo entities in -the datastore have all added the new fubar property."). - == Imports grouping and order == Imports should be on separate lines, e.g.: @@ -675,49 +210,6 @@ from b_soc import d }}} -== Statements == - -Generally only one statement per line. However, you may put the result -of a test on the same line as the test only if 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`. - -*Yes:* - -{{{ -if foo: fuBar(foo) -}}} - -*No:* - -{{{ -if foo: fuBar(foo) -else: fuBaz(foo) - -try: fuBar(foo) -except ValueError: fuBaz(foo) - -try: - fuBar(foo) -except ValueError: fuBaz(foo) -}}} - -== Access control == - -If an accessor function would be trivial you should use public variables -instead of accessor functions to avoid the extra cost of function calls -in Python. When more functionality is added you can use property to keep -the syntax consistent. - -On the other hand, if access is more complex, or the cost of accessing -the variable is significant, you should use function calls (following -the [PythonStyleGuide#Naming Naming guidelines]) such as `getFoo()` and -`setFoo()`. If the past behavior allowed access through a property, do -not bind the new accessor functions to the property. Any code still -attempting to access the variable by the old method should break visibly -so callers are made aware of the change in complexity. - == Naming == === Names to avoid === @@ -760,26 +252,6 @@ in Python, and `property` can be used later to turn attribute access into a function call without changing the access syntax. -== Main == - -Every Python source file should be importable. In Python, `pychecker`, -`pydoc`, and 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. The capitalization of `main()` is intentionally inconsistent -with the rest of the naming conventions, which would suggest `Main()`. - -{{{ -if __name__ == '__main__': - # parse arguments - main() -}}} - -All code at the top level will be executed when the module is imported. -Be careful not to call functions, create objects, or perform other -operations that should not be executed when the file is being `pycheck`ed -or `pydoc`ed. - == Conclusion == _BE CONSISTENT._ @@ -801,4 +273,4 @@ _Copyright 2008 Google Inc._ _This work is licensed under a_ [http://soc.googlecode.com/svn/wiki/html/licenses/cc-by-attribution-2_5.html Creative Commons Attribution 2.5 License]. -[http://creativecommons.org/licenses/by/2.5/ http://soc.googlecode.com/svn/wiki/html/licenses/cc-by-2_5-88x31.png] \ No newline at end of file +[http://creativecommons.org/licenses/by/2.5/ http://soc.googlecode.com/svn/wiki/html/licenses/cc-by-2_5-88x31.png]