Execute the Python code in#> python -c <command><command>.<command>can be one or more statements separated by newlines, with significant leading whitespace as in normal module code.
Search#> python -m <module>sys.pathfor 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 delcan 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()
intests if a value is in a sequence.not intests if a value is not in a sequence- The operators
isandis notcompare whether two objects are really the same object. and,or, andnotare Boolean operators
andandorperform a shortcut evaluation
#> print('' or 'a' or 'b')
a- Comparisons can be chained:
a < b == ctests whetherais less thanband moreoverbequalsc.
- 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
jorJto indicate the complex part.
1+2jor with thecomplexfunction (complex(1,2)). realandimagcan 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"*5is"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
but not for slices#> "language"[42]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range#> "language"[3:42]
'guage' lenreturn 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
It is possible to pad with another character than space#> 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
This is the same as#> 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 of 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. delcan 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
forclause, then zero or morefororifclauses.#> [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 positionappend(elem): append an item at the list endpop(i): remove the item at the given position in the list and return itpop(): remove the last item and return itindex(item): return the index of the first occurrence of the valueitemremove(item): remove the first occurrence of the valueitemsort(): sort the listreverse(): reverse the listcount(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 elementselemfor whichfunction(elem)is true.map(function,l)return the list of values offunctioncalled for each element ofl.
more than one list can be passed tomap, in this case,functionmust have the same number of arguments (if a list is shorter than the other one,functionwill be called with the valueNone)
ifNoneis passed instead of a function,mapreturns 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…
a third argument can be passed to indicate the starting value (this value will be returned in case of an empty list)#> 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
Tuple unpackingt=1,2,3x,y,z=t - Tuple are immutable: it is not possible to 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))
So, to transpose a list of lists: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. RaisesKeyErrorifelemis 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. RaisesKeyErrorif 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
delcan be used to delete entries of a dictionary, it raises aKeyErrorif 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: returnTrueif d has a key key, elseFalsekey not in d: equivalent tonot key in diter(d): return an iterator over the keys of the dictionary, this is a shortcut foriter(d.keys())clear(): remove all items from the dictionarycopy(): return a shallow copy of the dictionary.classmethod fromkeys(iterable[, value]): create a new dictionary with keys fromiterableand values set tovalueget(key[, default]): return the value for key ifkeyis in the dictionary, elsedefault. If default is not given, it defaults toNone, so that this method never raises aKeyErroritems(): return a new view of the dictionary’s items ((key, value)pairs)keys(): return a new view of the dictionary’s keyspop(key[, default]): ifkeyis in the dictionary, remove it and return its value, else returndefault. Ifdefaultis not given and key is not in the dictionary, aKeyErroris 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]): ifkeyis in the dictionary, return its value. If not, insertkeywith a value ofdefaultand returndefault.defaultdefaults 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 ofdandother, which must both be dictionaries. The values ofothertake priority whendandothershare 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 ofothertake 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 dictionaryiter(dictview): return an iterator over the keys, values or items (represented as tuples of (key, value)) in the dictionaryx in dictview: returnTrueifxis 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.MappingProxyTypethat 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")forloops on a sequence (string or list) content
Theelseclause 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
whileloops as long a condition is truewhile b < 10:
b = b+1
else:
print "end"- There is no
do/whilestatement, instead usewhile 1:
line = sys.stdin.readline()
if line == "\n":
break - Use
rangefor 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 breakbreaks out of the smallest enclosingfororwhileloop
theelseclause is not executedcontinuecontinues with the next iteration of the looppassis 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 returnreturns theNonevaluereturn sreturns thesvalue- 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.*namecan be used to get an arbitrary number of positional arguments.
**namecan 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 lambdacan be used to create anonymous functions
They are restricted to a single expression
Another example using a default argument valuelambda a,b:a+bdef 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_nameimport mathImports the entire module and makes it available under its original name. import module_name as aliasimport pandas as pdImports the entire module and makes it available under a specified alias. from module_name import attributefrom math import piImports specific attributes (functions, classes, variables) from a module. from module_name import attribute1, attribute2from math import pi, sqrtImports 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 aliasfrom math import sqrt as square_rootImports a specific attribute from a module and makes it available under a specified alias. import module_name.submodule_nameimport os.pathImports a submodule from a module. import module_name.submodule_name as aliasimport os.path as ospImports 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_namefrom . import utilsUsed within a package to import modules relative to the current module’s location (same-level module). from .. import module_namefrom .. import utilsUsed 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 followingasis 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_nameslists the modules compiled in the interpreter.- When you run a module with
The code in the module will be executed, just as if you imported it, but withpython 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
dirreturns a list of the names defined in a module.
dir(mymod)
dircan 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.pyis indir/subdir, it can be imported asimport dir.subdir.foo.
Relative imports: ifbar.pyis 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__.pycan 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
selfparameter 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): returnTrueif the object argument is an instance of theclassinfoargument, or of a (direct, indirect, or virtual) subclass thereof.issubclass(class, classinfo): returnTrueif 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. __slots____slots__is a class variable that is usually assigned a sequence of strings that are variable names used by instances.
Theclass Example():
__slots__ = ("slot_0", "slot_1")
def __init__(self):
self.slot_0 = "zero"
self.slot_1 = "one"__slots__declaration allows us to explicitly declare data members, causes Python to reserve space for them in memory, and prevents the creation of__dict__and__weakref__attributes. It also prevents the creation of any variables that aren't declared in__slots__.- There are a few things to be aware of when going beyond the basics. Slots variables declared in parents are available in child classes. However, child subclasses will have
__dict__and__weakref__attributes unless they also define__slots__, which should only contain names of additional slots. Multiple inheritance with multiple slotted parent classes can be used, but only one parent is allowed to have attributes created by slots. The other bases must have empty slot layouts. - Certain Python objects may depend on the
__dict__attribute. For example, descriptor classes depend on the__dict__attribute being present in the owner class. Programmers may want to avoid__slots__in any case where another Python object requires__dict__or__weakref__to be present. Thefunctools.cached_property()is another example that requires an instance dictionary to function correctly.
istests if two objects are the same.is nottests 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
typestatement, which creates an instance ofTypeAliasType.
Before Python 3.12, the syntax wastype Vector = list[float]
orVector = list[float]from typing import TypeAlias
Vector: TypeAlias = list[float] - Use the NewType helper to create distinct types:
The static type checker will treat the new type as if it were a subclass of the original type.from typing import NewType
UserId = NewType('UserId', int)
some_id = UserId(524313)
BaseExceptionis 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 ofExceptionare not typically handled, because they are used to indicate that the program should terminate. They includeSystemExitwhich is raised bysys.exit()andKeyboardInterruptwhich is raised when a user wishes to interrupt the program.- The exception hierarchy is here.
- Use
tryto declare the tentative code block andexceptto catch the exception.try:
…
except ValueError:
… - It is possible to have several exceptions with the same handler and several handlers with the same
tryclause.try:
…
except (RuntimeError, TypeError, NameError):
…
except ValueError:
… - A final
excepthandler will catch all exceptions.try:
…
except (RuntimeError, TypeError, NameError):
…
except:
… - An
elseclause 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
finallyblock can be used: it will be always executed.try:
…
finally:
…- If an exception occurs during execution of the
tryclause, the exception may be handled by anexceptclause. If the exception is not handled by anexceptclause, the exception is re-raised after thefinallyclause has been executed. - An exception could occur during execution of an
exceptorelseclause. Again, the exception is re-raised after thefinallyclause has been executed. - If the
finallyclause executes abreak,continue, orreturnstatement, exceptions are not re-raised. - If the
trystatement reaches abreak,continue, orreturnstatement, thefinallyclause will execute just prior to thebreak,continue, orreturnstatement’s execution. - If a
finallyclause includes areturnstatement, the returned value will be the one from the finally clause’sreturnstatement, not the value from the try clause’sreturnstatement.
- If an exception occurs during execution of the
raisecan 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'raisewith 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
fromtry:
func()
except ConnectionError as exc:
raise RuntimeError('Failed to open database') from exc - Chaining can be disabled using
from None add_notecan 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
ExceptionGroupwraps 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.
ordef 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__andAssertionErrorrefer to the built-in variables with those names.
In the current implementation, the built-in variable__debug__isTrueunder normal circumstances,Falsewhen 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
withstatement 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="")
timetime.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.
getpassgetpass.getpass(prompt='Password: ', stream=None): prompt the user for a password without echoing.
randomrandom.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.
osos.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: \usros.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
venvmodule. - 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 resultassertTrue()orassertFalse(): verify a conditionassertRaises(): 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.pyextension 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.