The book for this section of the course is Mark Pilgram’s “Dive into Python 3”. The full book is available online at http://www.diveintopython3.net/
My lecture notes (including source) and code examples are available at https://github.com/mlavin/lecture-notes
You use Linux or a Mac then you probably already have Python 2.7 but you'll probably want a more recent version
For Mac I suggest pyenv or Homebrew
If you use Windows you can download an executable installer from Python.org
4th on the TIOBE Index as of Feb 2018 below Java, C, and C++
Companies like:
Read more: http://www.python.org/about/success/
# %load ../code/hello.py
# hello.py
print('Hello, World')
Hello, World
# %load ../code/fibonacci.py
def fibonacci(n):
if n <= 2:
return 1
else:
return fibonacci(n - 1) + fibonacci(n - 2)
for i in range(1, 15):
print(fibonacci(i))
1 1 2 3 5 8 13 21 34 55 89 144 233 377
Python was created with the idea that most code will be read more times than it’s written.
Whitespace is meaningful for seperating code blocks without the use of braces.
The pass
statement can be used to hold an empty logical or function block.
The convention is to use 4 spaces per indention and you cannot mix tabs and spaces.
Suggested max line length is 79 characters. Backslash is a line continuation character but lines can also be extended with parentheses.
def my_long_function(arg1, arg2, optional_arg1="fizz",
optional_arg2="buzz", optional_arg3="done"):
pass
You can read the full style guide online http://www.python.org/dev/peps/pep-0008/
import this
The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than *right* now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let's do more of those!
Functions are declared with the def
keyword:
def my_function():
pass
Arguments can given starting with required then optional:
def short_name(first_name, last_name="Smith"):
return "%s %s" % (first_name[0], last_name)
Notice that the arguments do not declare their type.
Python is dynamically typed meaning you do not need to declare the types of your variables before using them. The variable type is determined when the program is executed.
Python is strongly typed meaning that type is enforced.
a = 1 # a is now an integer
b = '2' # b is now a string
a + b # this will fail
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-10-77cf1aad6cf7> in <module>() 1 a = 1 # a is now an integer 2 b = '2' # b is now a string ----> 3 a + b # this will fail TypeError: unsupported operand type(s) for +: 'int' and 'str'
str(a) + b
'12'
New in Python 3.5 - (PEP484)[https://www.python.org/dev/peps/pep-0484/]
You can annotate your functions with the types they take/return
def short_name(first_name: str, last_name="Smith": str) -> str:
return "%s %s" % (first_name[0], last_name)
This can help document your code but this isn't enforced at runtime.
Everything has:
Great expanation of Python Object model: http://www.effbot.org/zone/python-objects.htm
import math
math.sqrt(4)
2.0
math.sqrt.__doc__
'sqrt(x)\n\nReturn the square root of x.'
# %load ../code/fibo2.py
import time
def fibonacci(n):
if n <= 2:
return 1
else:
return fibonacci(n - 1) + fibonacci(n - 2)
start = time.time()
fibonacci(25)
time.time() - start
0.11204242706298828
# %load ../code/fibocache.py
import time
def fibonacci(n):
if hasattr(fibonacci, '_%s' % n):
return getattr(fibonacci, '_%s' % n)
if n <= 2:
value = 1
setattr(fibonacci, '_%s' % n, value)
return value
else:
value = fibonacci(n - 1) + fibonacci(n - 2)
setattr(fibonacci, '_%s' % n, value)
return value
start = time.time()
fibonacci(25)
time.time() - start
0.00019669532775878906
fibonacci._10
55
fibonacci._11
89
import math
def do_math(f, x):
print(f(x))
y = math.sqrt
do_math(y, 10)
y = math.log
do_math(y, 10)
3.1622776601683795 2.302585092994046
import math
math.log(10)
2.302585092994046
def new_log(x):
return 5
math.log = new_log
math.log(10)
5
Many of the same operators you know and love from C:
# add, subtract, multiply, divide
a + b, a - b, a * b , a / b
# exponentiation, floor divide, modulo
a ** b, a // b, a % b
# bitwise inverse, left bit shift, right bit shift
~a, a << b, a >> b
# bitwise and, bitwise or, bitwise xor
a & b, a | b, a ^ b
Most will be familiar:
# less than, less equal, greater than, greater equal
a < b, a <= b, a > b, a >= b
# equal, not equal, object identity, object identity negation
a == b, a != b, a is b, a is not b
# collection membership, collection membership negation
a in b, a not in b
# logical and, logical or, logical negation
a and b, a or b, not a
The basic flow control statements should also look familiar from C though the syntax is slightly different.
if, else, for, while
The same as with functions there are no braces to define the logical blocks. Instead everything is defined by the whitespace indention.
The if
statement defines a control block which will only execute when a logical statement is true. This can be paired with an else
statement to define how to handle the false case. To avoid deep nesting you can also use elif
statement.
if x > 100:
print("That's a lot!")
elif x > 10:
print("That's ok.")
else:
print("That's all you've got?")
The for
statement is used to loop through any iterable. This includes lists and strings. User defined type can also have the ability to be iterated by defining the iteration protocol.
for x in [1, 2, 3]:
print(x)
You can use the enumerate function to add the current index.
for i, c in enumerate("blip"):
print("Character %s is %s" (i, c))
range
allows you to generate a sequence of integers between a particular range. It starts at zero and increases by one but those are available arguments.
for i in range(5):
print(i)
0 1 2 3 4
for i in range(1, 5):
print(i)
1 2 3 4
for i in range(1, 5, 2):
print(i)
1 3
for name in ['Newton', 'x', 'Euler']:
if 'x' in name:
continue
else:
print(name)
for name in []:
print("Names were given.")
else:
print("No names were given.")
Newton Euler No names were given.
In addition to the for
loop there is also the while
loop. The while
loop will continue until a particular logical statement is false.
x = 10
while x > 5:
x -= 1
pass
is a special keyword in Python that does nothing. It can be used to fill a control block or a function or a class definition.
Python comments are denoted with the #
character. While not techinally a comment you can also use triple quoted strings as a multi-line comment. This is the style used to define doc strings previously discussed.
# My Comment
"""
This is a longer comment.
Blah blah blah.
Though technically it's a string literal.
"""
Python modules are collections of Python statements. They stored in text files with the .py extension. The module name is the same as the file name without the extension.
When you pass a module to the interpreter such as python hello.py
the module name changes from hello
to __main__
. You can use this fact to handle the case where the module is executed differently than when the module is imported.
if __name__ == "__main__":
print("I am a script.")
else:
print("I am a module.")
We’ve already seen some import statements but there are three styles of Python imports.
# Add a reference to the module
import X
# Creates references to all public objects in X
from X import *
# Creates refernces to the names a, b, c
from X import a, b, c
# Add a reference to the module
X = __import__('X')
Where does Python look for modules to import? The Python path.
This is defined by the PYTHONPATH
environment variable in your shell.
import sys
sys.path
['', '/home/mark/.virtualenvs/lectures/lib/python36.zip', '/home/mark/.virtualenvs/lectures/lib/python3.6', '/home/mark/.virtualenvs/lectures/lib/python3.6/lib-dynload', '/usr/lib/python3.6', '/home/mark/.virtualenvs/lectures/lib/python3.6/site-packages', '/home/mark/.virtualenvs/lectures/lib/python3.6/site-packages/IPython/extensions', '/home/mark/.ipython']
When Python imports a module, it first checks the module registry (sys.modules
) to see if the module is already imported. If that’s the case, Python uses the existing module object as is.
Otherwise, Python does something like this:
sys.modules
dictionaryimport math
dir(math)
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']
help(math)
Help on built-in module math: NAME math DESCRIPTION This module is always available. It provides access to the mathematical functions defined by the C standard. FUNCTIONS acos(...) acos(x) Return the arc cosine (measured in radians) of x. acosh(...) acosh(x) Return the inverse hyperbolic cosine of x. asin(...) asin(x) Return the arc sine (measured in radians) of x. asinh(...) asinh(x) Return the inverse hyperbolic sine of x. atan(...) atan(x) Return the arc tangent (measured in radians) of x. atan2(...) atan2(y, x) Return the arc tangent (measured in radians) of y/x. Unlike atan(y/x), the signs of both x and y are considered. atanh(...) atanh(x) Return the inverse hyperbolic tangent of x. ceil(...) ceil(x) Return the ceiling of x as an Integral. This is the smallest integer >= x. copysign(...) copysign(x, y) Return a float with the magnitude (absolute value) of x but the sign of y. On platforms that support signed zeros, copysign(1.0, -0.0) returns -1.0. cos(...) cos(x) Return the cosine of x (measured in radians). cosh(...) cosh(x) Return the hyperbolic cosine of x. degrees(...) degrees(x) Convert angle x from radians to degrees. erf(...) erf(x) Error function at x. erfc(...) erfc(x) Complementary error function at x. exp(...) exp(x) Return e raised to the power of x. expm1(...) expm1(x) Return exp(x)-1. This function avoids the loss of precision involved in the direct evaluation of exp(x)-1 for small x. fabs(...) fabs(x) Return the absolute value of the float x. factorial(...) factorial(x) -> Integral Find x!. Raise a ValueError if x is negative or non-integral. floor(...) floor(x) Return the floor of x as an Integral. This is the largest integer <= x. fmod(...) fmod(x, y) Return fmod(x, y), according to platform C. x % y may differ. frexp(...) frexp(x) Return the mantissa and exponent of x, as pair (m, e). m is a float and e is an int, such that x = m * 2.**e. If x is 0, m and e are both 0. Else 0.5 <= abs(m) < 1.0. fsum(...) fsum(iterable) Return an accurate floating point sum of values in the iterable. Assumes IEEE-754 floating point arithmetic. gamma(...) gamma(x) Gamma function at x. gcd(...) gcd(x, y) -> int greatest common divisor of x and y hypot(...) hypot(x, y) Return the Euclidean distance, sqrt(x*x + y*y). isclose(...) isclose(a, b, *, rel_tol=1e-09, abs_tol=0.0) -> bool Determine whether two floating point numbers are close in value. rel_tol maximum difference for being considered "close", relative to the magnitude of the input values abs_tol maximum difference for being considered "close", regardless of the magnitude of the input values Return True if a is close in value to b, and False otherwise. For the values to be considered close, the difference between them must be smaller than at least one of the tolerances. -inf, inf and NaN behave similarly to the IEEE 754 Standard. That is, NaN is not close to anything, even itself. inf and -inf are only close to themselves. isfinite(...) isfinite(x) -> bool Return True if x is neither an infinity nor a NaN, and False otherwise. isinf(...) isinf(x) -> bool Return True if x is a positive or negative infinity, and False otherwise. isnan(...) isnan(x) -> bool Return True if x is a NaN (not a number), and False otherwise. ldexp(...) ldexp(x, i) Return x * (2**i). lgamma(...) lgamma(x) Natural logarithm of absolute value of Gamma function at x. log10(...) log10(x) Return the base 10 logarithm of x. log1p(...) log1p(x) Return the natural logarithm of 1+x (base e). The result is computed in a way which is accurate for x near zero. log2(...) log2(x) Return the base 2 logarithm of x. modf(...) modf(x) Return the fractional and integer parts of x. Both results carry the sign of x and are floats. pow(...) pow(x, y) Return x**y (x to the power of y). radians(...) radians(x) Convert angle x from degrees to radians. sin(...) sin(x) Return the sine of x (measured in radians). sinh(...) sinh(x) Return the hyperbolic sine of x. sqrt(...) sqrt(x) Return the square root of x. tan(...) tan(x) Return the tangent of x (measured in radians). tanh(...) tanh(x) Return the hyperbolic tangent of x. trunc(...) trunc(x:Real) -> Integral Truncates x to the nearest Integral toward 0. Uses the __trunc__ magic method. DATA e = 2.718281828459045 inf = inf nan = nan pi = 3.141592653589793 tau = 6.283185307179586 FILE (built-in)
dir(__builtin__)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '__IPYTHON__', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'display', 'divmod', 'enumerate', 'eval', 'exec', 'filter', 'float', 'format', 'frozenset', 'get_ipython', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
Built-in data types.