#!/usr/bin/env python # coding: utf-8 # # Python Style Guide # In[1]: import addutils.toc ; addutils.toc.js(ipy_notebook=True) # You will soon realize that the Python community often cite the *Pythonic approach to do things*. # # *'Pythonic'* refers to the principles laid out in *'The Zen of Python'*: a collection of basic coding rules to allow Python code to be more readable, maintainable and accessible to both novice and experienced developers. You can access *'The Zen of Python'* by typing at any time `import this` in any Python interpreter. # In[2]: from addutils import css_notebook css_notebook() # In[3]: import this # ## 1 PEP8 # PEP is an acronym for Python Enhancement Proposals. The whole list can be found [HERE](http://www.python.org/dev/peps/). # # [PEP8](http://www.python.org/dev/peps/pep-0008/) in particular contains coding convections and is perhaps the most explicit example of idioms within the Python community. In Computer Science, idioms are preferred ways of writing code (often there are many possible coding solutions to reach the same results, and some solutions are considered better than others, both for readability and performance reasons). We highly recommend to read PEP8 before start your career as a Python Programmer. # It will be higly recommendable to use a PEP8 style-checking plugin to be shure your code is fully compliant with that rules. # ## 2 Syntax and Naming Conventions # ### 2.1 Avoid using semicolons at the end of lines # Even if allowed, python doesn't need it! # In[4]: # WRONG var = 15; s = "I like semicolons"; a = 1; b =2; c = 3 # In[5]: # CORRECT var = 15 s = "No semicolons!" a, b, c = 1, 2, 3 # ### 2.2 Avoid having multiple statements on a single line # In[6]: condition = True # WRONG if condition: a = 1; b =2; c = 3 # CORRECT if condition: a, b, c = 1, 2, 3 # ### 2.3 Indent your code block 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 for the examples in the line length section; or using a hanging indent of 4 spaces, in which case there should be no argument on the first line. # WRONG - Stuff on first line forbidden lfunc = long_function_name(var_one, var_two, var_three, var_four) # CORRECT - Aligned with opening delimiter lfunc = long_function_name(var_one, var_two, var_three, var_four) # ### 2.4 Imports: Should always be on separate lines, if refered to different modules. # Always on top of modules. Avoid **from module import *** if not strictly required. # Imports should be grouped in the following order: # # * standard library imports # * related third party imports # * local application/library specific imports # In[7]: # WRONG import sys, os from math import * # In[8]: # CORRECT import sys import os from math import gamma # ### 2.5 Whitespace: required or not? # No spaces in parentheses, no whitespace before a comma, semicolon, or colon. Do use whitespace after a comma, semicolon, or colon except at the end of the line. # WRONG spam( ham[ 1 ], { eggs: 2 }, [ ] ) #CORRECT spam(ham[1], {eggs: 2}, []) # No whitespace before the open paren/bracket that starts an argument list, indexing or slicing. # WRONG spam (1) dict ['key'] = list [index] # CORRECT spam(1) dict['key'] = list[index] # Don't use spaces around the **=** operator when used to indicate a keyword argument or a default parameter value. # In[9]: # WRONG def complex(real, imag = 0.0): return magic(r = real, i = imag) # In[10]: # CORRECT def complex(real, imag=0.0): return magic(r=real, i=imag) # 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. # ```python # # WRONG # x<1 # # # # CORRECT # x == 1 # ``` # Don't use spaces to vertically align tokens on consecutive lines, since it becomes a maintenance burden (applies to **:**, **#**, **=**, etc.): # In[11]: # WRONG short = 1000 # comment long_name = 2 # comment that should not be aligned dictionary = { 'foo' : 1, 'long_name': 2, } # In[12]: # CORRECT short = 1000 # comment long_name = 2 # comment that should not be aligned dictionary = { 'foo': 1, 'long_name': 2, } # ### 2.6 Naming: names in python should be chosen according to the following conventions: # * object naming: # `module_name, package_name, ClassName, method_name, ExceptionName, function_name, GLOBAL_CONSTANT_NAME, global_var_name, instance_var_name, function_parameter_name, local_var_name`. # * avoid single character names except for counters or iterators # * avoid dashes (-) in any package/module name # * `__double_leading_and_trailing_underscore` names (reserved by Python) # ## 3 Working with Data # ### 3.1 Avoid using a temporary variable when swapping two variables # There is no reason to swap using a temporary variable in Python. We can use tuples to make our code more readable # In[13]: # WRONG - Swap two variables using a temporary variable a, b = 10, 20 temp = a a = b b = temp # In[14]: # CORRECT - Swap two variables using tuples (a,b) = (b,a) # Parentesis can be omitted # ### 3.2 Use tuples to unpack data # In Python, it is possible to 'pack' and 'unpack' data. This is mostly used while passing multiple values to functions. # In[15]: # WRONG - Unpack values with single instructions packed = ['car', 'Cevy', 160] vehicle = packed[0] make = packed[1] speed = packed[2] # In[16]: # CORRECT - Unpack values using tuples packed = ['car', 'Cevy', 160] (vehicle, make, speed) = packed # ### 3.3 Strings: Use join and list to create a string from a list and viceversa # In[17]: mylist = ['u', 's', 'e', ' ', 'j', 'o', 'i', 'n', '(', '', ')'] # WRONG mystr = '' for letter in mylist: mystr = mystr + letter # CORRECT mystr = ''.join(mylist) # CORRECT: generate a list from a string mylist2 = list('this will be a list') print(mylist2) # ### 3.4 Strings: Use startswith and endswith instead of string slicing to check for prefixes or suffixes. # In[18]: mystr = 'Check me' # WRONG print(mystr[:5] == 'Check') # CORRECT print(mystr.startswith('Check')) # ### 3.5 Dictionaries: Use the default parameter of dict.get to provide default values # In[19]: # WRONG power = dict([('on', 100), ('off', 0)]) if 'idle' in power: print(power['idle']) else: print(0.1) # In[20]: # CORRECT print(power.get('idle', 0.1)) # ### 3.6 File IO: Use Context Managers to ensure resources are properly managed # # WRONG - If the function 'do_something' generates an exception # # the file will never be closed # file_handle = open('myfile', 'r') # for line in file_handle.readlines(): # do_something(line): # file_handle.close() # # # CORRECT - Using 'with' you don''t need to explicitly call 'close' # with open('myfile', 'r') as file_handle: # for line in file_handle.readlines(): # do_something(line): # ## 4 Control Structures # ### 4.1 Don't compare boolean values to True or False using == # # WRONG # if condition == True: # if condition is True: # # # CORRECT # if condition: # In[21]: # Remember that empty strings, lists or tuples are false mylist = [1, 2, 3] if mylist: print('There is something to do!') # ### 4.2 Avoid placing conditional branch on the same line as the colon # # WRONG # if condition: print (something) # # # CORRECT # if condition: # print (something) # ### 4.3 Comparisons to singletons like None should always be done with is or is not. # In[22]: # WRONG mytest = None if mytest == None: print('This is wrong') # CORRECT if mytest is None: print('This is correct') # ### 4.4 Avoid repeating variable name in compound if Statement # In[23]: a = 'two' # WRONG if a == 'one' or a == 'two' or a == 'three': print("This works but it's wrong") # CORRECT if a in ('one', 'two', 'three'): print('This is correct!') # ### 4.5 Use list comprehensions to create lists that are subsets of existing data # List comprehensions, when used judiciously, increase clarity in code that builds a list from existing data. Moreover list comprehensions can speed-up the code. # In[24]: # WRONG origin = range(1, 100) mylist = list() for item in origin: if not item%5: mylist.append(item+0.1) # CORRECT mylist = [item+0.1 for item in origin if not item%5] # ### 4.6 Indexes in for Loops # Programmers coming from other languages are used to iterate over a container by accessing elements via index. Python's **in** keyword handles this gracefully. # In[25]: mylist = ['a', 'b', 'c', 1, 2, 3] # WRONG index = 0 while index < len(mylist): print((mylist[index]), end=''), index+=1 print('\n') # CORRECT for item in mylist: print(item, end='') # In[26]: # CORRECT - When the index is needed for any reason, use 'enumerate' for index, item in enumerate(mylist): print(index, item, ' -- ', end='') # ### 4.7 `range` and `xrange` # In Python e3 `range()` now behaves like `xrange()` used to behave, except it works with values of arbitrary size. The latter no longer exists. # In[27]: # IN PYTHON 3 THIS IS CORRECT sum1 = 0 for x in range(5000*5000): sum1 = sum1+x print('Sum1: {0:,d}'.format(sum1)) # --- # # Visit [www.add-for.com]() for more tutorials and updates. # # This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.