Python (2018)
As ever, the notes are revision and cribsheet notes taken from the other sources. None of it is mine, but its a quick reminder.
Notes from : https://docs.python.org/3/contents.html
Python 3.6.4
and some comments from using it.
Duck typing
It’s finally time to return to duck typing. So here goes.
If it quacks like a duck it is one. ie typeless languages.
i=1 # Looks like an int to me s='guess' # String
Python Versions
Python 3 is better, but Python 2 is backed into Linux and many systems, so bad luck you. They are not compatible.
Modules and packages
Modules are files, packages are directories containing a special file called
__init__.py
REPL and running
python -c command [arg] python -m module [arg] python -i -m module [arg] # interactive mode
Script name of - means stdin. Access to args is via sys.argv[0] etc
Garbage collection
There is a background thread doing reference counts to remove zero reference variables. You can also delete yourself using
del a
Format
Python uses white space and indentation rather than brackets. Read pip8 before you type anything, and pycharm IDE with inspect will help you.
The world of python
Things to read about, are venv, PyPI, wheels, anaconda, miniconda, pip, pycharm, pyTest, tox
Basically, its as wide and deep as any other tech stack. Sorry.
multiple assignment
a, b = 0,1
Strings
s1 = 'I am a string' s2 = "I am a string" s3 = '"I contain quotes"' s4 = "'I contain aspostrophe's'" s5 = r'Use r for a raw string, so this \n stays unchanged' s6 = '''A multiline string''' s7 = """Another multiline string""" s8 = 'a ' 'concatinated ' 'string' # Strings next to each other are concatinated s9 = 'word'
Sequences
Strings are sequences
s9[0] # w s9[-1] # d Use - to index from the end s9[0:2] # wo This is slicing s9[1:] # ord Slice with default end s9[:2] # wo Slice with default start
Other common sequence operations
len(s9) # calls convention dunder function __len__
Lists
Are mutable - can be changed.
squares = [1,4,9] squares[0] squares[-1] # last item squares[-3:] # Slicing is oK squares[:] # Shallow copy, also works on strings...and sequences in general squares + [16, 25] # Concatination squares[3] = 9 # mutable - replace values squares[0:3] = [1,2,3] # Assign to slices squares[0:3] = [] # remove slices squares[:] = [] # clear squares.append[16] # is more efficient than squares = squares + [16]
Other useful operations:
append, extend, remove, pop, clear, index, count, sort, reverse, copy del a[0] # remove an element at index location del a[2:4} del a[:] del a # delete the entire variable
Lists have the map and filter functions (as well as others)
l2 = list(filter(lambda x: x==4, squares)) new_list = list(map(lambda x: x*2, squares))
Generators
def reverse(data): for index in range(len(data)-1, -1, -1): yield data[index]
Each time the generator is called it continues from where it left off. This is the yield keyword.
Operations
2**2 # 2 to the power of 2 _ # In interactive mode this is the previous result, so you can use it like a calculator
Printing
print('The value is', i, end='!') # end means change the end char from \n
If you have a class you can determine two formats by implementing:
str() # produces human readable format repr() # output for the interpreter - or syntax error if none
Other useful formatting functions are:
str="foo" print("[",str.rjust(10),"] [",str.ljust(10),"] [",str.center(10),"] [",str.zfill(10),"]")
format
You can use format to replace format fields by index
foo="foo" print("Hi {0}, you owe {1:.3f}".format(foo, 0.1))
If
if ok in ('y','ye','yes): print('OK') elif x==0: # can have multiple elif. print('zero') else: # else is optional; print('stupid example')
for and generators using range
for n in squares: print(n) # If altering an array, then copy it first for n in squares[:]: squares[1]= n**n +1 # Sorry, its a stupid example for i in range(5): # generates an arithmetic progression print(i) range(5,10) # 5 through to 9 range(0,10,2) # 0, 3, 6, 9 # To iterate over indexes in a sequence for i in range(len(squares)): print(i, squares[i]) # range is an object, not a list list(range(5)) # use range to generate a list
for and break
for n in range(2,10): for x in range(2, n): if n%x==0: print(n, ' equals ', x, '*', n//x) # n//x returns an int. n/x returns float break # leave the loop else: print(n, ' is a prime number') # loop fell through
Continue
for num in range(2,10): if num%2==0: print('Found an even number ', num) continue print('Number ',num)
pass
Does nothing useful, its a placeholder saying you will come back to it
class MyEmptyClasss: pass
Functions
No camel case for functions, but do use them for classes.
def fib(n): """Print stuff""" # If first line is a string then its a doc string. # Example with default values def ask_ok(prompt, retries=4): pass
Nested functions can reference variables from the enclosing scope
Functions can have annotations which are referenced via an attribute called annotations_
All functions return a value, None is built in.
Keyword arguments
This shows a call with a named (keyword) argument being given a value.
ask_ok('Hi', retries = 6)
Dictionary and variadic parameters
Variable length arguments (arbitary args) are taken as *args. This is a tuple holding all the args which are not named using a keyword.
Dictionary argumnents - ie keyword=value are taken as **kwords.
def foo(*args, **key_word_args): pass
Unpacking
args = [3,6] list(range(*args)) # ie range takes two params, and *args unpacks into the args # Can also unpack dictionaries into key word (named) arguments def foo(v, s): pass d = {'v':'four', 's':'bleed'} foo(**d)
Lambda expressions
Lambda is a keyword, syntactic sugar for a function definition.
d = lambda x: x*2 print(d(5))
Also useful for lists filter and map
l2 = list(filter(lambda x: x==4, squares)) new_list = list(map(lambda x: x*2, squares))
Documentation strings
Can access the doc string using foo.doc
They are right after a class or a function defn. Format as below
""""Do Something Stuff """
List comprehensions
squares=[x**2 for x in range(10)]
Tuples
are immutable.
t= 1,2,3 t1=t, (1,2,3) t2="Single item", # The trailing comma means this is a tuple. t3 = () #empty
Dictionary
d = {} d1 = ("Jack": 4098, "sape": 4139) d1["Jack"] # accesses value dict( [('J',1), ('K',2)] )
Modules
Any file is a module, eg fib.py
python fix.py args
Make it executable by adding this at the end of the file
if __name__ == "__main__": import sys fib(int(sys.argv[1]))
Lots of hooks into the code, for example
import sys dir(sys) # lists all the names a module defines
File access
Good practice to use the with form as it will ensure resources are closed even if there is an exception
with open('workfile') as f: read_data = f.read()
There are built in formats for json and pickle (pickle is a python only format)
Google them : json.dump, json.load
Exceptions
try : #if no issues here then except is skipped except ValueError: #if exception is ValueError then gthis is run
Or
try : #if no issues here then except is skipped except (RuntimeError, TypeError, NoneError): #if exception is any of these then gthis is run
and
raise #Raising (throwing...java, hey ho) an exception
also
try : # except Exception as inst: # inst is now the exception else : # executes if no except finally : # at the end, exception or not
Nested directory structure
Create packages, in each dir you need
__init__.py
so that python knows its a python package dir.
When import you can do:
from path.topackage import common
You can have a list in
__init__.py
called
__all__
to allow a wild card import, but that is considered bad form.
# Dont use it, even though it works from path.topackage import *
Namespaces
You can define things as nonlocal and global if you want to make your code hard to understand.
Classes
Python isn’t Java, Scala, C# or C++…etc. But, hey, here goes.
class MyClass : """A simple class""" i=1234 #Class variable shared by all instances def __init__(self): # Constructor self.whatever="foobar" def f(self): # all functions get self as first param self.data=[] # create a new member variable
A class is basically a namespace bound to the class name.
Method objects are part of the class. Function objects are part of the class instance.
Class type is stored in
object.__class__
You can do multiple inheritance, search is depth first, left to right. If it finds duplicates then it uses the first one it finds.
class DerivedClass(Base1, Base2, Base3):
__name
Anything that starts __ should not be considered part of the public API and is subject to change. Have at most one _ trailing, the name will be mangled.
You can then keep a reference to your private function object, so if its overridden you still call your copy.
class Mapping: ... def update(self, iterable): for item in iterable: self.items_list.append(item) __update = update # private copy of original update() method
Libraries
Nice simple language, but now you have to learn all the libraries too.
eg
glob.glob(ospath.join('mydir', 'subdir', '*.html')) os.listdir(os.path.join('mydir','subdir'))
Project structure
You could use one that is compatible with DistUtils, PyTest and tox, or you could just hack.
You could in fact not bother at all and ship jupiter notebooks.
miniconda
This is a packaged python environment. Download it, and then open the anaconda prompt.
conda create -n firstenv activate firstenv conda install pandas # eg of using with azure cloud pip install azure-cli az login