(Home)
Welcome to this introductory course in the Python programming language!
This course will take you through the basics of Python and hopefully demonstrate it to be a powerful, intuitive, and generally useful means of programming.
It's intended to be suitable for novice programmers while still being useful for those with previous experience of other languages, or even of python itself.
This course is presented in the form of a Jupyter notebook, which gives full access to the interactive python interpreter. We'll actually be running real python code as we go through the lectures.
All the material is available online, in static form. You can also download the source. If you then follow these Jupyter installation instructions you can use the interactive form of the notes. I encourage you to do so, and, if you have a laptop, follow the material interactively during the lectures, play about, and ask questions as we go.
There will be 4 lectures and 2 hands-on sessions:
The lectures are webcast and recordings are accessible through MySUPA.
The lab sessions allow you to work through examples, experiment with Python, and discuss any queries with me and fellow students.
You can also get help setting up python and Jupyter on your laptop/desktop.
Hit
class.Hit
has a 3D position which is saved in x
, y
, & z
attributes.Track
object has as its attributes a set of Hit
instances as well as an origin point (x
, y
, z
) and gradients tx
& ty
. These are calculate from a straight line fitted to the set of hits.Track
class has add_hit
and remove_hit
member methods to add or remove Hit
instances from its set, and an update_direction
method to recalculate the track origin & gradient from the set of Hit
instances.Hit
and Track
, depending on which subdetector they're from, but they all have the same interface (through their member functions).Hit
class. update_direction
method in Track
could be modified to take into account these uncertainties in finding the best-fit trajectory.In a jupyter notebook, an interpreter cell looks like this:
print("Hello World!")
Hello World!
Here's your first python function: "print", which converts objects to text and outputs them to the console.
You can pass several arguments to print
by separating them with commas within the brackets, then they're printed on the same line with spaces between them:
print(1, 2, 3)
1 2 3
"Hello World!"
'Hello World!'
10+3
13
2**10
1024
# A hash symbol precedes a comment, which is ignored
# by the interpreter, so this does nothing.
# Comments are just used to annotate code to explain
# the code to future readers
All the standard operators are available:
+ add
- subtract
* multiply
/ divide
// divide and round down
% remainder
** exponentiate
As said, the interactive prompt is handy as a simple calculator:
# Addition
2+2
4
# Division
3/2
1.5
# Floor division
3//2
1
-3/2
-1.5
-3//2
-2
# The usual operator precedence applies (BODMAS)
1 + 2 * 3
7
# As do parenthesis rules
(1 + 2) * 3
9
# Remainder
15 % 10
5
# Remainder also works on numbers with decimal points,
# but always be careful of rounding errors!
print(5.4 % 2)
1.4000000000000004
# Exponentiate
(6-2)**2
16
# At the interactive prompt the last value that was
# output is assigned to the variable "_", which can
# be useful for repeated calculations.
_
16
_ + 7.5
23.5
_ * 1.204
28.294
_
" only exists at the interactive prompt, and not in scripts.This allows you to create named variables with given values rather than just using fixed values.
You then use the name of the variable in place of the value in calculations and can assign new variables from the values of those calculations.
# As simple as this, no type declaration is needed. Just name the
# variable and give it a value with =.
width = 5
length = 2
area = width * length
area
10
This is particularly relevant when writing functions for repeated operations where the input values are provided by the user.
Functions are defined with the def
keyword and the return value with the return
keyword:
# Put the calculation above into a function:
def get_area(width, length):
return width * length
Then call the function similarly to print
by passing arguments in brackets and assign a variable from its return value:
area = get_area(5, 2)
print(area)
10
# You can pass named variables as arguments to functions
w = 6.5
l = 12.6
area = get_area(w, l)
print(area)
81.89999999999999
More on functions later.
# You can assign variables from other variables.
area2 = area
area2
81.89999999999999
# The same value can be assigned to several variables simultaneously
# like this:
x = y = z = 0.
x, y, z
(0.0, 0.0, 0.0)
# Or to give different values separate them with commas
x, y, z = 1, 2, 3
x, y, z
(1, 2, 3)
# You can delete a variable with the del keyword
del x
import keyword
print(keyword.kwlist)
['False', 'None', 'True', '__peg_parser__', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
import
is another keyword.# If you try to access a variable that doesn't exist,
# you get an exception.
x
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-1-295c1a8712a5> in <module> 2 # you get an exception. 3 ----> 4 x NameError: name 'x' is not defined
# If you try to use a keyword as a variable name,
# you also get an exception
del = 1
File "<ipython-input-1-db9bc4af240c>", line 4 del = 1 ^ SyntaxError: invalid syntax
There're a few basic types of object in python (and most programming languages) on top of which arbitrarily complex algorithms can be built.
# A number without a decimal point is an integer,
# (a whole number or "int")
x = 123
# You can check the type of any variable using the "type" function.
# As seen with "print", a function is called (excuted) using
# brackets which contain the arguments that're passed to the function.
print(x)
print(type(x))
123 <class 'int'>
Python can interpret integers in any basis. There're a few standard ones with special syntax:
# A 0o prefix causes a number to be interpreted as an octal number,
# though it's converted to base 10 and stored as a regular int.
x = 0o10
print(x)
print(type(x))
8 <class 'int'>
# Similarly for hexidecimal numbers prefix with 0x
x = 0xF
print(x)
print(type(x))
15 <class 'int'>
# Or for binary, use 0b.
x = 0b10
print(x)
print(type(x))
2 <class 'int'>
Numbers with a fractional part are known as "floating point" numbers, or floats.
# Anything with a decimal point or in scientific notation is a float.
# In python all floats are "double" precision (normally 16 d.p.),
# "single" precision float (as in some other languages) doesn't exist
x = 123.
print(x, type(x))
123.0 <class 'float'>
# Scientific notation can use "e" or "E" and makes a float
x = 1e6
print(x, type(x))
1000000.0 <class 'float'>
Python also has a builtin complex number class.
# "j" or "J" is valid to give the imaginary part
x = 1 + 2j
print(x, type(x))
(1+2j) <class 'complex'>
# You can also use the complex class constructor,
# which is called like a function with the real
# and imaginary parts as arguments.
x = complex(3, 4)
print(x, type(x))
(3+4j) <class 'complex'>
# Real and imaginary parts are stored as floats.
# Access member "attributes" of an object with '.'
print(x.real, type(x.real))
print(x.imag, type(x.imag))
3.0 <class 'float'> 4.0 <class 'float'>
# Also use '.' for member functions.
# You need brackets following a function in order
# to call (execute) it, even if there are no
# arguments.
y = x.conjugate()
print(y, type(y))
print(x + y)
(3-4j) <class 'complex'> (6+0j)
real
and imag
), which contain the data for the object.conjugate
), which can access, modify or perform other operations on the attributes.complex
class describes the structure for complex numbers: every instance has a value for the real
and imag
attributes, can call methods like conjugate
, and perform basic numerical operations.True
or False
.# Boolean types start with capital letters
x = True
y = False
print(x, type(x))
print(y, type(y))
True <class 'bool'> False <class 'bool'>
# Particularly relevant for comparisons
# Check if variables have the same value with ==
a = 1
b = 0
c = 1
print(a==c)
print(a==b)
True False
# You can also assign from comparisons
x = (a==c)
print(x, type(x))
True <class 'bool'>
Other comparison operations include:
>
>=
<
<=
!=
More info here.
# Booleans can be combined using 'and' or 'or'
x = 123.
print(x > 100 and x < 200)
print(x < 100 or x > 200)
True False
# They can be inverted with 'not'
print(not (x > 100 and x < 200))
False
and
or or
statements can be strung together.and
operations have higher precedence than or
operations (and
operations are evaluated first).print
something, it's converted to a string (if it isn't one already).# We already saw a string in 'Hello world!'
# Strings are enclosed by quote marks.
# They can be defined using single or double quotes
# (open and close quotes must be the same)
name = 'Sir Gallahad'
print(name)
Sir Gallahad
name = "Brave Sir Robin"
print(name)
Brave Sir Robin
# A string can contain quotation marks.
# If they're the same as the enclosing quotation marks they need to be
# "escaped" with a backslash, if they're different they don't need to
# be escaped.
"He's running away"
"He's running away"
'He\'s chickening out'
"He's chickening out"
# You can continue a string onto the next line with a backslash
lyric = 'Brave Sir Robin \
ran away'
lyric
'Brave Sir Robin ran away'
# Multi-line strings use triple quotes - can also use '''
lyric = """Boldly ran
away
away ..."""
# \n is the newline character
lyric
'Boldly ran\n away\n away ...'
# Spaces at the start of lines are kept
print(lyric)
Boldly ran away away ...
# If not assigned to a variable (and not the only thing in a script)
# a multi-line string can be used as a multi-line comment - python
# ignores it and not allocate any memory to it.
'''This is a
multi-line comment'''
# In a Jupyter notebook, there has to be something else in the cell
# for the string to be interpreted as a comment.
lyric = ''
# You can concatenate strings with +
'Spam ' + 'and eggs'
'Spam and eggs'
# You can optionally omit the + as python implicitly concatenates
# two strings declared side-by-side (the case above is explicit
# concatenation).
'Spam ' 'and eggs'
'Spam and eggs'
# This provides another way of writing a string across
# several lines, which can make code easier to read.
menu = ('Spam, spam, spam, spam, spam, spam, spam,'
' and eggs')
print(menu)
Spam, spam, spam, spam, spam, spam, spam, and eggs
# You can also multiply strings by integers
'Spam ' * 3
'Spam Spam Spam '
# Strings have lots of member methods, eg, make all
# letters uppercase.
menu = 'Spam and eggs'
menu.upper()
'SPAM AND EGGS'
# Note that these methods return new strings, and don't
# change the original.
# The replace method replaces a substring for another.
menu2 = menu.replace('eggs', 'spam')
menu2
'Spam and spam'
# The original string is unchanged
menu
'Spam and eggs'
# You can access single characters in a string using indexing
# with square brackets.
# Access the 4th character from the start (indices start at 0)
menu[3]
'm'
# Python also allows negative indices, which count from the end
# of the string (or other indexable object).
# eg, access the 4th character from the end:
menu[-4]
'e'
# You can also access slices of a string like so:
menu[1:3]
'pa'
# Omitting the first index is equivalent to it being 0
menu[:3]
'Spa'
# Omitting the second index is the same as it being equal to
# the number of characters in the string.
menu[3:]
'm and eggs'
# So this returns the original string:
menu[:3] + menu[3:]
'Spam and eggs'
# Negative indices are also allowed when slicing.
# They count backwards from the end.
# This gives the last 3 characters:
menu[-3:]
'ggs'
# This gives everything but the last 3 characters.
menu[:-3]
'Spam and e'
# If the index range is negative, or beyond the length of
# the string, you get an empty string.
menu[10:2]
''
menu[23:45]
''
# You can use the 'in' keyword to check if a string
# contains a character or substring.
print('m' in menu)
print('Spam' in menu)
print('spam' in menu)
True True False
format
member method of a string, expressions in braces {}
are replaced with the arguments of format
.# No flags: the braces are replaced with string versions
# of the format arguments.
print('Result: {} +/- {}'.format(1.435, 0.035))
Result: 1.435 +/- 0.035
# If you put indices in the curly brackets they're replaced by the
# argument of the same index. Indices count from zero.
# This is particulary useful if you use an argument more than once.
print('{0} and {1} and {0}'.format('spam', 'eggs'))
spam and eggs and spam
print('Result: {:8.2f} +/- {:4.2f}'.format(1.435, 0.035))
Result: 1.44 +/- 0.04
# Formatting flags can be combined with indices in front of the
# colon.
print('Result: {1:8.2f} +/- {0:4.2f}'.format(0.035, 1.435))
Result: 1.44 +/- 0.04
# Alternatively, you can use 'keywords' to label the arguments
# rather than indices.
print('Result: {value:8.2f} +/- {error:4.2f}'.format(value = 1.435,
error = 0.035))
Result: 1.44 +/- 0.04
# You don't need to format a string at initialisation. The format method
# actually returns a new string, which you can assign to a new variable.
genericResult = 'Result: {:8.2f} +/- {:4.2f}'
result1 = genericResult.format(3.2432, 0.2234)
result2 = genericResult.format(2.8982, 0.0879)
print(genericResult)
print(result1)
print(result2)
Result: {:8.2f} +/- {:4.2f} Result: 3.24 +/- 0.22 Result: 2.90 +/- 0.09
rjust
, ljust
, center
, rstrip
, lstrip
, zfill
...None
is the null type, and is useful for comparisons, as a default value for something that may be assigned later, a return value in the event of a failure, or various other applications.
result = None
print(result)
print(result==None)
None True
result = 10.
result==None
False
a = 1
print(a, type(a))
a = 'spam'
print(a, type(a))
1 <class 'int'> spam <class 'str'>
# Everything can be converted to a string in some way, using str(), this
# is done when an object is printed.
str(123), str(True), str(4.), str(None)
('123', 'True', '4.0', 'None')
# Many things can also be converted to ints.
# When converting floats to ints, the fractional part is just
# discarded (it doesn't round down)
print(int('1'))
print(int(4.6), int(-4.6))
print(int(True), int(False))
print(int(1e12))
1 4 -4 1 0 1000000000000
# When casting from string to int you can define the base to
# use by passing a second argument to int()
print(int('11'), int('11', 8), int('11', 2))
11 9 3
# Hexadecimal notation is also allowed.
print(int('F', 16))
15
# Some strings can't be interpreted as ints though, and then int() raises
# an exception.
int('spam')
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-1-80eca41878a9> in <module> 2 # an exception. 3 ----> 4 int('spam') ValueError: invalid literal for int() with base 10: 'spam'
# Casting to float works similarly.
print(float(123))
print(float('34.2'))
print(float(True), float(False))
123.0 34.2 1.0 0.0
# And fails under similar conditions.
float('eggs')
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-1-2cb4b6574388> in <module> 1 # And fails under similar conditions. 2 ----> 3 float('eggs') ValueError: could not convert string to float: 'eggs'
# The complex class can also cast from strings.
complex('1+2j')
(1+2j)
# The default bool is False.
# Casting None to a bool gives False.
# Any non-zero number is cast to a bool as True.
print(bool())
print(bool(None))
print(bool(0), bool(1))
print(bool(23.2), bool(-6), bool(3.3+5.4j), bool(0 + 0j))
False False False True True True True False
# Any non-empty string (or other iterable object) is also cast to True,
# regradless of content.
print(bool(''))
print(bool('spam'), bool('True'), bool('False'))
False True True True
if
statement allows you to evaluate a boolean expression and perform certain actions accordingly.:
and then an indented block of code which is evaluated if the boolean evaluates to True
.elif
statements, and finally an optional else
statement, each with their own boolean expression and indented block of code.True
. False
then the optional else
block is evaluated.yesNo = True
if yesNo:
print('Yes')
else:
print('No')
Yes
x = 10
if x < 0:
print('Negative')
elif x == 0:
print('Zero')
else:
print('Positive')
Positive
and
and or
.x = 3456.
if x > 2000. and x < 4000.:
print('x is in the signal region')
elif x < 1000. or x > 5000.:
print('x is in the background region')
x is in the signal region
:
is (almost) always followed by an increase in indentation.x = -324
if x < 0 :
if x < -100 :
print('x < -100')
else :
print('-100 <= x < 0')
x < -100
# Eg, using 2 spaces.
x = 1e6
if x < 0 :
print('Negative')
elif x == 0 :
print('Zero')
else :
print('Positive')
Positive
{ ... }
, rather than just using whitespace, but to get the developers' opinion just try from __future__ import braces
and
import this
def
keyword followed by the name of the function.# Put "Hello world!" into a function.
# It doesn't take any arguments.
def hello_world() :
print('Hello world!')
# Then call it - remember the brackets even if
# there are no arguments
hello_world()
Hello world!
return
keyword.# A simple function with two arguments.
def sum_of_squares(x, y) :
return x**2 + y**2
# Call the function & assign a variable from its
# return value
a, b = 2, 3
c = sum_of_squares(a, b)
print(c)
13
# A function with no return value actually returns None
var = hello_world()
print(var)
Hello world! None
print(type(sum_of_squares))
radius_sq = sum_of_squares
print(radius_sq == sum_of_squares)
<class 'function'> True
# Call the variable assigned to the function just
# as you do the original function.
x = radius_sq(1, 2)
print(type(x))
x = radius_sq(3, 4.)
print(type(x))
x = radius_sq(3+4j, 6.)
print(type(x))
<class 'int'> <class 'float'> <class 'complex'>
def fibonacci(n) :
if n < 3 :
return 1
return fibonacci(n-1) + fibonacci(n-2)
# When printing, the default value of 'end' is '\n',
# so each call to print outputs on a new line.
# Using end=' ' means they're printed on the same
# line with spaces between them.
print(fibonacci(1), end=' ')
print(fibonacci(2), end=' ')
print(fibonacci(3), end=' ')
print(fibonacci(4), end=' ')
print(fibonacci(5), end=' ')
1 1 2 3 5
# If you induce an infinite recursion, an exception
# is raised.
def infinite():
infinite()
infinite()
--------------------------------------------------------------------------- RecursionError Traceback (most recent call last) <ipython-input-1-5672e46a4865> in <module> 5 infinite() 6 ----> 7 infinite() <ipython-input-1-5672e46a4865> in infinite() 3 4 def infinite(): ----> 5 infinite() 6 7 infinite() ... last 1 frames repeated, from the frame below ... <ipython-input-1-5672e46a4865> in infinite() 3 4 def infinite(): ----> 5 infinite() 6 7 infinite() RecursionError: maximum recursion depth exceeded
*args
" and "**kwargs
" as arguments.import antigravity
from the python prompt!# Lists are represented by square brackets.
# Create an empty list:
L1 = []
# Or use the list constructor:
L2 = list()
print(L1, L1==L2)
[] True
# Lists can contain objects of any type:
x = 3.4 + 6.8j
# Create a list with predefined content:
L1 = [1, 2, 3.5, 'spam', x, True, None]
print(L1)
[1, 2, 3.5, 'spam', (3.4+6.8j), True, None]
# Get the length of a sequence with len()
print(len(L1))
7
# Add a single element to a list using append.
L = [1, 2, 3]
L.append(4)
print(L)
L.append('spam')
print(L)
[1, 2, 3, 4] [1, 2, 3, 4, 'spam']
# An element of a list can be another list.
L.append([5, 6])
print(L)
[1, 2, 3, 4, 'spam', [5, 6]]
# Add one or more elements to a list using extend.
# extend iterates over the object passed to it and adds each
# element to the list.
L = [1, 2, 3]
L.extend([4, 5])
print(L)
L.extend([6])
print(L)
[1, 2, 3, 4, 5] [1, 2, 3, 4, 5, 6]
# Since a string is a sequence, each character is appended to
# the list in turn.
L.extend('spam')
print(L)
[1, 2, 3, 4, 5, 6, 's', 'p', 'a', 'm']
# If you pass something that's not iterable to extend then
# you get an exception.
L.extend(5)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-1-773518e080b7> in <module> 2 # you get an exception. 3 ----> 4 L.extend(5) TypeError: 'int' object is not iterable
# Similarly to strings, lists can be concatenated with +
L1 = [3, 2, 1, 0]
L2 = L1 + [-1, -2]
print(L2)
[3, 2, 1, 0, -1, -2]
# The += operator behaves similarly to extend,
# but only works when adding on another list,
# not just any iterable object.
L1 += [-1, -2, -3]
print(L1)
[3, 2, 1, 0, -1, -2, -3]
# Lists can also be multplied by integers to repeat them.
L1 = [1, 2] * 3
print(L1)
[1, 2, 1, 2, 1, 2]
# Elements or slices can be accessed by index,
# just like strings.
L = [3, 2, 1, 0, -1, -2, -3]
print(L[0])
print(L[1:3])
3 [2, 1]
# Lists are "mutable", meaning you can change their elements.
print(L)
# Access an element and assign a new value
L[0] = 5
print(L)
[3, 2, 1, 0, -1, -2, -3] [5, 2, 1, 0, -1, -2, -3]
# You can even change slices of the list for another list
print(L)
# Access a slice and change its values
L[-3:] = [1,2,3]
print(L)
[5, 2, 1, 0, -1, -2, -3] [5, 2, 1, 0, 1, 2, 3]
# This is not so for strings, they're "immutable", so you can't
# change an element. If you try you get an exception.
name = 'Sir Lancelot'
name[0] = 's'
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-1-d174bc98c6eb> in <module> 3 4 name = 'Sir Lancelot' ----> 5 name[0] = 's' TypeError: 'str' object does not support item assignment
# The pop method removes an element and returns its value.
L = [3, 2, 1, 0, -1, -2, -3]
# By default it's the last element in the list.
elm1 = L.pop()
print(L)
print(elm1)
[3, 2, 1, 0, -1, -2] -3
# pop can also take an index as argument to remove a specific element.
elm2 = L.pop(0)
print(L)
print(elm2)
[2, 1, 0, -1, -2] 3
# You can simply delete elements or slices from the list using del
L = [3, 2, 1, 0, -1, -2, -3]
del L[0]
print(L)
del L[:2]
print(L)
[2, 1, 0, -1, -2, -3] [0, -1, -2, -3]
# You can check if a list contains an object with the 'in'
# keyword
print(0 in L)
print(3 in L)
True False
# Tuples are represented by regular brackets ().
# An empty tuple:
t1 = ()
t2 = tuple()
print(t1)
print(t1==t2)
() True
# Otherwise elements of a tuple are separated by commas.
# You can put previously assigned variables into any
# sequence.
x = [3,4]
t = (1, 2, 3.5, 'a', x, True, None)
print(t)
(1, 2, 3.5, 'a', [3, 4], True, None)
# To create a single element tuple you need to add a comma
# This just assigns zero to t1
t1 = (0)
# While this makes a single element tuple
t2 = (0,)
print(t1, type(t1))
print(t2, type(t2))
0 <class 'int'> (0,) <class 'tuple'>
# If you omit the brackets any sequence of objects separated by
# commas is made into a tuple on-the-fly.
t1 = 1, 2, 3, 4
print(t1, type(t1))
(1, 2, 3, 4) <class 'tuple'>
# You can get the number of elements using len as with a list.
len(t1)
4
# Concatenation work in the same way as lists.
t2 = t1 + (5, 6)
print(t2)
(1, 2, 3, 4, 5, 6)
# So does multiplication.
t3 = (1, 2) * 3
print(t3)
(1, 2, 1, 2, 1, 2)
# As with access to elements or slices.
print(t2[0])
print(t2[1:3])
print(t2[-1])
1 (2, 3) 6
# Check if an element is in the tuple with 'in', like lists.
print(1 in t3)
print(5 in t3)
True False
# Though, as with strings, if you try to change an element
# you get an exception
t2[0] = 'eggs'
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-1-73fa24ebf299> in <module> 2 # you get an exception 3 ----> 4 t2[0] = 'eggs' TypeError: 'tuple' object does not support item assignment
# Similarly, no pop method exists, and you can't delete
# elements or slices of a tuple using del. Though you
# can delete the whole tuple as with any variable
# like so:
del t2
# You can "unpack" a tuple or list, or any other iterable,
# and assign their elements to individual variables, like so:
t = 1, 2, 3
x, y, z = t
print(x, y, z)
1 2 3
# This also works for strings.
s = 'abc'
c1, c2, c3 = s
print(c1)
print(c2)
print(c3)
a b c
# Swapping the contents of variables is then trivial:
a, b = 1, 2
print(a, b)
b, a = a, b
print(a, b)
1 2 2 1
# Dictionaries are represented by curly brackets {}.
# Make an empty dictionary like so:
d1 = {}
d2 = dict()
print(d1)
print(d1==d2)
{} True
d = {key1 : element1, key2 : element2, ...}
.
d = {'nothing' : 0,
'a' : 1,
'b' : 'something'}
print(d)
{'nothing': 0, 'a': 1, 'b': 'something'}
# The value of an element is then retrieved using the
# relevant key.
print(d['a'])
1
# You can also store a key in a variable and use the
# variable as index:
key = 'b'
print('Key:', key, ', element:', d[key])
Key: b , element: something
# len works as on lists and tuples.
print('Length of d is', len(d))
Length of d is 3
# You don't have to use strings as keys, you can
# use dicts to map pairs of (almost) any types
d = {None : 'nothing',
2+3j : 84,
3.4 : 6}
print(d)
print(d[3.4])
print(d[None])
{None: 'nothing', (2+3j): 84, 3.4: 6} 6 nothing
phonebook = {'Me' : 1000,
'Sir Robin' : 2000,
'Sir Gallahad' : 3000}
# Get a sequence of keys with the keys() member method.
# Convert it to a list just so it's printed nicely.
print(list(phonebook.keys()))
# Get a sequence of the element values with values()
print(list(phonebook.values()))
['Me', 'Sir Robin', 'Sir Gallahad'] [1000, 2000, 3000]
# Check if a dictionary has a given key with 'in' keyword.
print('Sir Robin' in phonebook)
print('Sir Lancelot' in phonebook)
True False
# Dictionaries are mutable, so you can change the elements
# as with lists:
phonebook['Sir Robin'] = 2345
# Or you can add a new (key, element) pair by assigning a
# value to a key that isn't in the dict:
phonebook['Sir Lancelot'] = 8734
print(phonebook)
{'Me': 1000, 'Sir Robin': 2345, 'Sir Gallahad': 3000, 'Sir Lancelot': 8734}
# As you might expect, if you try to access a key that doesn't
# exist you get an exception.
phonebook['spam']
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) <ipython-input-1-3f6d98f337b1> in <module> 2 # exist you get an exception. 3 ----> 4 phonebook['spam'] KeyError: 'spam'
# You can use the dict.get method to return a default
# value if the key isn't in the dict
print(phonebook.get('Me', 1234))
print(phonebook.get('spam', 4567))
1000 4567
# Again, similarly to lists, you can delete elements by key:
del phonebook['Me']
print(phonebook)
{'Sir Robin': 2345, 'Sir Gallahad': 3000, 'Sir Lancelot': 8734}
# Or clear it using the clear() method:
phonebook.clear()
print(phonebook)
{}
# Or delete it entirely.
del phonebook
# You can declare them like a list or tuple using
# curly brackets
s = {1,2,3}
print(s)
{1, 2, 3}
# Or you can use the set constructor, which takes any
# iterable object as argument, from which unique elements
# are added.
s = set([4,5,6,4,5,6])
print(s)
{4, 5, 6}
# If you make a set from a string it selects unique
# characters from it, though their order isn't
# retained.
s = set('spam and eggs')
print(s)
{'e', 'g', 'a', 'p', ' ', 'd', 's', 'n', 'm'}
# Note that to make an empty set you need to use the set
# constructor as {} gives you an empty dictionary.
print(set(), type(set()))
print({}, type({}))
set() <class 'set'> {} <class 'dict'>
# Unlike a list or tuple, you can't access elements by index
s = set('spam and eggs')
s[0]
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-1-0eefc1388028> in <module> 2 3 s = set('spam and eggs') ----> 4 s[0] TypeError: 'set' object is not subscriptable
# But you can check if a set contains an object in
# the same way.
print('e' in s)
print(42 in s)
True False
# You can add or remove elements using the add and remove
# member methods.
s.add('k')
print(s)
print('k' in s)
{'e', 'g', 'a', 'p', ' ', 'd', 's', 'n', 'k', 'm'} True
s.remove('e')
print(s)
print('e' in s)
{'g', 'a', 'p', ' ', 'd', 's', 'n', 'k', 'm'} False
# Compare to the original set
soriginal = set('spam and eggs')
# This gives the set of elements in 's' that aren't in 'soriginal'
print(s.difference(soriginal))
{'k'}
while
Statements¶while
statement takes a boolean expression followed by an indented block of code.True
the indented code block is evaluated.False
, at which point the loop terminates.i = 0
while i < 10 :
print(i, end = ' ')
i += 1
# Printing an empty string means the newline is now
# printed.
print('')
# Confirm that the expression now evaluates to False
print(i, i < 10)
0 1 2 3 4 5 6 7 8 9 10 False
# Use the fact that a non-empty list evaluates to True
# and an empty one to False.
# Loops backwards over the list.
L = [1, 2, 3, 4, 5]
while L:
print(L.pop(), end = ' ')
5 4 3 2 1
for
Loops¶range
" built-in method returns a sequence of integers, which is very useful for looping. # If only one argument is given to range the sequence goes
# from 0 up to the argument -1.
# This makes a 'range' object
print(range(10))
# Convert the sequence to a list so we can see its contents.
print(list(range(10)))
range(0, 10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# If two are given range returns a list of integers
# with values between the two.
print(list(range(1, 4)))
[1, 2, 3]
# A third argument gives the step size between elements.
print(list(range(-8, 10, 2)))
[-8, -6, -4, -2, 0, 2, 4, 6, 8]
for element in sequence :
element
variable (you can call it whatever you want) then takes the values of each element in the sequence in turn.Eg:
# Iterate over the sequence of integers returned by range:
for i in range(1, 4) :
print(i, end=' ')
1 2 3
# Iterate over characters in a string:
for char in 'eggs' :
print(char)
e g g s
# Iterate over a tuple:
my_tuple = (1, 2, 3, 'a', (8,9), True, None)
for elm in my_tuple :
print(elm, end = ' ')
1 2 3 a (8, 9) True None
# Iterate over indices of the tuple.
for i in range(len(my_tuple)) :
print(i, my_tuple[i])
0 1 1 2 2 3 3 a 4 (8, 9) 5 True 6 None
continue
, break
and pass
can be used to control loop behaviour.for i in range(10, -100, -1) :
if i == 0 :
# Continue onto the next iteration.
continue
elif i % 2 == 1 :
# The pass statement means "do nothing".
pass
else :
print(i, end=' ')
if i < -10 :
# Stop the enclosing loop entirely.
break
10 8 6 4 2 -2 -4 -6 -8 -10
str
, complex
, list
, tuple
, dict
, set
.dir
¶dir()
method.>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
builtins
contains all the default classes and functions available in python.doc
contains the documentation on the current module. name
and package
are the name of the current module and the package to which it belongs.# As we've declared many things in the process of this course dir
# returns rather more now.
print(dir())
['In', 'L', 'L1', 'L2', 'Out', '_', '_1', '__', '___', '__builtin__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', '_dh', '_ih', '_oh', 'a', 'appnope', 'area', 'area2', 'b', 'c', 'c1', 'c2', 'c3', 'char', 'd', 'd1', 'd2', 'elm', 'elm1', 'elm2', 'exit', 'fibonacci', 'genericResult', 'get_area', 'get_ipython', 'hello_world', 'i', 'infinite', 'key', 'keyword', 'l', 'length', 'lyric', 'menu', 'menu2', 'my_tuple', 'name', 'quit', 'radius_sq', 'result', 'result1', 'result2', 's', 'soriginal', 'sum_of_squares', 'sys', 't', 't1', 't3', 'var', 'w', 'width', 'x', 'y', 'yesNo', 'z']
# You can see the full list of built-in functionality
# available by doing
print(dir(__builtins__))
['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', 'breakpoint', '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']
# You can call dir on a class type or an instance of a class.
print(dir(complex))
['__abs__', '__add__', '__bool__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__int__', '__le__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__pos__', '__pow__', '__radd__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rmod__', '__rmul__', '__rpow__', '__rsub__', '__rtruediv__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', 'conjugate', 'imag', 'real']
real
and imag
members we used before, as well as the conjugate
method.__add__
method is what's used by the + operator.# These are all equivalent:
print(1 + 2)
print((1).__add__(2))
x, y = 1, 2
print(x.__add__(y))
3 3 3
help
¶dir
is good for finding names of attributes, but doesn't tell you anything about them.help
method, which accesses the internal documentation.# For instance, the dir method has its own built-in documentation:
help(dir)
Help on built-in function dir in module builtins: dir(...) dir([object]) -> list of strings If called without an argument, return the names in the current scope. Else, return an alphabetized list of names comprising (some of) the attributes of the given object, and of attributes reachable from it. If the object supplies a method named __dir__, it will be used; otherwise the default dir() logic is used and returns: for a module object: the module's attributes. for a class object: its attributes, and recursively the attributes of its bases. for any other object: its attributes, its class's attributes, and recursively the attributes of its class's base classes.
# Or for the conjugate method of the complex class:
help(complex.conjugate)
Help on method_descriptor: conjugate(...) complex.conjugate() -> complex Return the complex conjugate of its argument. (3-4j).conjugate() == 3+4j.
# You can also enter interactive help mode by calling help without an
# argument. You can then enter any class or method name for help on it,
# or search for a specific word, etc.
help()
help
method is stored in a function's "doc string" as part of the function definition.# Redefine the method with a doc string.
def sum_of_squares(x, y) :
'''Returns the sum of the squares of the two arguments.'''
return x**2 + y**2
help(sum_of_squares)
Help on function sum_of_squares in module __main__: sum_of_squares(x, y) Returns the sum of the squares of the two arguments.
# The doc string is stored in the __doc__ attribute
# of an object.
print(sum_of_squares.__doc__)
Returns the sum of the squares of the two arguments.
help
is much less useful.type
method.isinstance
:print(isinstance(1, int))
print(isinstance(3., int))
True False
isinstance
, in which case it returns True
if the object is of any of the types in the tuple:# Check if something is a numerical type:
print(isinstance(.234, (int, float)))
print(isinstance('spam', (int, float)))
print(isinstance('spam', str))
True False True
dir
or help
on any object, class name, method, type specification, or indeed anything!class
keyword, followed by the class name and an indented block of code defining the class.class Minimal :
pass
# Then make an instance of the class by calling the constructor:
m = Minimal()
# Attributes can then be assigned dynamically.
m.spam = 'eggs'
# They're accessed in the usual way.
print(m.spam)
eggs
# You can check if an object has an attribute with "hasattr"
print(hasattr(m, 'spam'))
print(hasattr(m, 'bla'))
True False
# "getattr" retrieves an attribute.
# This is the same as m.spam
print(getattr(m, 'spam'))
eggs
# Attributes can be removed using del
del m.spam
print(hasattr(m, 'spam'))
False
def
, within the class
code block.self
. This represents the instance of the class on which the function is being called. It may be the only argument to a member function.self
is used to access attributes or call other member functions.__init__
function. This is called when a new instance of the class is created. It can initialise data members.class Pokemon:
'''Basic class describing a Pokemon'''
def __init__(self, name, category, level,
strongAgainst, weakAgainst):
'''Takes the category of the Pokemon (eg, fire/water),
level, strengths and weaknesses.'''
self.name = name
self.category = category
self.level = level
self.experience = 0
# Copy the lists of strengths/weaknesses into new tuples
self.strongAgainst = tuple(strongAgainst)
self.weakAgainst = tuple(weakAgainst)
def is_strong_against(self, other):
'''Check if this Pokemon is strong against
another Pokemon.'''
return other.category in self.strongAgainst
def is_weak_against(self, other):
'''Check if this Pokemon is weak against
another Pokemon.'''
return other.category in self.weakAgainst
def increase_exp(self, exp):
'''Increase the experience of this Pokemon and
possibly level up.'''
# Gradually increase experience and level up as
# necessary.
for i in range(exp):
self.experience += 1
if self.experience >= self.level * 10:
self.level_up()
def level_up(self):
'''Level up this Pokemon.'''
self.experience -= self.level * 10
self.level += 1
print(self.name, 'grew to level', self.level)
def print_info(self):
'''Print info on this Pokemon.'''
print(('{0}:\n'
'- Type: {1}\n'
'- Level: {2}\n'
'- Strong against: {3}\n'
'- Weak against: {4}\n').format(self.name,
self.category,
self.level,
', '.join(self.strongAgainst),
', '.join(self.weakAgainst)))
self
argument is omitted as it's implicit.# Make a Charmander
charmander = Pokemon('Charmander', 'fire', 1,
# Fire is strong against grass & ice
('grass', 'ice'),
# Fire is weak against water & rock
('water', 'rock'))
print(dir(charmander))
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'category', 'experience', 'increase_exp', 'is_strong_against', 'is_weak_against', 'level', 'level_up', 'name', 'print_info', 'strongAgainst', 'weakAgainst']
# help(Pokemon) would also work.
help(charmander)
Help on Pokemon in module __main__ object: class Pokemon(builtins.object) | Pokemon(name, category, level, strongAgainst, weakAgainst) | | Basic class describing a Pokemon | | Methods defined here: | | __init__(self, name, category, level, strongAgainst, weakAgainst) | Takes the category of the Pokemon (eg, fire/water), | level, strengths and weaknesses. | | increase_exp(self, exp) | Increase the experience of this Pokemon and | possibly level up. | | is_strong_against(self, other) | Check if this Pokemon is strong against | another Pokemon. | | is_weak_against(self, other) | Check if this Pokemon is weak against | another Pokemon. | | level_up(self) | Level up this Pokemon. | | print_info(self) | Print info on this Pokemon. | | ---------------------------------------------------------------------- | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined)
# Use help on a specific function
help(Pokemon.is_weak_against)
Help on function is_weak_against in module __main__: is_weak_against(self, other) Check if this Pokemon is weak against another Pokemon.
# As said before, the doc is stored in the __doc__
# attribute
print(Pokemon.is_weak_against.__doc__)
Check if this Pokemon is weak against another Pokemon.
# Make another instance with different attributes,
# eg, a water type Pokemon
squirtle = Pokemon('Squirtle', 'water', 1,
# Water is strong against fire
('fire',),
# Water is weak against electric
('electric',))
# Call some functions
squirtle.print_info()
Squirtle: - Type: water - Level: 1 - Strong against: fire - Weak against: electric
squirtle.increase_exp(10)
Squirtle grew to level 2
class
line.super()
to access the base class.super
.# Write a derived class for Charmander
class Charmander(Pokemon):
'''Describes all Charmanders.'''
def __init__(self, level, name='Charmander'):
'''Initialise a Charmander. Just needs the level
and optionally a name.'''
# Use super to call __init__ of the Pokemon
# base class.
super(Charmander, self).__init__('Charmander', 'fire', level,
('grass', 'ice'),
('water', 'rock'))
# Assign a new attribute
self.petname = name
def level_up(self):
'''Level up Charmander.'''
super(Charmander, self).level_up()
if self.level == 4:
print('Charmander learned "ember"!')
elif self.level == 16:
print('Charmander evolved into Charmeleon!')
# Instantiate as before.
charmander = Charmander(3)
# Check its attributes
print(dir(charmander))
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'category', 'experience', 'increase_exp', 'is_strong_against', 'is_weak_against', 'level', 'level_up', 'name', 'petname', 'print_info', 'strongAgainst', 'weakAgainst']
petname
attribute.# Now call some functions.
# This uses the definition in the Pokemon base class.
charmander.is_strong_against(squirtle)
False
# When level_up is called, it uses the version
# defined in the Charmander derived class.
charmander.increase_exp(30)
Charmander grew to level 4 Charmander learned "ember"!
__slots__
to specify attribute names¶# Eg, this typo passes silently:
charmander.naem = 'Bob'
charmander.print_info()
Charmander: - Type: fire - Level: 4 - Strong against: grass, ice - Weak against: water, rock
print(dir(charmander))
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'category', 'experience', 'increase_exp', 'is_strong_against', 'is_weak_against', 'level', 'level_up', 'naem', 'name', 'petname', 'print_info', 'strongAgainst', 'weakAgainst']
__slots__
attribute.__init__
.# Redefine the class with __slots__.
class Pokemon:
'''Basic class describing a Pokemon'''
# Define the allowed attributes
__slots__ = ('name', 'category', 'level',
'experience', 'strongAgainst',
'weakAgainst')
def __init__(self, name, category, level,
strongAgainst, weakAgainst):
'''Takes the category of the Pokemon (eg, fire/water),
level, strengths and weaknesses.'''
self.name = name
self.category = category
self.level = level
self.experience = 0
# Copy the lists of strengths/weaknesses into new tuples
self.strongAgainst = tuple(strongAgainst)
self.weakAgainst = tuple(weakAgainst)
def is_strong_against(self, other):
'''Check if this Pokemon is strong against
another Pokemon.'''
return other.category in self.strongAgainst
def is_weak_against(self, other):
'''Check if this Pokemon is weak against
another Pokemon.'''
return other.category in self.weakAgainst
def increase_exp(self, exp):
'''Increase the experience of this Pokemon and
possibly level up.'''
# Gradually increase experience and level up as
# necessary.
for i in range(exp):
self.experience += 1
if self.experience >= self.level * 10:
self.level_up()
def level_up(self):
'''Level up this Pokemon.'''
self.experience -= self.level * 10
self.level += 1
print(self.name, 'grew to level', self.level)
def print_info(self):
'''Print info on this Pokemon.'''
print(('{0}:\n'
'- Type: {1}\n'
'- Level: {2}\n'
'- Strong against: {3}\n'
'- Weak against: {4}\n').format(self.name,
self.category,
self.level,
', '.join(self.strongAgainst),
', '.join(self.weakAgainst)))
# Similarly for the derived class.
class Charmander(Pokemon):
'''Describes all Charmanders.'''
# Note that you only need to list the attributes
# added in the derived class
__slots__ = ('petname',)
def __init__(self, level, name='Charmander'):
'''Initialise a Charmander. Just needs the level
and optionally a name.'''
# Use super to call __init__ of the Pokemon
# base class.
super(Charmander, self).__init__('Charmander', 'fire', level,
('grass', 'ice'),
('water', 'rock'))
# Assign a new attribute
self.petname = name
def level_up(self):
'''Level up Charmander.'''
super(Charmander, self).level_up()
if self.level == 4:
print('Charmander learned "ember"!')
elif self.level == 16:
print('Charmander evolved into Charmeleon!')
# Now we get an exception from the typo.
charmander = Charmander(1)
charmander.naem = 'Bob'
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-1-18493b0d85ad> in <module> 2 3 charmander = Charmander(1) ----> 4 charmander.naem = 'Bob' AttributeError: 'Charmander' object has no attribute 'naem'
__slots__
and other aspects of the data model in python.__slots__
is an example of this.class Charmander(Pokemon):
'''Describes all Charmanders.'''
# Note that you only need to list the attributes
# added in the derived class
__slots__ = ('petname',)
# Define a class attribute
verbose = False
def __init__(self, level, name='Charmander'):
'''Initialise a Charmander. Just needs the level
and optionally a name.'''
# Use super to call __init__ of the Pokemon
# base class.
super(Charmander, self).__init__('Charmander', 'fire', level,
('grass', 'ice'),
('water', 'rock'))
# Assign a new attribute
self.petname = name
if Charmander.verbose:
print('Made a new Charmander')
self.print_info()
def level_up(self):
'''Level up Charmander.'''
super(Charmander, self).level_up()
if self.level == 4:
print('Charmander learned "ember"!')
elif self.level == 16:
print('Charmander evolved into Charmeleon!')
# You can access class attributes through the class itself
# or through instances of the class, they all refer to the
# same object.
charmander1 = Charmander(1)
charmander2 = Charmander(1)
print(charmander1.verbose)
print(id(charmander1.verbose) == id(charmander2.verbose)
== id(Charmander.verbose))
False True
# Change the value of the class attribute like so:
# (to change the value for all class instances this
# has to be done via the class itself)
Charmander.verbose = True
charmander3 = Charmander(1)
Made a new Charmander Charmander: - Type: fire - Level: 1 - Strong against: grass, ice - Weak against: water, rock
# The value of the attribute is the same for all instances
# of the class.
print(Charmander.verbose)
print(charmander1.verbose)
print(charmander2.verbose)
True True True
property
, as well as static and class function definitions through staticmethod
and classmethod
.sys
, math
, time
.os
, urllib
.numpy
, matplotlib
.import
keyword:# The built-in math module
import math
print(dir(math))
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'lcm', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'nextafter', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc', 'ulp']
# Call a method or access a variable contained in a module
# in the same way as you'd access methods & attributes of
# any other python object.
print(math.pi)
print(math.sin(math.pi/2.))
print(math.sin(math.pi))
3.141592653589793 1.0 1.2246467991473532e-16
# import a specific function/variable from a module.
from math import sin
from math import cos, pi
# They're then accessible in the "local namespace"
# so you can drop the math. prefix
print(sin(pi/4.), cos(pi/4.))
0.7071067811865475 0.7071067811865476
# You can also rename a variable at import using the
# 'as' keyword.
# Sometimes desirable to avoid confusion over variables.
from math import sqrt as my_sqrt
print(my_sqrt(4))
2.0
# Import everything from a module into the current
# namespace.
# Use with care! For large modules this is slow &
# memory intensive. It's much more efficient to
# import only what you need.
from math import *
print(e)
print(log(e))
2.718281828459045 1.0
# Import a sub-module from a module.
from os import path
print(dir(path))
['__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_get_sep', '_joinrealpath', '_varprog', '_varprogb', 'abspath', 'altsep', 'basename', 'commonpath', 'commonprefix', 'curdir', 'defpath', 'devnull', 'dirname', 'exists', 'expanduser', 'expandvars', 'extsep', 'genericpath', 'getatime', 'getctime', 'getmtime', 'getsize', 'isabs', 'isdir', 'isfile', 'islink', 'ismount', 'join', 'lexists', 'normcase', 'normpath', 'os', 'pardir', 'pathsep', 'realpath', 'relpath', 'samefile', 'sameopenfile', 'samestat', 'sep', 'split', 'splitdrive', 'splitext', 'stat', 'supports_unicode_filenames', 'sys']
# Import a method/variable from a sub-module.
from os.path import exists
print(exists('./Hello_world.py'))
True
import
actually calls the built-in __import__
method in the background.__import__
takes a string as argument, which allows you to import programmatically.# The __import__ method actually returns the module.
# Modules are objects too!
math_module = __import__('math')
print(dir(math_module))
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'lcm', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'nextafter', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc', 'ulp']
# If you alternatively want to use the cmath module,
# which supports maths with complex numbers.
math_module = __import__('cmath')
print(dir(math_module))
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh', 'cos', 'cosh', 'e', 'exp', 'inf', 'infj', 'isclose', 'isfinite', 'isinf', 'isnan', 'log', 'log10', 'nan', 'nanj', 'phase', 'pi', 'polar', 'rect', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau']
math
and cmath
modules contain sin
, cos
, etc, methods.array
and numpy
modules contain an array
class.from array import array
myArray = array('d', [0.] * 3)
print(myArray)
array('d', [0.0, 0.0, 0.0])
# Executing the same code after importing the numpy array
# class crashes, as the constructors take different
# arguments.
from numpy import array
myArray = array('d', [0.] * 3)
print(myArray)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-1-dfb138806743> in <module> 4 5 from numpy import array ----> 6 myArray = array('d', [0.] * 3) 7 print(myArray) TypeError: Field elements must be 2- or 3-tuples, got '0.0'
sys
, glob
os
, commands
, shutil
math
, cmath
, array
datetime
StringIO
, re
getopt
, argparse
webbrowser
, urllib2
timeit
help
on them.Pokemon
and Charmander
class definitions in a file called Pokemon.py.%%writefile <fname>
at the top of a cell will write the contents of the cell to a file named <fname>
:%%writefile Pokemon.py
'''A set of classes to describe different Pokemon.'''
class Pokemon:
'''Basic class describing a Pokemon'''
# Define the allowed attributes
__slots__ = ('name', 'category', 'level',
'experience', 'strongAgainst',
'weakAgainst')
def __init__(self, name, category, level,
strongAgainst, weakAgainst):
'''Takes the category of the Pokemon (eg, fire/water),
level, strengths and weaknesses.'''
self.name = name
self.category = category
self.level = level
self.experience = 0
# Copy the lists of strengths/weaknesses into new tuples
self.strongAgainst = tuple(strongAgainst)
self.weakAgainst = tuple(weakAgainst)
def is_strong_against(self, other):
'''Check if this Pokemon is strong against
another Pokemon.'''
return other.category in self.strongAgainst
def is_weak_against(self, other):
'''Check if this Pokemon is weak against
another Pokemon.'''
return other.category in self.weakAgainst
def increase_exp(self, exp):
'''Increase the experience of this Pokemon and
possibly level up.'''
# Gradually increase experience and level up as
# necessary.
for i in range(exp):
self.experience += 1
if self.experience >= self.level * 10:
self.level_up()
def level_up(self):
'''Level up this Pokemon.'''
self.experience -= self.level * 10
self.level += 1
print(self.name, 'grew to level', self.level)
def print_info(self):
'''Print info on this Pokemon.'''
print(('{0}:\n'
'- Type: {1}\n'
'- Level: {2}\n'
'- Strong against: {3}\n'
'- Weak against: {4}\n').format(self.name,
self.category,
self.level,
', '.join(self.strongAgainst),
', '.join(self.weakAgainst)))
class Charmander(Pokemon):
'''Describes all Charmanders.'''
# Note that you only need to list the attributes
# added in the derived class
__slots__ = ('petname',)
# Define a class attribute
verbose = False
def __init__(self, level, name='Charmander'):
'''Initialise a Charmander. Just needs the level
and optionally a name.'''
# Use super to call __init__ of the Pokemon
# base class.
super(Charmander, self).__init__('Charmander', 'fire', level,
('grass', 'ice'),
('water', 'rock'))
# Assign a new attribute
self.petname = name
if Charmander.verbose:
print('Made a new Charmander')
self.print_info()
def level_up(self):
'''Level up Charmander.'''
super(Charmander, self).level_up()
if self.level == 4:
print('Charmander learned "ember"!')
elif self.level == 16:
print('Charmander evolved into Charmeleon!')
Overwriting Pokemon.py
# Then we can import it.
import Pokemon
# The string at the top of the file is the doc string
# for the module itself.
print(Pokemon.__doc__)
print(dir(Pokemon))
A set of classes to describe different Pokemon. ['Charmander', 'Pokemon', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
PYTHONPATH
is a list of directories where python looks for modules.Pokemon
module because the file Pokemon.py
is in our current working directory.import Pokemon
when working in another directory we'd need to add the directory containing Pokemon.py
to PYTHONPATH
.PYTHONPATH
are thus available system wide.PYTHONPATH
is stored in the path
variable in the sys
module.import sys
print(sys.path)
['/Users/michaelalexander/cernbox/teaching/SUPAPYT/IntroductionToPython', '/Users/michaelalexander/cernbox/projects/G-Fact/src/G-Fact/tools', '/usr/local/Cellar/root/6.22.06_2/lib/root', '/usr/local/Cellar/python@3.9/3.9.1_6/Frameworks/Python.framework/Versions/3.9/lib/python39.zip', '/usr/local/Cellar/python@3.9/3.9.1_6/Frameworks/Python.framework/Versions/3.9/lib/python3.9', '/usr/local/Cellar/python@3.9/3.9.1_6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/lib-dynload', '', '/Users/michaelalexander/cernbox/teaching/SUPAPYT/env/lib/python3.9/site-packages', '/Users/michaelalexander/cernbox/teaching/SUPAPYT/env/lib/python3.9/site-packages/IPython/extensions', '/Users/michaelalexander/.ipython', '/Users/michaelalexander/cernbox/projects/G-Fact/src/G-Fact/tools', '/usr/local/Cellar/root/6.14.06/lib/root']
Pokemon.py
to another directory, say called PokemonRed
, and rename it to NewPokemon.py
.os
and shutil
modules:import os, shutil
dirname = 'PokemonRed'
if not os.path.exists(dirname) :
os.mkdir(dirname)
shutil.copy('Pokemon.py', os.path.join(dirname, 'NewPokemon.py'))
'PokemonRed/NewPokemon.py'
# This doesn't currently work.
import NewPokemon
--------------------------------------------------------------------------- ModuleNotFoundError Traceback (most recent call last) <ipython-input-1-02023314ad30> in <module> 1 # This doesn't currently work. ----> 2 import NewPokemon ModuleNotFoundError: No module named 'NewPokemon'
# Add the PokemonRed directory to sys.path
sys.path.append('./PokemonRed')
# Then we can import NewPokemon
import NewPokemon
# It just contains the same functionality as
# Pokemon.
print(dir(NewPokemon))
['Charmander', 'Pokemon', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
__name__
variable) set to '__main__'
, rather than the file name.%%writefile -a Pokemon.py
if __name__ == '__main__' :
charmander = Charmander(1)
charmander.print_info()
Appending to Pokemon.py
!
.Pokemon.py
as the main file by doing:!python Pokemon.py
Charmander: - Type: fire - Level: 1 - Strong against: grass, ice - Weak against: water, rock
Pokemon
into another script the __name__
variable within Pokemon
is set to 'Pokemon'
, not '__main__'
, and we get no output.import
of the same module does nothing. If the module has changed, you have to use importlib.reload
(though this is very rare):import importlib
# This gives no output.
importlib.reload(Pokemon)
<module 'Pokemon' from '/Users/michaelalexander/cernbox/teaching/SUPAPYT/IntroductionToPython/Pokemon.py'>
if __name__ == '__main__'
" statement, and call the script directly only when testing.__init__.py
file.__init__.py
file signals to python that the directory is a package. __init__.py
contains any code you want executed when the package is imported (it can be empty). PokemonRed
directory into a package by adding a __init__.py
file.Pokemon.py
module first:import os, shutil
# Make the directory.
dirname = 'PokemonRed'
if not os.path.exists(dirname) :
os.mkdir(dirname)
# Copy Pokemon.py to the directory.
shutil.copy('Pokemon.py', os.path.join(dirname, 'Pokemon.py'))
'PokemonRed/Pokemon.py'
__init__.py
file. More on manipulating files in the next section.with open(os.path.join(dirname, '__init__.py'), 'w') as finit :
pass
# Check the contents of PokemonRed
os.listdir(dirname)
['__init__.py', 'NewPokemon.py', '__pycache__', 'Pokemon.py']
# Now we can import the PokemonRed package.
import PokemonRed
# Packages are treated identically to modules.
type(PokemonRed)
module
# Import the Pokemon module from the PokemonRed package
from PokemonRed import Pokemon
print(dir(Pokemon))
['Charmander', 'Pokemon', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
# Import the Charmander class from the NewPokemon submodule of
# the PokemonRed package.
from PokemonRed.Pokemon import Charmander
print(dir(Charmander))
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'category', 'experience', 'increase_exp', 'is_strong_against', 'is_weak_against', 'level', 'level_up', 'name', 'petname', 'print_info', 'strongAgainst', 'verbose', 'weakAgainst']
PYTHONPATH
environment variable can be imported. open
built-in method.'r'
for read, 'w'
for write, or 'a'
for append.'r'
is default.'w'
or 'a'
is used for a file that doesn't exist then the file is created.'b'
to any of these modes (eg, 'wb'
to write in binary mode). 'rb'
).# Open a file in write mode.
fmovies = open('movie_titles.txt', 'w')
print(fmovies)
print(type(fmovies))
<_io.TextIOWrapper name='movie_titles.txt' mode='w' encoding='UTF-8'> <class '_io.TextIOWrapper'>
# You can write to a file like so, for a single string.
# Note you have to explicitly add the newline character.
fmovies.write('The Quest\n')
10
# Or several strings at once, contained in a sequence:
fmovies.writelines(['for the\n', 'Holy Grail\n'])
# Then close the file:
fmovies.close()
# Then open the file and read its contents.
fmovies = open('movie_titles.txt')
lines = fmovies.readlines()
print(lines)
['The Quest\n', 'for the\n', 'Holy Grail\n']
# By reading all lines in the file the "cursor"
# is at the end of the file, and another call to
# readlines returns an empty list.
lines = fmovies.readlines()
print(lines)
[]
# You can skip to a specific place in a file using
# the "seek" method. Though it's rare to need to read
# the same file more than once.
fmovies.seek(0)
lines = fmovies.readlines()
print(lines)
['The Quest\n', 'for the\n', 'Holy Grail\n']
# Another way to read the whole file is using 'read',
# which returns a single string.
fmovies.seek(0)
contents = fmovies.read()
contents
'The Quest\nfor the\nHoly Grail\n'
# Alternatively, you can read one line at a time
# with 'readline'. When you reach the end of the
# file, this returns a blank string.
fmovies.seek(0)
line = fmovies.readline()
lines = []
while line:
lines.append(line)
line = fmovies.readline()
print(lines)
['The Quest\n', 'for the\n', 'Holy Grail\n']
# Again, close the file when you're done with it.
fmovies.close()
# You can also iterate directly over the lines
# in a file - similar to using 'readline' with
# a while loop as above.
fmovies = open('movie_titles.txt')
for line in fmovies :
print(line, end='')
fmovies.close()
The Quest for the Holy Grail
read
or readlines
, particularly if the file is large.with
Statement¶with
keyword is useful when dealing with files.with
statement is executed.# Open a file using 'with' and write to it.
with open('movie_titles.txt', 'w') as fmovies :
fmovies.writelines(['The Quest\n', 'for the\n', 'Holy Grail\n'])
# Note that the variable f is still in scope, but is
# a closed file.
print(type(fmovies))
print(fmovies.closed)
<class '_io.TextIOWrapper'> True
f.close()
.with
statement raises an exception.# Raise an exception inside a with block
with open('test.txt', 'w') as ftest:
int('spam')
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-1-052213d953d4> in <module> 1 # Raise an exception inside a with block 2 with open('test.txt', 'w') as ftest: ----> 3 int('spam') ValueError: invalid literal for int() with base 10: 'spam'
# We see that the file is still closed.
ftest.closed
True
dict
:# Lets make a file.
with open('phonebook.txt', 'w') as fphone :
fphone.write('''Sir Lancelot 2343
Sir Robin 8945
Sir Gallahad 2302''')
# Now open it.
phonebook = {}
with open('phonebook.txt') as fphone :
# Loop over lines in the file.
for line in fphone :
# The 'split' method divides a string into a list
# of words.
splitLine = line.split()
name = splitLine[0] + ' ' + splitLine[1]
number = int(splitLine[2])
phonebook[name] = number
print(phonebook)
{'Sir Lancelot': 2343, 'Sir Robin': 8945, 'Sir Gallahad': 2302}
str()
and repr()
.repr
should yield an unambiguous representation of an object which can be understood by the python interpreter.str
yields a string that's more easily read by humans.datetime.date
class:import datetime
today = datetime.date.today()
print('str :', str(today))
print('repr:', repr(today))
str : 2022-02-04 repr: datetime.date(2022, 2, 4)
print
uses str
, while output at the interactive prompt uses repr
.print(today)
2022-02-04
today
datetime.date(2022, 2, 4)
eval
built-in function takes a string and evaluates it with the python interpreter.eval(repr(obj)) == obj
.eval(repr(today)) == today
True
str
isn't necessarily valid python:eval(str(today)) == today
Traceback (most recent call last): File "/Users/michaelalexander/cernbox/teaching/SUPAPYT/env/lib/python3.9/site-packages/IPython/core/interactiveshell.py", line 3418, in run_code exec(code_obj, self.user_global_ns, self.user_ns) File "<ipython-input-1-5f2f1ba24099>", line 1, in <module> eval(str(today)) == today File "<string>", line 1 2022-02-04 ^ SyntaxError: leading zeros in decimal integer literals are not permitted; use an 0o prefix for octal integers
repr()
rather than str()
.with open('savethedate.py','w') as fdate :
# The module must import datetime to be able to
# make date objects.
fdate.write('import datetime\n')
fdate.write('today = ' + repr(today) + '\n')
savethedate.py
:with open('savethedate.py') as fdate :
print(fdate.read())
import datetime today = datetime.date(2022, 2, 4)
savethedate.py
is then a python readable file, it can be imported as a module:import savethedate
print(savethedate.today)
print(savethedate.today == today)
2022-02-04 True
repr()
works on all built-in types, it doesn't work on everything.__repr__
member method which returns a string representation of the object that can be understood by the python interpreter and will reproduce exactly the same object.pickle
module provides such functionality.pickle
to write to a file, it must be opened in binary mode ('wb'
).dump
and dumps
functions can be used to save objects, while load
and loads
can be used to retrieve them.# First write to a file with pickle.dump
import pickle
with open('savethedate.pkl', 'wb') as fdate :
pickle.dump(today, fdate)
savethedate.pkl
:with open('savethedate.pkl', 'rb') as fdate :
print(fdate.read())
b'\x80\x04\x95 \x00\x00\x00\x00\x00\x00\x00\x8c\x08datetime\x94\x8c\x04date\x94\x93\x94C\x04\x07\xe6\x02\x04\x94\x85\x94R\x94.'
dumps
.dump
.today_str = pickle.dumps(today)
today_str
b'\x80\x04\x95 \x00\x00\x00\x00\x00\x00\x00\x8c\x08datetime\x94\x8c\x04date\x94\x93\x94C\x04\x07\xe6\x02\x04\x94\x85\x94R\x94.'
load
from a file - remember to open in binary mode - or loads
from a string:# Load from the file.
with open('savethedate.pkl', 'rb') as fdate :
today_load = pickle.load(fdate)
print(today_load == today)
True
# Load from a string.
today_load = pickle.loads(today_str)
print(today_load == today)
True
from PokemonRed.Pokemon import Charmander
charmander = Charmander(34)
with open('PickledCharmander.pkl', 'wb') as fpickle :
pickle.dump(charmander, fpickle)
# Again, open the file in binary mode.
with open('PickledCharmander.pkl', 'rb') as fpickle :
charmander2 = pickle.load(fpickle)
charmander2.print_info()
print(charmander2.level == charmander.level)
Charmander: - Type: fire - Level: 34 - Strong against: grass, ice - Weak against: water, rock True
argv
variable of the sys
module.# Check what arguments were passed when the python interpreter
# was started for this notebook
import sys
print(sys.argv)
['/Users/michaelalexander/cernbox/teaching/SUPAPYT/env/lib/python3.9/site-packages/ipykernel_launcher.py', '-f', '/private/var/folders/5d/tl169y4d7zd35k3m0k3wtr7r0000gn/T/tmp86o9nd7w.json', '--HistoryManager.hist_file=:memory:']
sys.argv
is always the name of the script that was passed to the python interpreter.sys.argv
like you would any other list
.%%writefile listdir.py
import os, sys
print(os.listdir(sys.argv[1]))
Overwriting listdir.py
!python listdir.py ~/cernbox
['personal', 'Music', '.DS_Store', 'LogBook', 'papers', 'projects', 'Pictures', 'Contacts', '.owncloudsync.log', 'admin', '._sync_fe4d1d92c5ed.db', '._sync_fe4d1d92c5ed.db-shm', '._sync_fe4d1d92c5ed.db-wal', 'Calibre Library', 'R12PWG', 'presentations', 'stripping', 'teaching', 'dast', 'keys', 'Documents', 'WINDOWS', '.owncloudsync.log.1', 'travel', 'thinking-rock', 'reviews']
ArgumentParser
class in the argparse
module provides useful functionality for parsing commandline arguments.# Access a variable that doesn't exist
print(roderick)
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-1-cdc0b8fb81c1> in <module> 1 # Access a variable that doesn't exist ----> 2 print(roderick) NameError: name 'roderick' is not defined
# Convert something that doesn't make sense
int('a')
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-1-7f573d9eb848> in <module> 1 # Convert something that doesn't make sense ----> 2 int('a') ValueError: invalid literal for int() with base 10: 'a'
# Perform maths operations on something that isn't
# a number
import math
math.sqrt('a')
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-1-af522017d41c> in <module> 2 # a number 3 import math ----> 4 math.sqrt('a') TypeError: must be real number, not str
# Divide by zero
1/0
--------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) <ipython-input-1-bec458d46caf> in <module> 1 # Divide by zero ----> 2 1/0 ZeroDivisionError: division by zero
# Forgetting to escape quote marks in strings
'Don't forget to escape!'
File "<ipython-input-1-5ecdd026f929>", line 2 'Don't forget to escape!' ^ SyntaxError: invalid syntax
# Import a module that doesn't exist
import spam
--------------------------------------------------------------------------- ModuleNotFoundError Traceback (most recent call last) <ipython-input-1-8ba443f9da3b> in <module> 1 # Import a module that doesn't exist ----> 2 import spam ModuleNotFoundError: No module named 'spam'
builtins
.# This is the same as dir(__builtins__) like we saw before
import builtins
print(dir(builtins))
['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', 'breakpoint', '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']
Exception
base class. You can inherit from this to define your own exception classes.help(Exception)
Help on class Exception in module builtins: class Exception(BaseException) | Common base class for all non-exit exceptions. | | Method resolution order: | Exception | BaseException | object | | Built-in subclasses: | ArithmeticError | AssertionError | AttributeError | BufferError | ... and 15 other subclasses | | Methods defined here: | | __init__(self, /, *args, **kwargs) | Initialize self. See help(type(self)) for accurate signature. | | ---------------------------------------------------------------------- | Static methods defined here: | | __new__(*args, **kwargs) from builtins.type | Create and return a new object. See help(type) for accurate signature. | | ---------------------------------------------------------------------- | Methods inherited from BaseException: | | __delattr__(self, name, /) | Implement delattr(self, name). | | __getattribute__(self, name, /) | Return getattr(self, name). | | __reduce__(...) | Helper for pickle. | | __repr__(self, /) | Return repr(self). | | __setattr__(self, name, value, /) | Implement setattr(self, name, value). | | __setstate__(...) | | __str__(self, /) | Return str(self). | | with_traceback(...) | Exception.with_traceback(tb) -- | set self.__traceback__ to tb and return self. | | ---------------------------------------------------------------------- | Data descriptors inherited from BaseException: | | __cause__ | exception cause | | __context__ | exception context | | __dict__ | | __suppress_context__ | | __traceback__ | | args
help
on any exception for more info.try/except
syntax.if/elif/else
.try
is first evaluated.except
statement and following block of code.except
keyword to handle exceptions of that specific type.except
statements with different exception types can follow a try
statement.def print_inverse(x) :
try :
print(1./x)
# Catch when x is of the wrong type.
except TypeError :
print(x, 'is a', type(x), \
', not a number!')
# Catch when x is zero.
except ZeroDivisionError :
print("Can't divide by zero!")
# No problems here
print_inverse(6.)
0.16666666666666666
# Here a TypeError is raised and caught by the first
# except statement
print_inverse('6.')
6. is a <class 'str'> , not a number!
# Here a ZeroDivisionError is raised and caught by
# the second except statement
print_inverse(0.)
Can't divide by zero!
except
without a type specified:def print_inverse(x) :
try :
print(1./x)
except :
print("That didn't work!")
print_inverse(6.)
print_inverse('6.')
print_inverse(0.)
0.16666666666666666 That didn't work! That didn't work!
raise
keyword followed by an exception instance.def print_inverse(x) :
if not isinstance(x, (int, float)) :
# The TypeError constructor takes a string
# message that's printed when raised.
raise TypeError('{0} is a {1}, not a number!'\
.format(x, type(x)))
else :
print(1./x)
print_inverse('spam')
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-1-783e65b9001e> in <module> ----> 1 print_inverse('spam') <ipython-input-1-43c65b8a6e33> in print_inverse(x) 3 # The TypeError constructor takes a string 4 # message that's printed when raised. ----> 5 raise TypeError('{0} is a {1}, not a number!'\ 6 .format(x, type(x))) 7 else : TypeError: spam is a <class 'str'>, not a number!
as
, finally
, and else
can also be used when handling exceptions.Exception
built-in class.lambda
keyword.# So this:
def inverse(x) :
return 1./x
# Becomes this:
inverse = lambda x : 1./x
# Then call it like any other function
print(inverse(8.))
0.125
# A lambda function with two arguments:
sum_of_squares = lambda x, y : x**2 + y**2
sum_of_squares(3, 4)
25
def
is that they can be declared inline.# Declare and call a lambda method in the
# same expression:
(lambda x, y : x**2 + y**2)(3, 4)
25
filter
and map
builtin methods.help(filter)
Help on class filter in module builtins: class filter(object) | filter(function or None, iterable) --> filter object | | Return an iterator yielding those items of iterable for which function(item) | is true. If function is None, return the items that are true. | | Methods defined here: | | __getattribute__(self, name, /) | Return getattr(self, name). | | __iter__(self, /) | Implement iter(self). | | __next__(self, /) | Implement next(self). | | __reduce__(...) | Return state information for pickling. | | ---------------------------------------------------------------------- | Static methods defined here: | | __new__(*args, **kwargs) from builtins.type | Create and return a new object. See help(type) for accurate signature.
# So, to select even numbers from a sequence, we could do:
def test(x) :
return x%2 == 0
list(filter(test, list(range(-10, 11))))
[-10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10]
# Or, using a lambda method in just one line:
list(filter(lambda x : x%2 == 0, list(range(-10, 11))))
[-10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10]
# Map one sequence to another, element by element
# using the given method.
list(map(lambda x : x**2, list(range(10))))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# Get the sum of elements in a sequence.
sum(range(10))
45
# Reduce a sequence via recursive method calls.
from functools import reduce
reduce(lambda x, y : x * y, list(range(1, 11)))
3628800
# sum only works for numerical types, but reduce
# can be used to concatenate sequences of strings.
from functools import reduce
reduce(lambda x, y : x + ' ' + y,
('The', 'Life', 'of', 'Brian'))
'The Life of Brian'
# Alternatively you can use the str.join method:
' '.join(('The', 'Life', 'of', 'Brian'))
'The Life of Brian'
# Merge two or more sequences into a list of tuples.
list(zip(range(5), range(5,10)))
[(0, 5), (1, 6), (2, 7), (3, 8), (4, 9)]
# 'any' and 'all' builtins are useful to test a condition
# on all elements in a sequence.
# 'any' requires any of the elements to evaluate to True
# while 'all' requires all of them to be True
# They're particularly useful in conjunction with 'map'
# along with a test function that returns a boolean.
l = list(range(10))
print(all(map(lambda x : x < 5, l)))
print(any(map(lambda x : x < 5, l)))
False True
import builtins
and dir(builtins)
, and use help
to find out more.pairs = list(zip(range(5), range(5,10)))
for a, b in pairs :
print(a, b)
0 5 1 6 2 7 3 8 4 9
# Which is equivalent to :
for elm in pairs :
a, b = elm[0], elm[1]
print(a, b)
0 5 1 6 2 7 3 8 4 9
for
syntax.# For a list:
list(str(i) for i in range(10))
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
# Also for tuples:
tuple(i%3 for i in range(10))
(0, 1, 2, 0, 1, 2, 0, 1, 2, 0)
# For lists this can also be put in square brackets
# for the same result.
[i**2 for i in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
if
:tuple(i for i in range(10) if i%2 == 0)
(0, 2, 4, 6, 8)
os
module provides lots of functionality for communicating with the operating system, eg:listdir
- list a directory's contents.mkidr
and makedirs
- make a directory/directories.getcwd
, chdir
- get or change the current working directory.fchmod
, fchown
- change a file's permissions & ownership.os.path
submodule is great for file path manipulations.exists
, isdir
, islink
- check if a file exists, is a directory or a link.abspath
- get the absolute path of a file.split
- split directory and file name parts of a path.join
- join file/directory names, adding separators as needed.subprocess
module allows you to call system commands.call
- call a command and wait for it to complete.Popen
- call a command in the background.dir
and help
.Official python homepage - www.python.org
Jupyter - jupyter.org
ipython
- the enhanced interactive python interpreter.pip
is shown in the installation instructions.uncertainties
- pypi.python.org/pypi/uncertainties(Home)