-
#> python -c <command>
<command>
.<command>
can be one or more statements separated by newlines, with significant leading whitespace as in normal module code. -
#> python -m <module>
sys.path
for the named module and execute its contents as the__main__
module. -
To avoid fucking problems when printing non-BMP characters to the console
#> python -X utf8 foo.py
-
Comment starts with
#
and extends to the end of the line -
Multiple assignment
a,b = 0,1
a,b = b,a+b
-
del
can be used to delete a variable
del a
-
Wrap lines using
\
a_very_long_variable_name = 'This is a very long string that we want to ' \
'wrap across two lines for better readability. -
Assignment inside expressions must be done explicitly with the walrus operator
:=
.#> numbers = [2, 8, 0, 1, 1, 9, 7, 7]
#> description = {
"length": (num_length := len(numbers)),
"sum": (num_sum := sum(numbers)),
"mean": num_sum / num_length,
}
#> description
{'length': 8, 'sum': 35, 'mean': 4.375} -
Floor division: division that rounds to nearest integer (not floor!)
a = (-11) // 4 # -3
-
Power
a = 3 ** 4 # 81
-
In interactive mode,
_
is a read-only variable containing the last printed expression -
Exit
import sys
sys.exit()
-
in
tests if a value is in a sequence.not in
tests if a value is not in a sequence -
The operators
is
andis not
compare whether two objects are really the same object. -
and
,or
, andnot
are Boolean operators
and
andor
perform a shortcut evaluation
#> print('' or 'a' or 'b')
a -
Comparisons can be chained:
a < b == c
tests whethera
is less thanb
and moreoverb
equalsc
.
-
define the separator between printed arguments
#> print(1, 2, 3, sep ='-')
1-2-3 -
define the line separator
#> print(1, end ='*'); print(2, end ='*'); print(3, end ='*')
1*2*3* -
print to a file
#> print('foobar', file=open('quux.txt', 'a'))
- For print data structure in a readable manner, use pprint.
-
A complex can be created by using
j
orJ
to indicate the complex part.
1+2j
or with thecomplex
function (complex(1,2)
). -
real
andimag
can be used to retrieve the real and imaginary parts of a complex
a=1.5+0.5j
a.real
a.imag
-
String literals can be enclosed in single or double quotes
"foobar 'n \" quux"
'foobar \'n" quux'
-
New line can be escaped by \
"first line \n\
second line" -
Triple single or double quotes can also be used to create strings containing new lines
"""first line
second line""" -
String literals are automatically concatenated
"foo" "bar"
-
+
appends strings
"foo" + "bar"
-
*
repeats strings
"foo"*5
is"foofoofoofoofoo"
-
Slices
str[4]
fifth letter
str[2:4]
third and fourth letters
str[:2]
first two characters
str[2:]
all but first two characters
str[-1]
last character
str[-2]
last but one character
str[-2:]
last two characters
str[:-2]
all but the last two characters
slices are immutable -
Using a too large index generates an error
#> "language"[42]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range#> "language"[3:42]
'guage' -
len
return the length a string
len(str)
-
String Interpolation
-
String modulo operator
myVal1 = 10.1
myVal2 = 2.2
print("The sum of %s and %s is %s." %(my_val_1, my_val_2, my_val_1+my_val_2)) -
String.format()
'My name is {name} and I am {age} years old'.format(name= 'Frida', age=114)
-
F-strings
-
f'The date today is {datetime.datetime.now():%B %d, %Y}'
-
Use
{{
to insert a{
and}}
to insert a}
-
Insert the variable name a value
#> name = 'Tom'
#> age = 42
#> print(f'{name=} is {age=} years old')
name='Tom' is age=42 years old -
Rounding to n decimal places
#> pi = 3.14159265
#> print(f'pi is {pi:.2f}')
pi is 3.14 -
Rounding to n significant figures
#> pi = 3.14159265
#> print(f'pi is {pi:.2g}')
pi is 3.1 -
Aligning
#> fruit = 'apple'
#> print(f'|{fruit:<20}|')
|apple |
#> print(f'|{fruit:>20}|')
| apple|
#> print(f'|{fruit:^20}|')
| apple |#> print(f'|{fruit:-<20}|')
|apple---------------|
#> print(f'|{fruit:x>20}|')
|xxxxxxxxxxxxxxxapple|
#> print(f'|{fruit:=^20}|')
|=======apple========| -
Formatting numbers with commas
#> large = 12345678
#> print(f'{large:,}')
12,345,678 -
Formatting numbers as percentage
#> a = 0.25
#> b = 0.5
#> c = 0.75
#> print(f'{a:.0%} {b:.1%} {c:.2%}')
25% 50.0% 75.00% -
Formatting numbers by prepending zeros
#> print(f'{42:04d}')
0042 -
Formatting numbers as hexadecimal
#> print(f'{9:0x} {10:0x} {11:0x} {12:0x}')
9 a b c
#> print(f'{9:0X} {10:0X} {11:0X} {12:0X}')
9 A B C
#> print(f'{9:#0x} {10:#0x} {11:#0x} {12:#0x}')
0x9 0xa 0xb 0xc
#> print(f'{9:#0X} {10:#0X} {11:#0X} {12:#0X}')
0X9 0XA 0XB 0XC -
Formatting numbers as binary
#> print(f'{1:b} {2:b} {3:b} {4:b} {5:b}')
1 10 11 100 101 -
Formatting numbers with a sign
#> a = 12
#> b = -13
#> print(f'{a:+} {b:+}')
+12 -13 -
Formatting datetimes
#> from datetime import datetime
#> d = datetime(2023, 12, 31)
#> print(f'{d:%B %d %Y}')
December 31 2023
#> print(f'{d:%b %d, %Y (%A)}')
Dec 31, 2023 (Sunday) -
Formatting as printable representation
#> name = 'Rocky'
#> print(f'Name is {name!r}')
Name is 'Rocky'#> print(f'Name is {repr(name)}')
Name is 'Rocky'
-
-
Template strings
from string import Template
greeting = Template('Welcome, $name')
greeting.substitute(name='Frida!')
-
String modulo operator
-
Lists can mix types
a = ['foo', 69, 'bar']
-
Lists support slices (these ones are mutable and can even be used to change the size of the list)
a[0:2]
: remove the two first elements of the list
a[:0] = a
: insert a copy ot itself at the beginning of the list -
All slice operations return a new list containing the requested elements. So
a[:]
returns a shallow copy ofa
. -
del
can be used to remove elements in a listdel a[2:4]
-
We can do the same with
a[2:4] = []
-
lists can be concatenated with
+
#> [ 1, 2 ] + [ 3, 4, 5]
[1, 2, 3, 4, 5] -
len
: return the number of elements of a list -
Lists can be nested
q = [45, 3]
p = [0, q, 14] -
List unpacking
a = [1, 2, 3, 4]
[a1, a2, a3, a4] = a -
Test if an element is in a list
item in List
-
Test if a list is empty
if my_list:
print("list is not empty")
else:
print("list is empty") -
A list comprehension consists of brackets containing an expression followed by a
for
clause, then zero or morefor
orif
clauses.#> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]#> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)] -
Join the members of a list (as a string)
vowels = ["a", "e", "i", "o", "u"]
vowelsCSV = ",".join(vowels)
print("Vowels are = ", vowelsCSV) -
Methods
-
insert(pos,item)
: insert an item at a given position -
append(elem)
: append an item at the list end -
pop(i)
: remove the item at the given position in the list and return it -
pop()
: remove the last item and return it -
index(item)
: return the index of the first occurrence of the valueitem
-
remove(item)
: remove the first occurrence of the valueitem
-
sort()
: sort the list -
reverse()
: reverse the list -
count(item)
: return the number of occurrences of the valueitem
-
-
Functions
- Functions can have attributes and inner functions.
-
Generator function:
def fibonacci_generator():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
fib_generator = fibonacci_generator()
print(next(fib_generator)) # Prints 0
print(next(fib_generator)) # Prints 1
print(next(fib_generator)) # Prints 1
print(next(fib_generator)) # Prints 2
print(next(fib_generator)) # Prints 3 - Attributes of a function.
-
filter(function,l)
return the list of elementselem
for whichfunction(elem)
is true. -
map(function,l)
return the list of values offunction
called for each element ofl
.
more than one list can be passed tomap
, in this case,function
must have the same number of arguments (if a list is shorter than the other one,function
will be called with the valueNone
)
ifNone
is passed instead of a function,map
returns its arguments#> (None,[1,2,3,4],[5,6,7]) [(1, 5), (2, 6), (3, 7), (4, None)]
-
reduce(function,l)
call function on the two first items, then on the result and the next item…#> reduce(lambda x,y:x+y , [1,2,3,4,5,6])
21
-
A tuple is a number of values separated by a comma
(they may be input with or without parentheses)t=1,2,"azerty"
- Tuples support slicing
-
An empty tuple is created with the syntax:
empty=()
-
A singleton tuple is created with an empty comma
singleton=1,
-
Tuple packing
t=1,2,3
x,y,z=t
- Tuple are immutable: it is not possible ot assign to the individual items of a tuple
- Sequences can be lists, strings, or tuples.
-
Loops
-
Tuple unpacking (all tuples must have the same length):
for a, b in [(1, "one"), (3, "three"), (5, "five")]:
print(a, b)for a, b, c in [(1, "one", "un"), (3, "three", "trois"), (5, "five", "cinq")]:
print(a, b, c)for a, (b, c) in [(1, ("one", "un")), (3, ("three", "trois")), (5, ("five", "cinq"))]:
print(a, b, c) -
When looping through a sequence, the position index and corresponding value can be retrieved at the same time using
enumerate()
for i, v in enumerate(['tic', 'tac', 'toe']):
print(i, v) -
To loop over two or more sequences at the same time, the entries can be paired with
zip()
.
The loop finishes with the shortest sequence.questions = ['name', 'quest', 'favorite color']
answers = ['lancelot', 'the holy grail', 'blue']
for q, a in zip(questions, answers):
print('What is your {0}? It is {1}.'.format(q, a))letters = [ "alpha", "beta", "gamma", "delta" ]
numbers = [ 0, 1, 2, 3 ]
months = [ "jan", "feb", "mar", "apr", "may" ]
for l, n, m in zip (letters, numbers, months):
print(l, n , m)#> l = [[11, 12, 13, 14], [21, 22, 23, 24], [31, 32, 33, 34]]
#> [list(i) for i in zip(*l)]
[[11, 21, 31], [12, 22, 32], [13, 23, 33], [14, 24, 34]] -
To loop over a sequence in reverse, first specify the sequence in a forward direction and then call
reversed()
for i in reversed(range(1, 10, 2)):
print(i) -
To loop over a sequence in sorted order, use
sorted()
function which returns a new sorted list while leaving the source unaltered.basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
for i in sorted(basket):
print(i)#> l = [('apple', 4), ('orange', 5), ('pear', 2)]
#> s = sorted(l, key=lambda x: x[-1])
#> print(s)
[('pear', 2), ('apple', 4), ('orange', 5)] -
Using
set()
on a sequence eliminates duplicate elements. The use ofsorted()
in combination withset()
over a sequence is an idiomatic way to loop over unique elements of the sequence in sorted order..basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
for f in sorted(set(basket)):
print(i)
-
Tuple unpacking (all tuples must have the same length):
-
Create an empty set
s = set()
-
isdisjoint(other)
: Return True if the set has no elements in common with other. Sets are disjoint if and only if their intersection is the empty set. -
issubset(other)
set <= other
: Test whether every element in the set is in other. -
set < other
: Test whether the set is a proper subset of other, that is,set <= other and set != other
. -
issuperset(other)
set >= other
: Test whether every element in other is in the set. -
set > other
: Test whether the set is a proper superset of other, that is,set >= other and set != other
. -
union(*others)
set | other | …
: Return a new set with elements from the set and all others.#> { 1, 2, 3 } | { 4, 5 }
{1, 2, 3, 4, 5}
#> { 1, 2, 3 }.union({ 4, 5 })
{1, 2, 3, 4, 5} -
intersection(*others)
set & other & …
: Return a new set with elements common to the set and all others.#> { 1, 2, 3, 4, } & { 2, 3 }
{2, 3}
#> { 1, 2, 3, 4, }.intersection({ 2, 3 })
{2, 3} -
difference(*others)
set - other - …
: Return a new set with elements in the set that are not in the others.#> { 1, 2, 3, 4, } - { 2, 3, 5, 6 }
{1, 4}
#> { 1, 2, 3, 4, }.difference({ 2, 3, 5, 6 })
{1, 4} -
symmetric_difference(other)
set ^ other
: Return a new set with elements in either the set or other but not both.#> { 1, 2, 3, 4, } ^ { 2, 3, 5, 6 }
{1, 4, 5, 6}
#> { 1, 2, 3, 4, }.symmetric_difference({ 2, 3, 5, 6 })
{1, 4, 5, 6} -
update(*others)
set |= other | …
: Update the set, adding elements from all others. -
intersection_update(*others)
set &= other & …
: Update the set, keeping only elements found in it and all others. -
difference_update(*others)
set -= other | …
: Update the set, removing elements found in others. -
symmetric_difference_update(other)
set ^= other
: Update the set, keeping only elements found in either set, but not in both. -
add(elem)
: Add element elem to the set. -
remove(elem)
: Remove element elem from the set. RaisesKeyError
ifelem
is not contained in the set. -
discard(elem)
: Remove element elem from the set if it is present. -
pop()
: Remove and return an arbitrary element from the set. RaisesKeyError
if the set is empty. -
clear()
: Remove all elements from the set. -
Set comprehension
#> {s**2 for s in range(10)}
{0, 1, 64, 4, 36, 9, 16, 49, 81, 25} -
Sets can only contain immutable types
So, in order to put a dictionary in a set, a kludge must be used, for example:set1 = set()
set1.add(frozenset({("email", "john@example.com"), ("full_name", email["John Doe"]), ("tags", ",".join(["high", "red"]))}))
…
for d in set1:
data = dict(d)
print(f"{data['email']} — {data['full_name']} — {data['tags']}")
-
Syntax
d={'key1':1234,'key2':5678}
d['key3']=43 -
Create an empty dictionary
d = {}
- Keys must be immutable: numbers, strings and tuples containing only numbers, strings and tuples
-
del
can be used to delete entries of a dictionary, it raises aKeyError
if rhe key is not in the mapdel d['key3']
-
When looping through dictionaries, the key and corresponding value can be retrieved at the same time using
items()
knights = {'gallahad': 'the pure', 'robin': 'the brave'}
for k, v in knights.items():
print(k, v) -
Dictionary comprehension
dict1 = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
# Double each value in the dictionary
double_dict1 = {k:v*2 for (k,v) in dict1.items()}
print(double_dict1) -
Methods
-
key in d
: returnTrue
if d has a key key, elseFalse
-
key not in d
: equivalent tonot key in d
-
iter(d)
: return an iterator over the keys of the dictionary, this is a shortcut foriter(d.keys())
-
clear()
: remove all items from the dictionary -
copy()
: return a shallow copy of the dictionary. -
classmethod fromkeys(iterable[, value])
: create a new dictionary with keys fromiterable
and values set tovalue
-
get(key[, default])
: return the value for key ifkey
is in the dictionary, elsedefault
. If default is not given, it defaults toNone
, so that this method never raises aKeyError
-
items()
: return a new view of the dictionary’s items ((key, value)
pairs) -
keys()
: return a new view of the dictionary’s keys -
pop(key[, default])
: ifkey
is in the dictionary, remove it and return its value, else returndefault
. Ifdefault
is not given and key is not in the dictionary, aKeyError
is raised. -
popitem()
: remove and return a(key, value)
pair from the dictionary. Pairs are returned in LIFO order. If the dictionary is empty, callingpopitem()
raises aKeyError
. -
reversed(d)
: return a reverse iterator over the keys of the dictionary. This is a shortcut forreversed(d.keys()).
-
setdefault(key[, default])
: ifkey
is in the dictionary, return its value. If not, insertkey
with a value ofdefault
and returndefault
.default
defaults toNone
. -
update([other])
: update the dictionary with the key/value pairs from other, overwriting existing keys. ReturnNone
.update()
accepts either another dictionary object or an iterable of key/value pairs (as tuples or other iterables of length two). If keyword arguments are specified, the dictionary is then updated with those key/value pairs:d.update(red=1, blue=2)
. -
values()
: return a new view of the dictionary’s values. -
d | other
: create a new dictionary with the merged keys and values ofd
andother
, which must both be dictionaries. The values ofother
take priority whend
andother
share keys. -
d |= other
: update the dictionary d with keys and values fromother
, which may be either a mapping or an iterable of key/value pairs. The values ofother
take priority when d and other share keys. -
The objects returned by
dict.keys()
,dict.values
(), anddict.items(
) are view objects. They provide a dynamic view on the dictionary’s entries, which means that when the dictionary changes, the view reflects these changes.
Dictionary views can be iterated over to yield their respective data, and support membership tests:-
len(dictview)
: return the number of entries in the dictionary -
iter(dictview)
: return an iterator over the keys, values or items (represented as tuples of (key, value)) in the dictionary -
x in dictview
: returnTrue
ifx
is in the underlying dictionary’s keys, values or items (in the latter case, x should be a(key, value)
tuple) -
reversed(dictview)
: return a reverse iterator over the keys, values or items of the dictionary. The view will be iterated in reverse order of the insertion. -
dictview.mapping
: return atypes.MappingProxyType
that wraps the original dictionary to which the view refers
-
-
-
Any non-zero integer value is true; zero is false.
For a sequence (string, list…), anything with a non-zero length is true, empty sequences are false. -
if x == 1:
print("one")
elif x == 2:
print("two")
elif x == 3:
print("three")
else:
print("other") -
for
loops on a sequence (string or list) content
Theelse
clause is executed when the list is exhausted
a=[1,2,3]
for x in a:
print x
else:
print "finished" - It is not safe to modify the content of the list being looped on, a copy should be generated
-
while
loops as long a condition is truewhile b < 10:
b = b+1
else:
print "end" -
There is no
do
/while
statement, instead usewhile 1:
line = sys.stdin.readline()
if line == "\n":
break -
Use
range
for iterating over a sequence of numbers
range(stop)
returns[0, 1, 2… stop-1]
range(start, stop)
returns[start, start+1… stop-1]
range(start, stop, incr)
returns[start, start+incr… stop-incr]
#> r = range(-1, -6, -1)
#> for i in r:
#> print(i)
-1
-2
-3
-4
-5 -
break
breaks out of the smallest enclosingfor
orwhile
loop
theelse
clause is not executed -
continue
continues with the next iteration of the loop -
pass
is a noop statement -
Structural Pattern Matching
-
_
is a wildcard always matchingmatch status:
case 400:
return "Bad request"
case 401 | 403 | 404:
return "Not allowed"
case 404:
return "Not found"
case 418:
return "I'm a teapot"
case _:
return "Something’s wrong with the internet"
-
-
Syntax (the docstring is optional):
def myfunction(a,b,c):
"docstring"
# … code -
All variable assignments store value in the local symbol table.
Variable references are looked in the local symbol table, then in the global symbol table and, at last, in the table of built-in names. - Parameters are passed by reference.
-
Function references can be stored in variables.
f=myfunction
-
return
returns theNone
value -
return s
returns thes
value -
Default argument values can be used, they are evaluated only once
def f(a,l=[]):
l.append(a)
return lprint f(1)
prints[1]
print f(2)
prints[1,2]
print f(3)
prints[1,2,3]
To avoid this:def f(a,l=None)
if l is None:
l=[]
l.append(a)
return l -
Parameters can be passed by keywords
def foobar(a,b,c,d):
#…
foobar(0,1,d=4,c=3) -
def quux(pos1, pos2, /, pos_or_kwd1, pos_or_kwd2, *, kwd1, kwd2):
Arguments before/
are positional only.
Arguments between/
and*
can be positional or keyword.
Arguments after*
are keyword only. -
*name
can be used to get an arbitrary number of positional arguments.
**name
can be used to get an arbitrary number of keyword arguments.def quux(*a,**b):
for arg in a: print arg
for kw in b.keys(): print(kw,':',b[kw]) -
A function can return a function
def curry(func, value):
def f(x):
return func(x, value)
return f -
lambda
can be used to create anonymous functions
They are restricted to a single expressionlambda a,b:a+b
def make_incrementator(n)
return lambda x,incr=n:x+incr
-
The generic pattern is:
import functools
def decorator(func):
@functools.wraps(func)
def wrapper_decorator(*args, **kwargs):
# Do something before
value = func(*args, **kwargs)
# Do something after
return value
return wrapper_decorator
@decorator
def decoratee():
…@functools.wraps(func)
ensures that the decorated function retains its original identity. -
Example of a decorator with arguments:
import functools
def repeat(num_times):
def decorator_repeat(func):
@functools.wraps(func)
def wrapper_repeat(*args, **kwargs):
for _ in range(num_times):
value = func(*args, **kwargs)
return value
return wrapper_repeat
return decorator_repeat
@repeat(num_times=4)
def greet(name):
print(f"Hello {name}")
-
A module is a file containing Python definitions and statements.
The statements are executed the first time the module is imported. -
Imports
-
Syntax overview
Syntax Example Usage import module_name
import math
Imports the entire module and makes it available under its original name. import module_name as alias
import pandas as pd
Imports the entire module and makes it available under a specified alias. from module_name import attribute
from math import pi
Imports specific attributes (functions, classes, variables) from a module. from module_name import attribute1, attribute2
from math import pi, sqrt
Imports multiple specific attributes from a module. from module_name import *
from math import *
Imports all attributes from a module. This is generally discouraged because it can lead to namespace pollution and conflicts. from module_name import attribute as alias
from math import sqrt as square_root
Imports a specific attribute from a module and makes it available under a specified alias. import module_name.submodule_name
import os.path
Imports a submodule from a module. import module_name.submodule_name as alias
import os.path as osp
Imports a submodule from a module and makes it available under a specified alias. module = __import__("module_name")
pd = __import__("pandas")
Imports a module programmatically. This is less common and typically used in dynamic or metaprogramming scenarios. from . import module_name
from . import utils
Used within a package to import modules relative to the current module’s location (same-level module). from .. import module_name
from .. import utils
Used within a package to import modules relative to the current module’s location (parent-level module). -
Syntax to import a module
import mymodule
mymod.myfunc(2) -
If the module name is followed by
as
, then the name followingas
is bound directly to the imported module.import mymodule as mydmod
-
Symbols of the imported module can be declared in the importing module’s symbol table.
from mymod import myfunc, myfunc2
All symbols (except those beginning by an underscore) can be declared in the importing module’s symbol table.
from mymod import *
-
pd = __import__('pandas')
is the same asimport pandas as pd
.
-
Syntax overview
-
Reload a module.
reload(mymod)
-
Inside a module, its name is defined in
__name__
. -
sys.builtin_module_names
lists the modules compiled in the interpreter. -
When you run a module with
python mymodule.py <arguments>
__name__
set to__main__
. -
Module path
-
Modules are looked for in the directories listed by
sys.path
(which is initially defined by the environment variable$PYTHONPATH
) -
Append a new directory to the path:
sys.path.append('C:\\windows\desktop')
-
Modules are looked for in the directories listed by
-
dir
returns a list of the names defined in a module.
dir(mymod)
dir
can also be used to get the methods and attributes of an object.
Without arguments,dir()
return the list of names in the current local scope. -
__builtin__
is the standard module. -
__all__
can be used in a module to define the symbols that should be imported when the module is imported with a wildcard (from <module> import *
). But the other symbols can still be imported by stating them explicitly (from <module> import <symbol>
). -
Absolute imports: if
foo.py
is indir/subdir
, it can be imported asimport dir.subdir.foo
.
Relative imports: ifbar.py
is in the same directory, it can useimport .foo
.
-
Packages are structured as directories containing the file
__init__.py
(possibly empty) and other files being modules - A package can also contain subdirectories (i.e. subpackages)
-
__init__.py
can define__all__
variable which is the list of the modules which should be imported when the syntaxfrom mypackage import *
is used.
-
The definition of a class starts with the declaration
class:
-
The initialisation method is
__init__
class Complex:
def __init__(self, realpart, imagpart):
self.r = realpart
self.i = imagpart -
The
__str__
function controls what should be returned when the class object is represented as a string.class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"{self.name}({self.age})" -
The
self
parameter is a reference to the current instance of the class, and is used to access variables that belongs to the class.
It does not have to be namedself
, but it has to be the first parameter of any function in the class. -
There is no data privacy, properties can be modified (
p1.age = 40
) or deleted (del p1.age
). -
Inheritance
class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname
class Student(Person):
def __init__(self, fname, lname, year):
super().__init__(fname, lname)
self.graduationyear = year -
isinstance(object, classinfo)
: returnTrue
if the object argument is an instance of theclassinfo
argument, or of a (direct, indirect, or virtual) subclass thereof. -
issubclass(class, classinfo)
: returnTrue
if class is a subclass (direct, indirect, or virtual) ofclassinfo
. A class is considered a subclass of itself. -
Private methods are indicated with the
__
prefix.
Protected methods are indicated with the_
prefix.
-
is
tests if two objects are the same. -
is not
tests if two objects are not the same. -
id()
returns an integer representing the identity of the object (currently implemented as its address). -
type()
returns the type of an object.
-
Types can be declared using:
def surface_area_of_cube(edge_length: float) -> str:
return f"The surface area of the cube is {6 * edge_length ** 2}." -
A type alias is defined using the
type
statement, which creates an instance ofTypeAliasType
.type Vector = list[float]
Vector = list[float]
from typing import TypeAlias
Vector: TypeAlias = list[float] -
Use the NewType helper to create distinct types:
from typing import NewType
UserId = NewType('UserId', int)
some_id = UserId(524313)
-
BaseException
is the common base class of all exceptions.
One of its subclasses,Exception
, is the base class of all the non-fatal exceptions.
Exceptions which are not subclasses ofException
are not typically handled, because they are used to indicate that the program should terminate. They includeSystemExit
which is raised bysys.exit()
andKeyboardInterrupt
which is raised when a user wishes to interrupt the program. - The exception hierarchy is here.
-
Use
try
to declare the tentative code block andexcept
to catch the exception.try:
…
except ValueError:
… -
It is possible to have several exceptions with the same handler and several handlers with the same
try
clause.try:
…
except (RuntimeError, TypeError, NameError):
…
except ValueError:
… -
A final
except
handler will catch all exceptions.try:
…
except (RuntimeError, TypeError, NameError):
…
except:
… -
An
else
clause may be added after the exception handlers, it will be executed anytime no exception occurred.try:
…
except (RuntimeError, TypeError, NameError):
…
else:
… -
It is possible to retrieve the exception details by adding a variable name after the exception list.
try:
…
except IOError, (errno, strerror):
…
except ZeroDivisionError, detail:
… -
A
finally
block can be used: it will be always executed.try:
…
finally:
…-
If an exception occurs during execution of the
try
clause, the exception may be handled by anexcept
clause. If the exception is not handled by anexcept
clause, the exception is re-raised after thefinally
clause has been executed. -
An exception could occur during execution of an
except
orelse
clause. Again, the exception is re-raised after thefinally
clause has been executed. -
If the
finally
clause executes abreak
,continue
, orreturn
statement, exceptions are not re-raised. -
If the
try
statement reaches abreak
,continue
, orreturn
statement, thefinally
clause will execute just prior to thebreak
,continue
, orreturn
statement’s execution. -
If a
finally
clause includes areturn
statement, the returned value will be the one from the finally clause’sreturn
statement, not the value from the try clause’sreturn
statement.
-
If an exception occurs during execution of the
-
raise
can be used to raise an exception, it is followed by a class (it will be implicitly instantiated by calling its constructor with no arguments) or an instance.raise NameError, 'HiThere'
-
raise
with no argument reraises the current exception. - Exceptions are automatically chained: if an unhandled exception occurs inside an except section, it will have the exception being handled attached to it and included in the error message
-
Exceptions can be explicitly chained using
from
try:
func()
except ConnectionError as exc:
raise RuntimeError('Failed to open database') from exc -
Chaining can be disabled using
from None
-
add_note
can be used to add some text to an exceptiontry:
raise TypeError('bad type')
except Exception as e:
e.add_note('Add some information')
e.add_note('Add some more information')
raise -
The built-in
ExceptionGroup
wraps a list of exception instances so that they can be raised together. It is an exception itself, so it can be caught like any other exception.def f():
excs = [OSError('error 1'), SystemError('error 2')]
raise ExceptionGroup('there were problems', excs)excs = []
for test in tests:
try:
test.run()
except Exception as e:
excs.append(e)
if excs:
raise ExceptionGroup("Test Failures", excs) -
By using
except*
instead ofexcept
, we can selectively handle only the exceptions in the group that match a certain type, while letting all other exceptions propagate to other clauses and eventually to be reraised.
- Assert statements are a convenient way to insert debugging assertions into a program:
-
The simple form,
assert expression
, is equivalent toif __debug__:
if not expression: raise AssertionError -
The extended form,
assert expression1, expression2
, is equivalent toif __debug__:
if not expression1: raise AssertionError(expression2) -
These equivalences assume that
__debug__
andAssertionError
refer to the built-in variables with those names.
In the current implementation, the built-in variable__debug__
isTrue
under normal circumstances,False
when optimization is requested (command line option-O
). The current code generator emits no code for an assert statement when optimization is requested at compile time.
with
-
The
with
statement allows objects like files to be used in a way that ensures they are always cleaned up promptly and correctly.with open("myfile.txt") as f:
for line in f:
print(line, end="")
time
-
time.sleep(secs)
: suspend execution of the calling thread for the given number of seconds. The argument may be a floating point number to indicate a more precise sleep time.
getpass
-
getpass.getpass(prompt='Password: ', stream=None)
: prompt the user for a password without echoing.
random
-
random.randrange(stop)
random.randrange(start, stop[, step])
: return a randomly selected element fromrange(start, stop, step)
. -
random.random()
: return a random floating point number in the range 0.0 <= X < 1.0. -
random.choice(seq)
: return a random element from the non-empty sequenceseq
.
os
-
os.listdir(path='.')
: return a list containing the names of the entries in the directory given bypath
. -
os.path.commonpath(paths)
return the longest common sub-path of each pathname in the iterable paths.#> paths = ['/usr/local/bin', '/usr/bin']
#> prefix = os.path.commonpath(paths)
#> print("Longest common sub-path:", prefix)
Longest common sub-path: \usr -
os.walk(top, topdown=True, onerror=None, followlinks=False)
: generate the file names in a directory tree by walking the tree either top-down or bottom-up. For each directory in the tree rooted at directory top (including top itself), it yields a 3-tuple(dirpath, dirnames, filenames)
.
-
Virtual environments are managed by the
venv
module. -
Create a virtual environment
#> python -m venv /path/to/new/virtual/environment
-
A common directory location for a virtual environment is
.venv
. -
In order to activate the environment, some scripts are generated for each Linux/Windows shell.
-
For bash
#> source <venv>/bin/activate
-
For Windows bat
#> <venv>\Scripts\activate
-
For PowerShell
#> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process
#> <venv>\Scripts\Activate.ps1
-
For bash
-
To deactivate the environment:
#> deactivate
-
To know the current environment:
#> echo $VIRTUAL_ENV
unittest (doc)
-
A testcase is created by subclassing
unittest.TestCase
. The three individual tests are defined with methods whose names start with the letterstest
. -
assertEqual()
: check for an expected result -
assertTrue()
orassertFalse()
: verify a condition -
assertRaises()
: verify that a specific exception gets raised -
example
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main() -
setUp()
andtearDown()
: define instructions that will be executed before and after each test method -
The unittest module can be used from the command line to run tests from modules, classes, or individual test methods:
python -m unittest test_module1 test_module2
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method
Running with a file name is a kludge to be able to use with the shell file name autocompletion, it removes the.py
extension and replaces/
by.
.
#> python -m unittest tests/test_something.py
- Function names should be lowercase, with words separated by underscores.
- Variable names should be lowercase, with words separated by underscores.