A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://gto76.github.io/python-cheatsheet/ below:

Comprehensive Python Cheatsheet

July 31, 2025 Comprehensive Python Cheatsheet
ToC = {
    '1. Collections': [List, Dictionary, Set, Tuple, Range, Enumerate, Iterator, Generator],
    '2. Types':       [Type, String, Regular_Exp, Format, Numbers, Combinatorics, Datetime],
    '3. Syntax':      [Function, Inline, Import, Decorator, Class, Duck_Type, Enum, Except],
    '4. System':      [Exit, Print, Input, Command_Line_Arguments, Open, Path, OS_Commands],
    '5. Data':        [JSON, Pickle, CSV, SQLite, Bytes, Struct, Array, Memory_View, Deque],
    '6. Advanced':    [Operator, Match_Stmt, Logging, Introspection, Threading, Coroutines],
    '7. Libraries':   [Progress_Bar, Plot, Table, Console_App, GUI, Scraping, Web, Profile],
    '8. Multimedia':  [NumPy, Image, Animation, Audio, Synthesizer, Pygame, Pandas, Plotly]
}
#Main
if __name__ == '__main__':      
    main()                      
#List
<list> = [<el_1>, <el_2>, ...]  
<el>   = <list>[index]          
<list> = <list>[<slice>]        
<list>.append(<el>)             
<list>.extend(<collection>)     
<list>.sort()                   
<list>.reverse()                
<list> = sorted(<collection>)   
<iter> = reversed(<list>)       
<el>  = max(<collection>)       
<num> = sum(<collection>)       
elementwise_sum  = [sum(pair) for pair in zip(list_a, list_b)]
sorted_by_second = sorted(<collection>, key=lambda el: el[1])
sorted_by_both   = sorted(<collection>, key=lambda el: (el[1], el[0]))
flatter_list     = list(itertools.chain.from_iterable(<list>))
<int> = len(<list>)             
<int> = <list>.count(<el>)      
<int> = <list>.index(<el>)      
<el>  = <list>.pop()            
<list>.insert(<int>, <el>)      
<list>.remove(<el>)             
<list>.clear()                  
#Dictionary
<dict> = {key_1: val_1, key_2: val_2, ...}      
<view> = <dict>.keys()                          
<view> = <dict>.values()                        
<view> = <dict>.items()                         
value  = <dict>.get(key, default=None)          
value  = <dict>.setdefault(key, default=None)   
<dict> = collections.defaultdict(<type>)        
<dict> = collections.defaultdict(lambda: 1)     
<dict> = dict(<collection>)                     
<dict> = dict(zip(keys, values))                
<dict> = dict.fromkeys(keys [, value])          
<dict>.update(<dict>)                           
value = <dict>.pop(key)                         
{k for k, v in <dict>.items() if v == value}    
{k: v for k, v in <dict>.items() if k in keys}  
Counter
>>> from collections import Counter
>>> counter = Counter(['blue', 'blue', 'blue', 'red', 'red'])
>>> counter['yellow'] += 1
>>> print(counter.most_common())
[('blue', 3), ('red', 2), ('yellow', 1)]
#Set
<set> = {<el_1>, <el_2>, ...}                   
<set>.add(<el>)                                 
<set>.update(<collection> [, ...])              
<set>  = <set>.union(<coll.>)                   
<set>  = <set>.intersection(<coll.>)            
<set>  = <set>.difference(<coll.>)              
<set>  = <set>.symmetric_difference(<coll.>)    
<bool> = <set>.issubset(<coll.>)                
<bool> = <set>.issuperset(<coll.>)              
<el> = <set>.pop()                              
<set>.remove(<el>)                              
<set>.discard(<el>)                             
Frozen Set
<frozenset> = frozenset(<collection>)
#Tuple

Tuple is an immutable and hashable list.

<tuple> = ()                               
<tuple> = (<el>,)                          
<tuple> = (<el_1>, <el_2> [, ...])         
Named Tuple

Tuple's subclass with named elements.

>>> from collections import namedtuple
>>> Point = namedtuple('Point', 'x y')
>>> p = Point(1, y=2)
>>> print(p)
Point(x=1, y=2)
>>> p.x, p[1]
(1, 2)
#Range

Immutable and hashable sequence of integers.

<range> = range(stop)                      
<range> = range(start, stop)               
<range> = range(start, stop, ±step)        
>>> [i for i in range(3)]
[0, 1, 2]
#Enumerate
for i, el in enumerate(<coll>, start=0):   
    ...
#Iterator

Potentially endless stream of elements.

<iter> = iter(<collection>)                
<iter> = iter(<function>, to_exclusive)    
<el>   = next(<iter> [, default])          
<list> = list(<iter>)                      
Itertools
import itertools as it
<iter> = it.count(start=0, step=1)         
<iter> = it.repeat(<el> [, times])         
<iter> = it.cycle(<collection>)            
<iter> = it.chain(<coll>, <coll> [, ...])  
<iter> = it.chain.from_iterable(<coll>)    
<iter> = it.islice(<coll>, to_exclusive)   
<iter> = it.islice(<coll>, from_inc, …)    
#Generator
def count(start, step):
    while True:
        yield start
        start += step
>>> counter = count(10, 2)
>>> next(counter), next(counter), next(counter)
(10, 12, 14)
#Type
<type> = type(<el>)                          
<bool> = isinstance(<el>, <type>)            
>>> type('a'), 'a'.__class__, str
(<class 'str'>, <class 'str'>, <class 'str'>)
Some types do not have built-in names, so they must be imported:
from types import FunctionType, MethodType, LambdaType, GeneratorType, ModuleType
Abstract Base Classes

Each abstract base class specifies a set of virtual subclasses. These classes are then recognized by isinstance() and issubclass() as subclasses of the ABC, although they are really not. ABC can also manually decide whether or not a specific class is its virtual subclass, usually based on which methods the class has implemented. For instance, Iterable ABC looks for method iter(), while Collection ABC looks for iter(), contains() and len().

>>> from collections.abc import Iterable, Collection, Sequence
>>> isinstance([1, 2, 3], Iterable)
True
┏━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━┯━━━━━━━━━━━━┯━━━━━━━━━━━━┓
┃                  │  Iterable  │ Collection │  Sequence  ┃
┠──────────────────┼────────────┼────────────┼────────────┨
┃ list, range, str │     ✓      │     ✓      │     ✓      ┃
┃ dict, set        │     ✓      │     ✓      │            ┃
┃ iter             │     ✓      │            │            ┃
┗━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━┷━━━━━━━━━━━━┷━━━━━━━━━━━━┛
>>> from numbers import Number, Complex, Real, Rational, Integral
>>> isinstance(123, Number)
True
┏━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━┓
┃                    │  Number  │  Complex │   Real   │ Rational │ Integral ┃
┠────────────────────┼──────────┼──────────┼──────────┼──────────┼──────────┨
┃ int                │    ✓     │    ✓     │    ✓     │    ✓     │    ✓     ┃
┃ fractions.Fraction │    ✓     │    ✓     │    ✓     │    ✓     │          ┃
┃ float              │    ✓     │    ✓     │    ✓     │          │          ┃
┃ complex            │    ✓     │    ✓     │          │          │          ┃
┃ decimal.Decimal    │    ✓     │          │          │          │          ┃
┗━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━┛
#String

Immutable sequence of characters.

<str>  = <str>.strip()                       
<str>  = <str>.strip('<chars>')              
<list> = <str>.split()                       
<list> = <str>.split(sep=None, maxsplit=-1)  
<list> = <str>.splitlines(keepends=False)    
<str>  = <str>.join(<coll_of_strings>)       
<bool> = <sub_str> in <str>                  
<bool> = <str>.startswith(<sub_str>)         
<int>  = <str>.find(<sub_str>)               
<str>  = <str>.lower()                       
<str>  = <str>.casefold()                    
<str>  = <str>.replace(old, new [, count])   
<str>  = <str>.translate(<table>)            
<str>  = chr(<int>)                          
<int>  = ord(<str>)                          
Property Methods
<bool> = <str>.isdecimal()                   
<bool> = <str>.isdigit()                     
<bool> = <str>.isnumeric()                   
<bool> = <str>.isalnum()                     
<bool> = <str>.isprintable()                 
<bool> = <str>.isspace()                     
#Regex

Functions for regular expression matching.

import re
<str>   = re.sub(r'<regex>', new, text, count=0)  
<list>  = re.findall(r'<regex>', text)            
<list>  = re.split(r'<regex>', text, maxsplit=0)  
<Match> = re.search(r'<regex>', text)             
<Match> = re.match(r'<regex>', text)              
<iter>  = re.finditer(r'<regex>', text)           
Match Object
<str>   = <Match>.group()                         
<str>   = <Match>.group(1)                        
<tuple> = <Match>.groups()                        
<int>   = <Match>.start()                         
<int>   = <Match>.end()                           
Special Sequences
'\d' == '[0-9]'                                   
'\w' == '[a-zA-Z0-9_]'                            
'\s' == '[ \t\n\r\f\v]'                           
#Format
<str> = f'{<el_1>}, {<el_2>}'            
<str> = '{}, {}'.format(<el_1>, <el_2>)  
<str> = '%s, %s' % (<el_1>, <el_2>)      
Example
>>> Person = collections.namedtuple('Person', 'name height')
>>> person = Person('Jean-Luc', 187)
>>> f'{person.name} is {person.height / 100} meters tall.'
'Jean-Luc is 1.87 meters tall.'
General Options
{<el>:<10}                               
{<el>:^10}                               
{<el>:>10}                               
{<el>:.<10}                              
{<el>:0}                                 
Strings
{'abcde':10}                             
{'abcde':10.3}                           
{'abcde':.3}                             
{'abcde'!r:10}                           
Numbers
{123456:10}                              
{123456:10,}                             
{123456:10_}                             
{123456:+10}                             
{123456:=+10}                            
{123456: }                               
{-123456: }                              
Floats
{1.23456:10.3}                           
{1.23456:10.3f}                          
{1.23456:10.3e}                          
{1.23456:10.3%}                          
Comparison of presentation types:
┏━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━┓
┃              │    {<float>}   │   {<float>:f}  │   {<float>:e}  │   {<float>:%}  ┃
┠──────────────┼────────────────┼────────────────┼────────────────┼────────────────┨
┃  0.000056789 │   '5.6789e-05' │    '0.000057'  │ '5.678900e-05' │    '0.005679%' ┃
┃  0.00056789  │   '0.00056789' │    '0.000568'  │ '5.678900e-04' │    '0.056789%' ┃
┃  0.0056789   │   '0.0056789'  │    '0.005679'  │ '5.678900e-03' │    '0.567890%' ┃
┃  0.056789    │   '0.056789'   │    '0.056789'  │ '5.678900e-02' │    '5.678900%' ┃
┃  0.56789     │   '0.56789'    │    '0.567890'  │ '5.678900e-01' │   '56.789000%' ┃
┃  5.6789      │   '5.6789'     │    '5.678900'  │ '5.678900e+00' │  '567.890000%' ┃
┃ 56.789       │  '56.789'      │   '56.789000'  │ '5.678900e+01' │ '5678.900000%' ┃
┗━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━┛

┏━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━┓
┃              │  {<float>:.2}  │  {<float>:.2f} │  {<float>:.2e} │  {<float>:.2%} ┃
┠──────────────┼────────────────┼────────────────┼────────────────┼────────────────┨
┃  0.000056789 │    '5.7e-05'   │      '0.00'    │   '5.68e-05'   │      '0.01%'   ┃
┃  0.00056789  │    '0.00057'   │      '0.00'    │   '5.68e-04'   │      '0.06%'   ┃
┃  0.0056789   │    '0.0057'    │      '0.01'    │   '5.68e-03'   │      '0.57%'   ┃
┃  0.056789    │    '0.057'     │      '0.06'    │   '5.68e-02'   │      '5.68%'   ┃
┃  0.56789     │    '0.57'      │      '0.57'    │   '5.68e-01'   │     '56.79%'   ┃
┃  5.6789      │    '5.7'       │      '5.68'    │   '5.68e+00'   │    '567.89%'   ┃
┃ 56.789       │    '5.7e+01'   │     '56.79'    │   '5.68e+01'   │   '5678.90%'   ┃
┗━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━┛
Ints
{90:c}                                   
{90:b}                                   
{90:X}                                   
#Numbers
<int>      = int(<float/str/bool>)             
<float>    = float(<int/str/bool>)             
<complex>  = complex(real=0, imag=0)           
<Fraction> = fractions.Fraction(<int>, <int>)  
<Decimal>  = decimal.Decimal(<str/int/tuple>)  
Built-in Functions
<num> = pow(<num>, <num>)                      
<num> = abs(<num>)                             
<num> = round(<num> [, ±ndigits])              
<num> = min(<collection>)                      
<num> = sum(<collection>)                      
Math
from math import floor, ceil, trunc            
from math import pi, inf, nan, isnan           
from math import sqrt, factorial               
from math import sin, cos, tan                 
from math import log, log10, log2              
Statistics
from statistics import mean, median, mode      
from statistics import variance, stdev         
Random
from random import random, randint, uniform    
<float> = random()                             
<num>   = randint/uniform(a, b)                
<float> = gauss(mean, stdev)                   
<el>    = choice(<sequence>)                   
shuffle(<list>)                                
Hexadecimal Numbers
<int> = 0x<hex>                                
<int> = int('±<hex>', 16)                      
<str> = hex(<int>)                             
Bitwise Operators
<int> = <int> & <int>                          
<int> = <int> | <int>                          
<int> = <int> ^ <int>                          
<int> = <int> << n_bits                        
<int> = ~<int>                                 
#Combinatorics
import itertools as it
>>> list(it.product('abc', repeat=2))        
[('a', 'a'), ('a', 'b'), ('a', 'c'),         
 ('b', 'a'), ('b', 'b'), ('b', 'c'),         
 ('c', 'a'), ('c', 'b'), ('c', 'c')]         
>>> list(it.permutations('abc', 2))          
[('a', 'b'), ('a', 'c'),                     
 ('b', 'a'), ('b', 'c'),                     
 ('c', 'a'), ('c', 'b')]                     
>>> list(it.combinations('abc', 2))          
[('a', 'b'), ('a', 'c'),                     
 ('b', 'c')                                  
]                                            
#Datetime

Provides 'date', 'time', 'datetime' and 'timedelta' classes. All are immutable and hashable.


from datetime import date, time, datetime, timedelta, timezone
import zoneinfo, dateutil.tz
<D>  = date(year, month, day)               
<T>  = time(hour=0, minute=0, second=0)     
<DT> = datetime(year, month, day, hour=0)   
<TD> = timedelta(weeks=0, days=0, hours=0)  
Now
<D/DTn> = D/DT.today()                      
<DTa>   = DT.now(<tzinfo>)                  
Timezones
<tzinfo> = timezone.utc                     
<tzinfo> = timezone(<timedelta>)            
<tzinfo> = dateutil.tz.tzlocal()            
<tzinfo> = zoneinfo.ZoneInfo('<iana_key>')  
<DTa>    = <DT>.astimezone([<tzinfo>])      
<Ta/DTa> = <T/DT>.replace(tzinfo=<tzinfo>)  
Encode
<D/T/DT> = D/T/DT.fromisoformat(<str>)      
<DT>     = DT.strptime(<str>, '<format>')   
<D/DTn>  = D/DT.fromordinal(<int>)          
<DTn>    = DT.fromtimestamp(<float>)        
<DTa>    = DT.fromtimestamp(<float>, <tz>)  
Decode
<str>    = <D/T/DT>.isoformat(sep='T')      
<str>    = <D/T/DT>.strftime('<format>')    
<int>    = <D/DT>.toordinal()               
<float>  = <DTn>.timestamp()                
<float>  = <DTa>.timestamp()                
Format
>>> dt = datetime.strptime('2025-08-14 23:39:00.00 +0200', '%Y-%m-%d %H:%M:%S.%f %z')
>>> dt.strftime("%dth of %B '%y (%a), %I:%M %p %Z")
"14th of August '25 (Thu), 11:39 PM UTC+02:00"
Arithmetics
<bool>   = <D/T/DTn> > <D/T/DTn>            
<bool>   = <DTa>     > <DTa>                
<TD>     = <D/DTn>   - <D/DTn>              
<TD>     = <DTa>     - <DTa>                
<D/DT>   = <D/DT>    ± <TD>                 
<TD>     = <TD>      * <float>              
<float>  = <TD>      / <TD>                 
#Function

Independent block of code that returns a value when called.

def <func_name>(<nondefault_args>): ...                  
def <func_name>(<default_args>): ...                     
def <func_name>(<nondefault_args>, <default_args>): ...  
Function Call
<obj> = <function>(<positional_args>)                    
<obj> = <function>(<keyword_args>)                       
<obj> = <function>(<positional_args>, <keyword_args>)    
#Splat Operator

Splat expands a collection into positional arguments, while splatty-splat expands a dictionary into keyword arguments.

args, kwargs = (1, 2), {'z': 3}
func(*args, **kwargs)
Is the same as:
func(1, 2, z=3)
Inside Function Definition

Splat combines zero or more positional arguments into a tuple, while splatty-splat combines zero or more keyword arguments into a dictionary.

def add(*a):
    return sum(a)
>>> add(1, 2, 3)
6
Allowed compositions of arguments and the ways they can be called:
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━┓
┃                           │  func(1, 2)  │ func(1, y=2) │ func(x=1, y=2) ┃
┠───────────────────────────┼──────────────┼──────────────┼────────────────┨
┃ func(x, *args, **kwargs): │      ✓       │      ✓       │       ✓        ┃
┃ func(*args, y, **kwargs): │              │      ✓       │       ✓        ┃
┃ func(*, x, **kwargs):     │              │              │       ✓        ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━┛
Other Uses
<list>  = [*<collection> [, ...]]  
<tuple> = (*<collection>, [...])   
<set>   = {*<collection> [, ...]}  
<dict>  = {**<dict> [, ...]}       
head, *body, tail = <collection>   
#Inline Lambda
<func> = lambda: <return_value>                     
<func> = lambda <arg_1>, <arg_2>: <return_value>    
Comprehensions
<list> = [i+1 for i in range(10)]                   
<iter> = (i for i in range(10) if i > 5)            
<set>  = {i+5 for i in range(10)}                   
<dict> = {i: i*2 for i in range(10)}                
>>> [l+r for l in 'abc' for r in 'abc']             
['aa', 'ab', 'ac', ..., 'cc']
Map, Filter, Reduce
from functools import reduce
<iter> = map(lambda x: x + 1, range(10))            
<iter> = filter(lambda x: x > 5, range(10))         
<obj>  = reduce(lambda out, x: out + x, range(10))  
Any, All
<bool> = any(<collection>)                          
<bool> = all(<collection>)                          
Conditional Expression
<obj> = <exp> if <condition> else <exp>             
>>> [i if i else 'zero' for i in (0, 1, 2, 3)]      
['zero', 1, 2, 3]
And, Or
<obj> = <exp> and <exp> [and ...]                   
<obj> = <exp> or <exp> [or ...]                     
Walrus Operator
>>> [i for ch in '0123' if (i := int(ch)) > 0]      
[1, 2, 3]
Named Tuple, Enum, Dataclass
from collections import namedtuple
Point = namedtuple('Point', 'x y')                  
point = Point(0, 0)                                 

from enum import Enum
Direction = Enum('Direction', 'N E S W')            
direction = Direction.N                             

from dataclasses import make_dataclass
Player = make_dataclass('Player', ['loc', 'dir'])   
player = Player(point, direction)                   
#Imports

Mechanism that makes code in one file available to another file.

import <module>            
import <package>           
import <package>.<module>  
#Closure

We have/get a closure in Python when a nested function references a value of its enclosing function and then the enclosing function returns its nested function.

def get_multiplier(a):
    def out(b):
        return a * b
    return out
>>> multiply_by_3 = get_multiplier(3)
>>> multiply_by_3(10)
30
Partial
from functools import partial
<function> = partial(<function> [, <arg_1> [, ...]])
>>> def multiply(a, b):
...     return a * b
>>> multiply_by_3 = partial(multiply, 3)
>>> multiply_by_3(10)
30
Non-Local

If variable is being assigned to anywhere in the scope, it is regarded as a local variable, unless it is declared as a 'global' or a 'nonlocal'.

def get_counter():
    i = 0
    def out():
        nonlocal i
        i += 1
        return i
    return out
>>> counter = get_counter()
>>> counter(), counter(), counter()
(1, 2, 3)
#Decorator

A decorator takes a function, adds some functionality and returns it. It can be any callable, but is usually implemented as a function that returns a closure.

@decorator_name
def function_that_gets_passed_to_decorator():
    ...
Debugger Example

Decorator that prints function's name every time the function is called.

from functools import wraps

def debug(func):
    @wraps(func)
    def out(*args, **kwargs):
        print(func.__name__)
        return func(*args, **kwargs)
    return out

@debug
def add(x, y):
    return x + y
Cache

Decorator that caches function's return values. All function's arguments must be hashable.

from functools import cache

@cache
def fib(n):
    return n if n < 2 else fib(n-2) + fib(n-1)
Parametrized Decorator

A decorator that accepts arguments and returns a normal decorator that accepts a function.

from functools import wraps

def debug(print_result=False):
    def decorator(func):
        @wraps(func)
        def out(*args, **kwargs):
            result = func(*args, **kwargs)
            print(func.__name__, result if print_result else '')
            return result
        return out
    return decorator

@debug(print_result=True)
def add(x, y):
    return x + y
#Class

A template for creating user-defined objects.

class MyClass:
    def __init__(self, a):
        self.a = a
    def __str__(self):
        return str(self.a)
    def __repr__(self):
        class_name = self.__class__.__name__
        return f'{class_name}({self.a!r})'

    @classmethod
    def get_class_name(cls):
        return cls.__name__
>>> obj = MyClass(1)
>>> obj.a, str(obj), repr(obj)
(1, '1', 'MyClass(1)')
Expressions that call the str() method:
print(<obj>)
f'{<obj>}'
logging.warning(<obj>)
csv.writer(<file>).writerow([<obj>])
Expressions that call the repr() method:
print/str/repr([<obj>])
print/str/repr({<obj>: <obj>})
f'{<obj>!r}'
Z = make_dataclass('Z', ['a']); print/str/repr(Z(<obj>))
Subclass
class Person:
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return f'Person({self.name!r})'
    def __lt__(self, other):
        return self.name < other.name

class Employee(Person):
    def __init__(self, name, staff_num):
        super().__init__(name)
        self.staff_num = staff_num
    def __repr__(self):
        return f'Employee({self.name!r}, {self.staff_num})'
>>> people = {Person('Ann'), Employee('Bob', 0)}
>>> sorted(people)
[Person('Ann'), Employee('Bob', 0)]
Type Annotations
from collections import abc

<name>: <type> [| ...] [= <obj>]
<name>: list/set/abc.Iterable/abc.Sequence[<type>] [= <obj>]
<name>: tuple/dict[<type>, ...] [= <obj>]
Dataclass

Decorator that uses class variables to generate init(), repr() and eq() special methods.

from dataclasses import dataclass, field, make_dataclass

@dataclass(order=False, frozen=False)
class <class_name>:
    <attr_name>: <type>
    <attr_name>: <type> = <default_value>
    <attr_name>: list/dict/set = field(default_factory=list/dict/set)
P = make_dataclass('P', ['x', 'y'])
P = make_dataclass('P', [('x', float), ('y', float)])
P = make_dataclass('P', [('x', float, 0), ('y', float, 0)])
Property

Pythonic way of implementing getters and setters.

class Person:
    @property
    def name(self):
        return ' '.join(self._name)

    @name.setter
    def name(self, value):
        self._name = value.split()
>>> person = Person()
>>> person.name = '\t Guido  van Rossum \n'
>>> person.name
'Guido van Rossum'
Slots

Mechanism that restricts objects to attributes listed in 'slots'.

class MyClassWithSlots:
    __slots__ = ['a']
    def __init__(self):
        self.a = 1
Copy
from copy import copy, deepcopy
<object> = copy/deepcopy(<object>)
#Duck Types

A duck type is an implicit type that prescribes a set of special methods. Any object that has those methods defined is considered a member of that duck type.

Comparable
class MyComparable:
    def __init__(self, a):
        self.a = a
    def __eq__(self, other):
        if isinstance(other, type(self)):
            return self.a == other.a
        return NotImplemented
Hashable
class MyHashable:
    def __init__(self, a):
        self._a = a
    @property
    def a(self):
        return self._a
    def __eq__(self, other):
        if isinstance(other, type(self)):
            return self.a == other.a
        return NotImplemented
    def __hash__(self):
        return hash(self.a)
Sortable
from functools import total_ordering

@total_ordering
class MySortable:
    def __init__(self, a):
        self.a = a
    def __eq__(self, other):
        if isinstance(other, type(self)):
            return self.a == other.a
        return NotImplemented
    def __lt__(self, other):
        if isinstance(other, type(self)):
            return self.a < other.a
        return NotImplemented
Iterator
class Counter:
    def __init__(self):
        self.i = 0
    def __next__(self):
        self.i += 1
        return self.i
    def __iter__(self):
        return self
>>> counter = Counter()
>>> next(counter), next(counter), next(counter)
(1, 2, 3)
Python has many different iterator objects: Callable
class Counter:
    def __init__(self):
        self.i = 0
    def __call__(self):
        self.i += 1
        return self.i
>>> counter = Counter()
>>> counter(), counter(), counter()
(1, 2, 3)
Context Manager
class MyOpen:
    def __init__(self, filename):
        self.filename = filename
    def __enter__(self):
        self.file = open(self.filename)
        return self.file
    def __exit__(self, exc_type, exception, traceback):
        self.file.close()
>>> with open('test.txt', 'w') as file:
...     file.write('Hello World!')
>>> with MyOpen('test.txt') as file:
...     print(file.read())
Hello World!
#Iterable Duck Types Iterable
class MyIterable:
    def __init__(self, a):
        self.a = a
    def __iter__(self):
        return iter(self.a)
    def __contains__(self, el):
        return el in self.a
>>> obj = MyIterable([1, 2, 3])
>>> [el for el in obj]
[1, 2, 3]
>>> 1 in obj
True
Collection
class MyCollection:
    def __init__(self, a):
        self.a = a
    def __iter__(self):
        return iter(self.a)
    def __contains__(self, el):
        return el in self.a
    def __len__(self):
        return len(self.a)
Sequence
class MySequence:
    def __init__(self, a):
        self.a = a
    def __iter__(self):
        return iter(self.a)
    def __contains__(self, el):
        return el in self.a
    def __len__(self):
        return len(self.a)
    def __getitem__(self, i):
        return self.a[i]
    def __reversed__(self):
        return reversed(self.a)
Discrepancies between glossary definitions and abstract base classes: ABC Sequence
from collections import abc

class MyAbcSequence(abc.Sequence):
    def __init__(self, a):
        self.a = a
    def __len__(self):
        return len(self.a)
    def __getitem__(self, i):
        return self.a[i]
Table of required and automatically available special methods:
┏━━━━━━━━━━━━┯━━━━━━━━━━━━┯━━━━━━━━━━━━┯━━━━━━━━━━━━┯━━━━━━━━━━━━━━┓
┃            │  Iterable  │ Collection │  Sequence  │ abc.Sequence ┃
┠────────────┼────────────┼────────────┼────────────┼──────────────┨
┃ iter()     │     !      │     !      │     ✓      │      ✓       ┃
┃ contains() │     ✓      │     ✓      │     ✓      │      ✓       ┃
┃ len()      │            │     !      │     !      │      !       ┃
┃ getitem()  │            │            │     !      │      !       ┃
┃ reversed() │            │            │     ✓      │      ✓       ┃
┃ index()    │            │            │            │      ✓       ┃
┃ count()    │            │            │            │      ✓       ┃
┗━━━━━━━━━━━━┷━━━━━━━━━━━━┷━━━━━━━━━━━━┷━━━━━━━━━━━━┷━━━━━━━━━━━━━━┛
#Enum

Class of named constants called members.

from enum import Enum, auto
class <enum_name>(Enum):
    <member_name> = auto()              
    <member_name> = <value>             
    <member_name> = <el_1>, <el_2>      
<member> = <enum>.<member_name>         
<member> = <enum>['<member_name>']      
<member> = <enum>(<value>)              
<str>    = <member>.name                
<obj>    = <member>.value               
<list>   = list(<enum>)                 
<list>   = <enum>._member_names_        
<list>   = [m.value for m in <enum>]    
<enum>   = type(<member>)               
<iter>   = itertools.cycle(<enum>)      
<member> = random.choice(list(<enum>))  
Inline
Cutlery = Enum('Cutlery', 'FORK KNIFE SPOON')
Cutlery = Enum('Cutlery', ['FORK', 'KNIFE', 'SPOON'])
Cutlery = Enum('Cutlery', {'FORK': 1, 'KNIFE': 2, 'SPOON': 3})
User-defined functions cannot be values, so they must be wrapped:
from functools import partial
LogicOp = Enum('LogicOp', {'AND': partial(lambda l, r: l and r),
                           'OR':  partial(lambda l, r: l or r)})
#Exceptions
try:
    <code>
except <exception>:
    <code>
Complex Example
try:
    <code_1>
except <exception_a>:
    <code_2_a>
except <exception_b>:
    <code_2_b>
else:
    <code_2_c>
finally:
    <code_3>
Catching Exceptions
except <exception>: ...
except <exception> as <name>: ...
except (<exception>, [...]): ...
except (<exception>, [...]) as <name>: ...
Raising Exceptions
raise <exception>
raise <exception>()
raise <exception>(<obj> [, ...])
Re-raising caught exception:
except <exception> [as <name>]:
    ...
    raise
Exception Object
arguments = <name>.args
exc_type  = <name>.__class__
filename  = <name>.__traceback__.tb_frame.f_code.co_filename
func_name = <name>.__traceback__.tb_frame.f_code.co_name
line_str  = linecache.getline(filename, <name>.__traceback__.tb_lineno)
trace_str = ''.join(traceback.format_tb(<name>.__traceback__))
error_msg = ''.join(traceback.format_exception(type(<name>), <name>, <name>.__traceback__))
Built-in Exceptions
BaseException
 ├── SystemExit                   
 ├── KeyboardInterrupt            
 └── Exception                    
      ├── ArithmeticError         
      ├── AssertionError          
      ├── AttributeError          
      ├── EOFError                
      ├── LookupError             
      │    ├── IndexError         
      │    └── KeyError           
      ├── MemoryError             
      ├── NameError               
      │    └── UnboundLocalError  
      ├── OSError                 
      │    └── ConnectionError    
      ├── RuntimeError            
      │    ├── NotImplementedEr…  
      │    └── RecursionError     
      ├── StopIteration           
      ├── TypeError               
      └── ValueError              
Collections and their exceptions:
┏━━━━━━━━━━━┯━━━━━━━━━━━━┯━━━━━━━━━━━━┯━━━━━━━━━━━━┓
┃           │    List    │    Set     │    Dict    ┃
┠───────────┼────────────┼────────────┼────────────┨
┃ getitem() │ IndexError │            │  KeyError  ┃
┃ pop()     │ IndexError │  KeyError  │  KeyError  ┃
┃ remove()  │ ValueError │  KeyError  │            ┃
┃ index()   │ ValueError │            │            ┃
┗━━━━━━━━━━━┷━━━━━━━━━━━━┷━━━━━━━━━━━━┷━━━━━━━━━━━━┛
Useful built-in exceptions:
raise TypeError('Argument is of the wrong type!')
raise ValueError('Argument has the right type but an inappropriate value!')
raise RuntimeError('I am too lazy to define my own exception!')
User-defined Exceptions
class MyError(Exception): pass
class MyInputError(MyError): pass
#Exit

Exits the interpreter by raising SystemExit exception.

import sys
sys.exit()                        
sys.exit(<int>)                   
sys.exit(<obj>)                   
#Print
print(<el_1>, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
Pretty Print
from pprint import pprint
pprint(<collection>, width=80, depth=None, compact=False, sort_dicts=True)
#Command Line Arguments
import sys
scripts_path = sys.argv[0]
arguments    = sys.argv[1:]
Argument Parser
from argparse import ArgumentParser, FileType
p = ArgumentParser(description=<str>)                             
p.add_argument('-<short_name>', '--<name>', action='store_true')  
p.add_argument('-<short_name>', '--<name>', type=<type>)          
p.add_argument('<name>', type=<type>, nargs=1)                    
p.add_argument('<name>', type=<type>, nargs='+')                  
p.add_argument('<name>', type=<type>, nargs='?/*')                
args  = p.parse_args()                                            
<obj> = args.<name>                                               
#Open

Opens a file and returns the corresponding file object.

<file> = open(<path>, mode='r', encoding=None, newline=None)
Modes Exceptions File Object
<file>.seek(0)                      
<file>.seek(offset)                 
<file>.seek(0, 2)                   
<bin_file>.seek(±offset, origin)    
<str/bytes> = <file>.read(size=-1)  
<str/bytes> = <file>.readline()     
<list>      = <file>.readlines()    
<str/bytes> = next(<file>)          
<file>.write(<str/bytes>)           
<file>.writelines(<collection>)     
<file>.flush()                      
<file>.close()                      
Read Text from File
def read_file(filename):
    with open(filename, encoding='utf-8') as file:
        return file.readlines()
Write Text to File
def write_to_file(filename, text):
    with open(filename, 'w', encoding='utf-8') as file:
        file.write(text)
#Paths
import os, glob
from pathlib import Path
<str>  = os.getcwd()                
<str>  = os.path.join(<path>, ...)  
<str>  = os.path.realpath(<path>)   
<str>  = os.path.basename(<path>)   
<str>  = os.path.dirname(<path>)    
<tup.> = os.path.splitext(<path>)   
<list> = os.listdir(path='.')       
<list> = glob.glob('<pattern>')     
<bool> = os.path.exists(<path>)     
<bool> = os.path.isfile(<path>)     
<bool> = os.path.isdir(<path>)      
<stat> = os.stat(<path>)            
<num>  = <stat>.st_mtime/st_size/…  
DirEntry

Unlike listdir(), scandir() returns DirEntry objects that cache isfile, isdir, and on Windows also stat information, thus significantly increasing the performance of code that requires it.

<iter> = os.scandir(path='.')       
<str>  = <DirEntry>.path            
<str>  = <DirEntry>.name            
<file> = open(<DirEntry>)           
Path Object
<Path> = Path(<path> [, ...])       
<Path> = <path> / <path> [/ ...]    
<Path> = <Path>.resolve()           
<Path> = Path()                     
<Path> = Path.cwd()                 
<Path> = Path.home()                
<Path> = Path(__file__).resolve()   
<Path> = <Path>.parent              
<str>  = <Path>.name                
<str>  = <Path>.suffix              
<str>  = <Path>.stem                
<tup.> = <Path>.parts               
<iter> = <Path>.iterdir()           
<iter> = <Path>.glob('<pattern>')   
<str>  = str(<Path>)                
<file> = open(<Path>)               
#OS Commands
import os, shutil, subprocess
os.chdir(<path>)                    
os.mkdir(<path>, mode=0o777)        
os.makedirs(<path>, mode=0o777)     
shutil.copy(from, to)               
shutil.copy2(from, to)              
shutil.copytree(from, to)           
os.rename(from, to)                 
os.replace(from, to)                
shutil.move(from, to)               
os.remove(<path>)                   
os.rmdir(<path>)                    
shutil.rmtree(<path>)               
Shell Commands
<pipe> = os.popen('<commands>')     
<str>  = <pipe>.read(size=-1)       
<int>  = <pipe>.close()             
Sends "1 + 1" to the basic calculator and captures its output:
>>> subprocess.run('bc', input='1 + 1\n', capture_output=True, text=True)
CompletedProcess(args='bc', returncode=0, stdout='2\n', stderr='')
Sends test.in to the basic calculator running in standard mode and saves its output to test.out:
>>> from shlex import split
>>> os.popen('echo 1 + 1 > test.in')
>>> subprocess.run(split('bc -s'), stdin=open('test.in'), stdout=open('test.out', 'w'))
CompletedProcess(args=['bc', '-s'], returncode=0)
>>> open('test.out').read()
'2\n'
#JSON

Text file format for storing collections of strings and numbers.

import json
<str>  = json.dumps(<list/dict>)    
<coll> = json.loads(<str>)          
Read Collection from JSON File
def read_json_file(filename):
    with open(filename, encoding='utf-8') as file:
        return json.load(file)
Write Collection to JSON File
def write_to_json_file(filename, collection):
    with open(filename, 'w', encoding='utf-8') as file:
        json.dump(collection, file, ensure_ascii=False, indent=2)
#Pickle

Binary file format for storing Python objects.

import pickle
<bytes>  = pickle.dumps(<object>)   
<object> = pickle.loads(<bytes>)    
Read Object from Pickle File
def read_pickle_file(filename):
    with open(filename, 'rb') as file:
        return pickle.load(file)
Write Object to Pickle File
def write_to_pickle_file(filename, an_object):
    with open(filename, 'wb') as file:
        pickle.dump(an_object, file)
#CSV

Text file format for storing spreadsheets.

import csv
<file>   = open(<path>, newline='')       
<reader> = csv.reader(<file>)             
<list>   = next(<reader>)                 
<list>   = list(<reader>)                 
Write
<file>   = open(<path>, 'w', newline='')  
<writer> = csv.writer(<file>)             
<writer>.writerow(<collection>)           
<writer>.writerows(<coll_of_coll>)        
Parameters Dialects
┏━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━┓
┃                  │     excel    │   excel-tab  │     unix     ┃
┠──────────────────┼──────────────┼──────────────┼──────────────┨
┃ delimiter        │       ','    │      '\t'    │       ','    ┃
┃ lineterminator   │    '\r\n'    │    '\r\n'    │      '\n'    ┃
┃ quotechar        │       '"'    │       '"'    │       '"'    ┃
┃ escapechar       │      None    │      None    │      None    ┃
┃ doublequote      │      True    │      True    │      True    ┃
┃ quoting          │         0    │         0    │         1    ┃
┃ skipinitialspace │     False    │     False    │     False    ┃
┗━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━┛
Read Rows from CSV File
def read_csv_file(filename, **csv_params):
    with open(filename, encoding='utf-8', newline='') as file:
        return list(csv.reader(file, **csv_params))
Write Rows to CSV File
def write_to_csv_file(filename, rows, mode='w', **csv_params):
    with open(filename, mode, encoding='utf-8', newline='') as file:
        writer = csv.writer(file, **csv_params)
        writer.writerows(rows)
#SQLite

A server-less database engine that stores each database into its own file.

import sqlite3
<conn> = sqlite3.connect(<path>)               
<conn>.close()                                 
Read
<cursor> = <conn>.execute('<query>')           
<tuple>  = <cursor>.fetchone()                 
<list>   = <cursor>.fetchall()                 
Write
<conn>.execute('<query>')                      
<conn>.commit()                                
<conn>.rollback()                              
Or:
with <conn>:                                   
    <conn>.execute('<query>')                  
Placeholders
<conn>.execute('<query>', <list/tuple>)        
<conn>.execute('<query>', <dict/namedtuple>)   
<conn>.executemany('<query>', <coll_of_coll>)  
Example

Values are not actually saved in this example because 'conn.commit()' is omitted!

>>> conn = sqlite3.connect('test.db')
>>> conn.execute('CREATE TABLE person (name TEXT, height INTEGER) STRICT')
>>> conn.execute('INSERT INTO person VALUES (?, ?)', ('Jean-Luc', 187))
>>> conn.execute('SELECT rowid, * FROM person').fetchall()
[(1, 'Jean-Luc', 187)]
SQLAlchemy

Library for interacting with various DB systems via SQL, method chaining, or ORM.


from sqlalchemy import create_engine, text
<engine> = create_engine('<url>')              
<conn>   = <engine>.connect()                  
<cursor> = <conn>.execute(text('<query>'), …)  
with <conn>.begin(): ...                       
┏━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Dialect         │ pip3 install │           Dependencies           ┃
┠─────────────────┼──────────────┼──────────────────────────────────┨
┃ mysql           │ mysqlclient  │ www.pypi.org/project/mysqlclient ┃
┃ postgresql      │ psycopg2     │ www.pypi.org/project/psycopg2    ┃
┃ mssql           │ pyodbc       │ www.pypi.org/project/pyodbc      ┃
┃ oracle+oracledb │ oracledb     │ www.pypi.org/project/oracledb    ┃
┗━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
#Bytes

A bytes object is an immutable sequence of single bytes. Mutable version is called bytearray.

<bytes> = b'<str>'                       
<int>   = <bytes>[index]                 
<bytes> = <bytes>[<slice>]               
<bytes> = <bytes>.join(<coll_of_bytes>)  
Encode
<bytes> = bytes(<coll_of_ints>)          
<bytes> = bytes(<str>, 'utf-8')          
<bytes> = bytes.fromhex('<hex>')         
<bytes> = <int>.to_bytes(n_bytes, …)     
Decode
<list>  = list(<bytes>)                  
<str>   = str(<bytes>, 'utf-8')          
<str>   = <bytes>.hex()                  
<int>   = int.from_bytes(<bytes>, …)     
Read Bytes from File
def read_bytes(filename):
    with open(filename, 'rb') as file:
        return file.read()
Write Bytes to File
def write_bytes(filename, bytes_obj):
    with open(filename, 'wb') as file:
        file.write(bytes_obj)
#Struct
from struct import pack, unpack

<bytes> = pack('<format>', <el_1> [, ...])  
<tuple> = unpack('<format>', <bytes>)       
>>> pack('>hhl', 1, 2, 3)
b'\x00\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('>hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
Format For standard type sizes and manual alignment (padding) start format string with: Besides numbers, pack() and unpack() also support bytes objects as a part of the sequence: Integer types. Use a capital letter for unsigned type. Minimum and standard sizes are in brackets: Floating point types (struct always uses standard sizes): #Array

List that can only hold numbers of a predefined type. Available types and their minimum sizes in bytes are listed above. Type sizes and byte order are always determined by the system, however bytes of each element can be reversed (by calling the byteswap() method).

from array import array
<array> = array('<typecode>', <coll_of_nums>)  
<array> = array('<typecode>', <bytes>)         
<array> = array('<typecode>', <array>)         
<array>.fromfile(<file>, n_items)              
<bytes> = bytes(<array>)                       
<file>.write(<array>)                          
#Memory View

A sequence object that points to the memory of another bytes-like object. Each element can reference a single or multiple consecutive bytes, depending on format. Order and number of elements can be changed with slicing.

<mview> = memoryview(<bytes/bytearray/array>)  
<obj>   = <mview>[index]                       
<mview> = <mview>[<slice>]                     
<mview> = <mview>.cast('<typecode>')           
<mview>.release()                              
<bytes> = bytes(<mview>)                       
<bytes> = <bytes>.join(<coll_of_mviews>)       
<array> = array('<typecode>', <mview>)         
<file>.write(<mview>)                          
<list>  = list(<mview>)                        
<str>   = str(<mview>, 'utf-8')                
<str>   = <mview>.hex()                        
#Deque

List with efficient appends and pops from either side.

from collections import deque
<deque> = deque(<collection>)                  
<deque>.appendleft(<el>)                       
<deque>.extendleft(<collection>)               
<deque>.rotate(n=1)                            
<el> = <deque>.popleft()                       
#Operator

Module of functions that provide the functionality of operators. Functions are grouped by operator precedence, from least to most binding. Functions and operators in first, third and fifth line are also ordered by precedence within a group.

import operator as op
<bool> = op.not_(<obj>)                                        
<bool> = op.eq/ne/lt/ge/is_/is_not/contains(<obj>, <obj>)      
<obj>  = op.or_/xor/and_(<int/set>, <int/set>)                 
<int>  = op.lshift/rshift(<int>, <int>)                        
<obj>  = op.add/sub/mul/truediv/floordiv/mod(<obj>, <obj>)     
<num>  = op.neg/invert(<num>)                                  
<num>  = op.pow(<num>, <num>)                                  
<func> = op.itemgetter/attrgetter/methodcaller(<obj> [, ...])  
elementwise_sum  = map(op.add, list_a, list_b)
sorted_by_second = sorted(<coll>, key=op.itemgetter(1))
sorted_by_both   = sorted(<coll>, key=op.itemgetter(1, 0))
first_element    = op.methodcaller('pop', 0)(<list>)
#Match Statement

Executes the first block with matching pattern.

match <object/expression>:
    case <pattern> [if <condition>]:
        <code>
    ...
Patterns
<value_pattern> = 1/'abc'/True/None/math.pi        
<class_pattern> = <type>()                         
<wildcard_patt> = _                                
<capture_patt>  = <name>                           
<as_pattern>    = <pattern> as <name>              
<or_pattern>    = <pattern> | <pattern> [| ...]    
<sequence_patt> = [<pattern>, ...]                 
<mapping_patt>  = {<value_pattern>: <patt>, ...}   
<class_pattern> = <type>(<attr_name>=<patt>, ...)  
Example
>>> from pathlib import Path
>>> match Path('/home/gto/python-cheatsheet/README.md'):
...     case Path(
...         parts=['/', 'home', user, *_]
...     ) as p if p.name.lower().startswith('readme') and p.is_file():
...         print(f'{p.name} is a readme file that belongs to user {user}.')
README.md is a readme file that belongs to user gto.
#Logging
import logging as log
log.basicConfig(filename=<path>, level='DEBUG')   
log.debug/info/warning/error/critical(<str>)      
<Logger> = log.getLogger(__name__)                
<Logger>.<level>(<str>)                           
<Logger>.exception(<str>)                         
Setup
log.basicConfig(
    filename=None,                                
    format='%(levelname)s:%(name)s:%(message)s',  
    level=log.WARNING,                            
    handlers=[log.StreamHandler(sys.stderr)]      
)
<Formatter> = log.Formatter('<format>')           
<Handler> = log.FileHandler(<path>, mode='a')     
<Handler>.setFormatter(<Formatter>)               
<Handler>.setLevel(<int/str>)                     
<Logger>.addHandler(<Handler>)                    
<Logger>.setLevel(<int/str>)                      
<Logger>.propagate = <bool>                       
Creates a logger that writes all messages to a file and sends them to the root's handler that prints warnings or higher:
>>> logger = log.getLogger('my_module')
>>> handler = log.FileHandler('test.log', encoding='utf-8')
>>> handler.setFormatter(log.Formatter('%(asctime)s %(levelname)s:%(name)s:%(message)s'))
>>> logger.addHandler(handler)
>>> logger.setLevel('DEBUG')
>>> log.basicConfig()
>>> log.root.handlers[0].setLevel('WARNING')
>>> logger.critical('Running out of disk space.')
CRITICAL:my_module:Running out of disk space.
>>> print(open('test.log').read())
2023-02-07 23:21:01,430 CRITICAL:my_module:Running out of disk space.
#Introspection
<list> = dir()                      
<dict> = vars()                     
<dict> = globals()                  
<list> = dir(<obj>)                 
<dict> = vars(<obj>)                
<bool> = hasattr(<obj>, '<name>')   
value  = getattr(<obj>, '<name>')   
setattr(<obj>, '<name>', value)     
delattr(<obj>, '<name>')            
<Sig>  = inspect.signature(<func>)  
<dict> = <Sig>.parameters           
<memb> = <Param>.kind               
<type> = <Param>.annotation         
#Threading

CPython interpreter can only run a single thread at a time. Using multiple threads won't result in a faster execution, unless at least one of the threads contains an I/O operation.

from threading import Thread, Lock, RLock, Semaphore, Event, Barrier
from concurrent.futures import ThreadPoolExecutor, as_completed
Thread
<Thread> = Thread(target=<function>)           
<Thread>.start()                               
<Thread>.join()                                
Lock
<lock> = Lock/RLock()                          
<lock>.acquire()                               
<lock>.release()                               
Semaphore, Event, Barrier
<Semaphore> = Semaphore(value=1)               
<Event>     = Event()                          
<Barrier>   = Barrier(n_times)                 
Queue
<Queue> = queue.Queue(maxsize=0)               
<Queue>.put(<el>)                              
<Queue>.put_nowait(<el>)                       
<el> = <Queue>.get()                           
<el> = <Queue>.get_nowait()                    
Thread Pool Executor
<Exec> = ThreadPoolExecutor(max_workers=None)  
<iter> = <Exec>.map(<func>, <args_1>, ...)     
<Futr> = <Exec>.submit(<func>, <arg_1>, ...)   
<Exec>.shutdown()                              
<bool> = <Future>.done()                       
<obj>  = <Future>.result(timeout=None)         
<bool> = <Future>.cancel()                     
<iter> = as_completed(<coll_of_Futures>)       
#Coroutines
import asyncio as aio
<coro> = <async_function>(<args>)          
<obj>  = await <coroutine>                 
<task> = aio.create_task(<coroutine>)      
<obj>  = await <task>                      
<coro> = aio.gather(<coro/task>, ...)      
<coro> = aio.wait(<tasks>, return_when=…)  
<iter> = aio.as_completed(<coros/tasks>)   
Runs a terminal game where you control an asterisk that must avoid numbers:
import asyncio, collections, curses, curses.textpad, enum, random

P = collections.namedtuple('P', 'x y')     
D = enum.Enum('D', 'n e s w')              
W, H = 15, 7                               

def main(screen):
    curses.curs_set(0)                     
    screen.nodelay(True)                   
    asyncio.run(main_coroutine(screen))    

async def main_coroutine(screen):
    moves = asyncio.Queue()
    state = {'*': P(0, 0)} | {id_: P(W//2, H//2) for id_ in range(10)}
    ai    = [random_controller(id_, moves) for id_ in range(10)]
    mvc   = [human_controller(screen, moves), model(moves, state), view(state, screen)]
    tasks = [asyncio.create_task(coro) for coro in ai + mvc]
    await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)

async def random_controller(id_, moves):
    while True:
        d = random.choice(list(D))
        moves.put_nowait((id_, d))
        await asyncio.sleep(random.triangular(0.01, 0.65))

async def human_controller(screen, moves):
    while True:
        key_mappings = {258: D.s, 259: D.n, 260: D.w, 261: D.e}
        if d := key_mappings.get(screen.getch()):
            moves.put_nowait(('*', d))
        await asyncio.sleep(0.005)

async def model(moves, state):
    while state['*'] not in (state[id_] for id_ in range(10)):
        id_, d = await moves.get()
        deltas = {D.n: P(0, -1), D.e: P(1, 0), D.s: P(0, 1), D.w: P(-1, 0)}
        state[id_] = P((state[id_].x + deltas[d].x) % W, (state[id_].y + deltas[d].y) % H)

async def view(state, screen):
    offset = P(curses.COLS//2 - W//2, curses.LINES//2 - H//2)
    while True:
        screen.erase()
        curses.textpad.rectangle(screen, offset.y-1, offset.x-1, offset.y+H, offset.x+W)
        for id_, p in state.items():
            screen.addstr(offset.y + (p.y - state['*'].y + H//2) % H,
                          offset.x + (p.x - state['*'].x + W//2) % W, str(id_))
        screen.refresh()
        await asyncio.sleep(0.005)

if __name__ == '__main__':
    curses.wrapper(main)
Libraries #Progress Bar

>>> import tqdm, time
>>> for el in tqdm.tqdm([1, 2, 3], desc='Processing'):
...     time.sleep(1)
Processing: 100%|████████████████████| 3/3 [00:03<00:00,  1.00s/it]
#Plot

import matplotlib.pyplot as plt

plt.plot/bar/scatter(x_data, y_data [, label=<str>])  
plt.legend()                                          
plt.title/xlabel/ylabel(<str>)                        
plt.show()                                            
plt.clf()                                             
#Table Prints a CSV spreadsheet to the console:

import csv, tabulate
with open('test.csv', encoding='utf-8', newline='') as file:
    rows = list(csv.reader(file))
print(tabulate.tabulate(rows, headers='firstrow'))
#Console App Runs a basic file explorer in the console:

import curses, os
from curses import A_REVERSE, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT

def main(screen):
    ch, first, selected, paths = 0, 0, 0, os.listdir()
    while ch != ord('q'):
        height, width = screen.getmaxyx()
        screen.erase()
        for y, filename in enumerate(paths[first : first+height]):
            color = A_REVERSE if filename == paths[selected] else 0
            screen.addnstr(y, 0, filename, width-1, color)
        ch = screen.getch()
        selected -= (ch == KEY_UP) and (selected > 0)
        selected += (ch == KEY_DOWN) and (selected < len(paths)-1)
        first -= (first > selected)
        first += (first < selected-(height-1))
        if ch in [KEY_LEFT, KEY_RIGHT, ord('\n')]:
            new_dir = '..' if ch == KEY_LEFT else paths[selected]
            if os.path.isdir(new_dir):
                os.chdir(new_dir)
                first, selected, paths = 0, 0, os.listdir()

if __name__ == '__main__':
    curses.wrapper(main)
#GUI App A weight converter GUI application:

import PySimpleGUI as sg

text_box = sg.Input(default_text='100', enable_events=True, key='QUANTITY')
dropdown = sg.InputCombo(['g', 'kg', 't'], 'kg', readonly=True, enable_events=True, k='UNIT')
label    = sg.Text('100 kg is 220.462 lbs.', key='OUTPUT')
button   = sg.Button('Close')
window   = sg.Window('Weight Converter', [[text_box, dropdown], [label], [button]])

while True:
    event, values = window.read()
    if event in [sg.WIN_CLOSED, 'Close']:
        break
    try:
        quantity = float(values['QUANTITY'])
    except ValueError:
        continue
    unit = values['UNIT']
    factors = {'g': 0.001, 'kg': 1, 't': 1000}
    lbs = quantity * factors[unit] / 0.45359237
    window['OUTPUT'].update(value=f'{quantity} {unit} is {lbs:g} lbs.')
window.close()
#Scraping Scrapes Python's URL and logo from its Wikipedia page:

import requests, bs4, os

response   = requests.get('https://en.wikipedia.org/wiki/Python_(programming_language)')
document   = bs4.BeautifulSoup(response.text, 'html.parser')
table      = document.find('table', class_='infobox vevent')
python_url = table.find('th', text='Website').next_sibling.a['href']
logo_url   = table.find('img')['src']
filename   = os.path.basename(logo_url)
with open(filename, 'wb') as file:
    file.write(requests.get(f'https:{logo_url}').content)
print(f'{python_url}, file://{os.path.abspath(filename)}')
Selenium

Library for scraping websites with dynamic content.


from selenium import webdriver

<WebDrv> = webdriver.Chrome/Firefox/Safari/Edge()     
<WebDrv>.get('<url>')                                 
<str>  = <WebDrv>.page_source                         
<El>   = <WebDrv/El>.find_element('css selector', …)  
<list> = <WebDrv/El>.find_elements('xpath', …)        
<str>  = <El>.get_attribute(<str>)                    
<El>.click/clear()                                    
XPath — also available in lxml, Scrapy, and browser's console via '$x("<xpath>")':
<xpath>     = //<element>[/ or // <element>]          
<xpath>     = //<element>/following::<element>        
<element>   = <tag><conditions><index>                
<condition> = [<sub_cond> [and/or <sub_cond>]]        
<sub_cond>  = @<attr>[="<val>"]                       
<sub_cond>  = contains(@<attr>, "<val>")              
<sub_cond>  = [//]<element>                           
#Web App

Flask is a micro web framework/server. If you just want to open a html file in a web browser use 'webbrowser.open(<path>)' instead.


import flask as fl
app = fl.Flask(__name__)                   
app.run(host=None, port=None, debug=None)  
Serving Files
@app.route('/img/<path:filename>')
def serve_file(filename):
    return fl.send_from_directory('DIRNAME', filename)
Serving HTML
@app.route('/<sport>')
def serve_html(sport):
    return fl.render_template_string('<h1>{{title}}</h1>', title=sport)
Serving JSON
@app.post('/<sport>/odds')
def serve_json(sport):
    team = fl.request.form['team']
    return {'team': team, 'odds': [2.09, 3.74, 3.68]}
Starts the app in its own thread and queries its REST API:

>>> import threading, requests
>>> threading.Thread(target=app.run, daemon=True).start()
>>> url = 'http://localhost:5000/football/odds'
>>> response = requests.post(url, data={'team': 'arsenal f.c.'})
>>> response.json()
{'team': 'arsenal f.c.', 'odds': [2.09, 3.74, 3.68]}
#Profiling
from time import perf_counter
start_time = perf_counter()
...
duration_in_seconds = perf_counter() - start_time
Timing a Snippet
>>> from timeit import timeit
>>> timeit('list(range(10000))', number=1000, globals=globals(), setup='pass')
0.19373
Profiling by Line
$ pip3 install line_profiler
$ echo '@profile
def main():
    a = list(range(10000))
    b = set(range(10000))
main()' > test.py
$ kernprof -lv test.py
Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     1                                           @profile
     2                                           def main():
     3         1        253.4    253.4     32.2      a = list(range(10000))
     4         1        534.1    534.1     67.8      b = set(range(10000))
Call and Flame Graphs
$ apt/brew install graphviz && pip3 install gprof2dot snakeviz  
$ tail --lines=+2 test.py > test.py                             
$ python3 -m cProfile -o test.prof test.py                      
$ gprof2dot --format=pstats test.prof | dot -T png -o test.png  
$ xdg-open/open test.png                                        
$ snakeviz test.prof                                            
Sampling and Memory Profilers
┏━━━━━━━━━━━━━━┯━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━┯━━━━━━┓
┃ pip3 install │   Target   │          How to run           │ Lines │ Live ┃
┠──────────────┼────────────┼───────────────────────────────┼───────┼──────┨
┃ pyinstrument │    CPU     │ pyinstrument test.py          │   ×   │  ×   ┃
┃ py-spy       │    CPU     │ py-spy top -- python3 test.py │   ×   │  ✓   ┃
┃ scalene      │ CPU+Memory │ scalene test.py               │   ✓   │  ×   ┃
┃ memray       │   Memory   │ memray run --live test.py     │   ✓   │  ✓   ┃
┗━━━━━━━━━━━━━━┷━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━┷━━━━━━┛
#NumPy

Array manipulation mini-language. It can run up to one hundred times faster than the equivalent Python code. An even faster alternative that runs on a GPU is called CuPy.


import numpy as np
<array> = np.array(<list/list_of_lists/…>)              
<array> = np.zeros/ones/empty(<shape>)                  
<array> = np.arange(from_inc, to_exc, ±step)            
<array> = np.random.randint(from_inc, to_exc, <shape>)  
<view>  = <array>.reshape(<shape>)                      
<array> = <array>.flatten()                             
<view>  = <array>.transpose()                           
<array> = np.copy/abs/sqrt/log/int64(<array>)           
<array> = <array>.sum/max/mean/argmax/all(axis)         
<array> = np.apply_along_axis(<func>, axis, <array>)    
<array> = np.concatenate(<list_of_arrays>, axis=0)      
<array> = np.vstack/column_stack(<list_of_arrays>)      
<array> = np.tile/repeat(<array>, <int/list> [, axis])  
Indexing
<el>       = <2d>[row_index, col_index]                 
<1d_view>  = <2d>[row_index]                            
<1d_view>  = <2d>[:, col_index]                         
<2d_view>  = <2d>[from:to_row_i, from:to_col_i]         
<1d_array> = <2d>[row_indices, col_indices]             
<2d_array> = <2d>[row_indices]                          
<2d_array> = <2d>[:, col_indices]                       
<2d_array> = <2d>[np.ix_(row_indices, col_indices)]     
<2d_bools> = <2d> > <el/1d/2d>                          
<1/2d_arr> = <2d>[<2d/1d_bools>]                        
Broadcasting

A set of rules by which NumPy functions operate on arrays of different shapes.

left  = np.array([0.1,  0.6,  0.8])                     
right = np.array([[0.1], [0.6], [0.8]])                 
1. If array shapes differ in length, left-pad the shorter shape with ones:
left  = np.array([[0.1,  0.6,  0.8]])                   
right = np.array([[0.1], [0.6], [0.8]])                 
2. If any dimensions differ in size, expand the ones that have size 1 by duplicating their elements:
left  = np.array([[0.1,  0.6,  0.8],                    
                  [0.1,  0.6,  0.8],
                  [0.1,  0.6,  0.8]])

right = np.array([[0.1,  0.1,  0.1],                    
                  [0.6,  0.6,  0.6],
                  [0.8,  0.8,  0.8]])
Example For each point returns index of its nearest point ([0.1, 0.6, 0.8] => [1, 2, 1]):
>>> print(points := np.array([0.1, 0.6, 0.8]))
[0.1  0.6  0.8]
>>> print(wrapped_points := points.reshape(3, 1))
[[0.1]
 [0.6]
 [0.8]]
>>> print(deltas := points - wrapped_points)
[[ 0.   0.5  0.7]
 [-0.5  0.   0.2]
 [-0.7 -0.2  0. ]]
>>> deltas[range(3), range(3)] = np.inf
>>> print(distances := np.abs(deltas))
[[inf  0.5  0.7]
 [0.5  inf  0.2]
 [0.7  0.2  inf]]
>>> print(distances.argmin(axis=1))
[1 2 1]
#Image

from PIL import Image
<Image> = Image.new('<mode>', (width, height))  
<Image> = Image.open(<path>)                    
<Image> = <Image>.convert('<mode>')             
<Image>.save(<path>)                            
<Image>.show()                                  
<int/tup> = <Image>.getpixel((x, y))            
<ImgCore> = <Image>.getdata()                   
<Image>.putpixel((x, y), <int/tuple>)           
<Image>.putdata(<list/ImgCore>)                 
<Image>.paste(<Image>, (x, y))                  
<Image> = <Image>.filter(<Filter>)              
<Image> = <Enhance>.enhance(<float>)            
<array> = np.array(<Image>)                     
<Image> = Image.fromarray(np.uint8(<array>))    
Modes Examples Creates a PNG image of a rainbow gradient:
WIDTH, HEIGHT = 100, 100
n_pixels = WIDTH * HEIGHT
hues = (255 * i/n_pixels for i in range(n_pixels))
img = Image.new('HSV', (WIDTH, HEIGHT))
img.putdata([(int(h), 255, 255) for h in hues])
img.convert('RGB').save('test.png')
Adds noise to the PNG image and displays it:
from random import randint
add_noise = lambda value: max(0, min(255, value + randint(-20, 20)))
img = Image.open('test.png').convert('HSV')
img.putdata([(add_noise(h), s, v) for h, s, v in img.getdata()])
img.show()
Image Draw
from PIL import ImageDraw
<Draw> = ImageDraw.Draw(<Image>)                
<Draw>.point((x, y))                            
<Draw>.line((x1, y1, x2, y2 [, ...]))           
<Draw>.arc((x1, y1, x2, y2), deg1, deg2)        
<Draw>.rectangle((x1, y1, x2, y2))              
<Draw>.polygon((x1, y1, x2, y2, ...))           
<Draw>.ellipse((x1, y1, x2, y2))                
<Draw>.text((x, y), <str>, font=<Font>)         
#Animation Creates a GIF of a bouncing ball:

from PIL import Image, ImageDraw
import imageio

WIDTH, HEIGHT, R = 126, 126, 10
frames = []
for velocity in range(1, 16):
    y = sum(range(velocity))
    frame = Image.new('L', (WIDTH, HEIGHT))
    draw = ImageDraw.Draw(frame)
    draw.ellipse((WIDTH/2-R, y, WIDTH/2+R, y+R*2), fill='white')
    frames.append(frame)
frames += reversed(frames[1:-1])
imageio.mimsave('test.gif', frames, duration=0.03)
<Wave>  = wave.open('<path>')         
<int>   = <Wave>.getframerate()       
<int>   = <Wave>.getnchannels()       
<int>   = <Wave>.getsampwidth()       
<tuple> = <Wave>.getparams()          
<bytes> = <Wave>.readframes(nframes)  
<Wave> = wave.open('<path>', 'wb')    
<Wave>.setframerate(<int>)            
<Wave>.setnchannels(<int>)            
<Wave>.setsampwidth(<int>)            
<Wave>.setparams(<tuple>)             
<Wave>.writeframes(<bytes>)           
Sample Values
┏━━━━━━━━━━━┯━━━━━━━━━━━┯━━━━━━┯━━━━━━━━━━━┓
┃ sampwidth │    min    │ zero │    max    ┃
┠───────────┼───────────┼──────┼───────────┨
┃     10128255 ┃
┃     2-32768032767 ┃
┃     3-838860808388607 ┃
┗━━━━━━━━━━━┷━━━━━━━━━━━┷━━━━━━┷━━━━━━━━━━━┛
Read Float Samples from WAV File
def read_wav_file(filename):
    def get_int(bytes_obj):
        an_int = int.from_bytes(bytes_obj, 'little', signed=(p.sampwidth != 1))
        return an_int - 128 * (p.sampwidth == 1)
    with wave.open(filename) as file:
        p = file.getparams()
        frames = file.readframes(-1)
    bytes_samples = (frames[i : i + p.sampwidth] for i in range(0, len(frames), p.sampwidth))
    return [get_int(b) / pow(2, (p.sampwidth * 8) - 1) for b in bytes_samples], p
Write Float Samples to WAV File
def write_to_wav_file(filename, samples_f, p=None, nchannels=1, sampwidth=2, framerate=44100):
    def get_bytes(a_float):
        a_float = max(-1, min(1 - 2e-16, a_float))
        a_float += (p.sampwidth == 1)
        a_float *= pow(2, (p.sampwidth * 8) - 1)
        return int(a_float).to_bytes(p.sampwidth, 'little', signed=(p.sampwidth != 1))
    if p is None:
        p = wave._wave_params(nchannels, sampwidth, framerate, 0, 'NONE', 'not compressed')
    with wave.open(filename, 'wb') as file:
        file.setparams(p)
        file.writeframes(b''.join(get_bytes(f) for f in samples_f))
Examples Saves a 440 Hz sine wave to a mono WAV file:
from math import pi, sin
samples_f = (sin(i * 2 * pi * 440 / 44100) for i in range(100_000))
write_to_wav_file('test.wav', samples_f)
Adds noise to the WAV file:
from random import uniform
samples_f, params = read_wav_file('test.wav')
samples_f = (f + uniform(-0.05, 0.05) for f in samples_f)
write_to_wav_file('test.wav', samples_f, p=params)
Plays the WAV file:

from simpleaudio import play_buffer
with wave.open('test.wav') as file:
    frames, p = file.readframes(-1), file.getparams()
    play_buffer(frames, p.nchannels, p.sampwidth, p.framerate).wait_done()
Text to Speech

import pyttsx3
engine = pyttsx3.init()
engine.say('Sally sells seashells by the seashore.')
engine.runAndWait()
#Synthesizer Plays Popcorn by Gershon Kingsley:

import itertools as it, math, array, simpleaudio

def play_notes(notes, bpm=132, f=44100):
    get_pause   = lambda n_beats: it.repeat(0, int(n_beats * 60/bpm * f))
    sin_f       = lambda i, hz: math.sin(i * 2 * math.pi * hz / f)
    get_wave    = lambda hz, n_beats: (sin_f(i, hz) for i in range(int(n_beats * 60/bpm * f)))
    get_hz      = lambda note: 440 * 2 ** ((int(note[:2]) - 69) / 12)
    get_nbeats  = lambda note: 1/2 if '♩' in note else 1/4 if '♪' in note else 1
    get_samples = lambda n: get_wave(get_hz(n), get_nbeats(n)) if n else get_pause(1/4)
    samples_f   = it.chain.from_iterable(get_samples(n) for n in notes.split(','))
    samples_i   = array.array('h', (int(fl * 5000) for fl in samples_f))
    simpleaudio.play_buffer(samples_i, 1, 2, f).wait_done()

play_notes('83♩,81♪,,83♪,,78♪,,74♪,,78♪,,71♪,,,,83♪,,81♪,,83♪,,78♪,,74♪,,78♪,,71♪,,,,'
           '83♩,85♪,,86♪,,85♪,,86♪,,83♪,,85♩,83♪,,85♪,,81♪,,83♪,,81♪,,83♪,,79♪,,83♪,,,,')
#Pygame Opes a window and draws a square that can be moved with arrow keys:

import pygame as pg

pg.init()
screen = pg.display.set_mode((500, 500))
rect = pg.Rect(240, 240, 20, 20)
while not pg.event.get(pg.QUIT):
    for event in pg.event.get(pg.KEYDOWN):
        dx = (event.key == pg.K_RIGHT) - (event.key == pg.K_LEFT)
        dy = (event.key == pg.K_DOWN) - (event.key == pg.K_UP)
        rect = rect.move((dx * 20, dy * 20))
    screen.fill(pg.Color('black'))
    pg.draw.rect(screen, pg.Color('white'), rect)
    pg.display.flip()
pg.quit()
Rect

Object for storing rectangular coordinates.

<Rect> = pg.Rect(x, y, width, height)           
<int>  = <Rect>.x/y/centerx/centery/…           
<tup.> = <Rect>.topleft/center/…                
<Rect> = <Rect>.move((delta_x, delta_y))        
<bool> = <Rect>.collidepoint((x, y))            
<bool> = <Rect>.colliderect(<Rect>)             
<int>  = <Rect>.collidelist(<list_of_Rect>)     
<list> = <Rect>.collidelistall(<list_of_Rect>)  
Surface

Object for representing images.

<Surf> = pg.display.set_mode((width, height))   
<Surf> = pg.Surface((width, height))            
<Surf> = pg.image.load(<path/file>)             
<Surf> = pg.surfarray.make_surface(<np_array>)  
<Surf> = <Surf>.subsurface(<Rect>)              
<Surf>.fill(color)                              
<Surf>.set_at((x, y), color)                    
<Surf>.blit(<Surf>, (x, y))                     
from pygame.transform import scale, rotate      
<Surf> = scale(<Surf>, (width, height))         
<Surf> = rotate(<Surf>, angle)                  
<Surf> = flip(<Surf>, flip_x=False)             
from pygame.draw import line, arc, rect         
line(<Surf>, color, (x1, y1), (x2, y2))         
arc(<Surf>, color, <Rect>, from_rad, to_rad)    
rect(<Surf>, color, <Rect>, width=0)            
<Font> = pg.font.Font(<path/file>, size)        
<Surf> = <Font>.render(text, antialias, color)  
Sound
<Sound> = pg.mixer.Sound(<path/file/bytes>)     
<Sound>.play/stop()                             
Basic Mario Brothers Example
import collections, dataclasses, enum, io, itertools as it, pygame as pg, urllib.request
from random import randint

P = collections.namedtuple('P', 'x y')          
D = enum.Enum('D', 'n e s w')                   
W, H, MAX_S = 50, 50, P(5, 10)                  

def main():
    def get_screen():
        pg.init()
        return pg.display.set_mode((W*16, H*16))
    def get_images():
        url = 'https://gto76.github.io/python-cheatsheet/web/mario_bros.png'
        img = pg.image.load(io.BytesIO(urllib.request.urlopen(url).read()))
        return [img.subsurface(get_rect(x, 0)) for x in range(img.get_width() // 16)]
    def get_mario():
        Mario = dataclasses.make_dataclass('Mario', 'rect spd facing_left frame_cycle'.split())
        return Mario(get_rect(1, 1), P(0, 0), False, it.cycle(range(3)))
    def get_tiles():
        border = [(x, y) for x in range(W) for y in range(H) if x in [0, W-1] or y in [0, H-1]]
        platforms = [(randint(1, W-2), randint(2, H-2)) for _ in range(W*H // 10)]
        return [get_rect(x, y) for x, y in border + platforms]
    def get_rect(x, y):
        return pg.Rect(x*16, y*16, 16, 16)
    run(get_screen(), get_images(), get_mario(), get_tiles())

def run(screen, images, mario, tiles):
    clock = pg.time.Clock()
    pressed = set()
    while not pg.event.get(pg.QUIT):
        clock.tick(28)
        pressed |= {e.key for e in pg.event.get(pg.KEYDOWN)}
        pressed -= {e.key for e in pg.event.get(pg.KEYUP)}
        update_speed(mario, tiles, pressed)
        update_position(mario, tiles)
        draw(screen, images, mario, tiles)

def update_speed(mario, tiles, pressed):
    x, y = mario.spd
    x += 2 * ((pg.K_RIGHT in pressed) - (pg.K_LEFT in pressed))
    x += (x < 0) - (x > 0)
    y += 1 if D.s not in get_boundaries(mario.rect, tiles) else (pg.K_UP in pressed) * -10
    mario.spd = P(x=max(-MAX_S.x, min(MAX_S.x, x)), y=max(-MAX_S.y, min(MAX_S.y, y)))

def update_position(mario, tiles):
    x, y = mario.rect.topleft
    n_steps = max(abs(s) for s in mario.spd)
    for _ in range(n_steps):
        mario.spd = stop_on_collision(mario.spd, get_boundaries(mario.rect, tiles))
        x, y = x + (mario.spd.x / n_steps), y + (mario.spd.y / n_steps)
        mario.rect.topleft = x, y

def get_boundaries(rect, tiles):
    deltas = {D.n: P(0, -1), D.e: P(1, 0), D.s: P(0, 1), D.w: P(-1, 0)}
    return {d for d, delta in deltas.items() if rect.move(delta).collidelist(tiles) != -1}

def stop_on_collision(spd, bounds):
    return P(x=0 if (D.w in bounds and spd.x < 0) or (D.e in bounds and spd.x > 0) else spd.x,
             y=0 if (D.n in bounds and spd.y < 0) or (D.s in bounds and spd.y > 0) else spd.y)

def draw(screen, images, mario, tiles):
    screen.fill((85, 168, 255))
    mario.facing_left = mario.spd.x < 0 if mario.spd.x else mario.facing_left
    is_airborne = D.s not in get_boundaries(mario.rect, tiles)
    image_index = 4 if is_airborne else next(mario.frame_cycle) if mario.spd.x else 6
    screen.blit(images[image_index + (mario.facing_left * 9)], mario.rect)
    for t in tiles:
        is_border = t.x in [0, (W-1)*16] or t.y in [0, (H-1)*16]
        screen.blit(images[18 if is_border else 19], t)
    pg.display.flip()

if __name__ == '__main__':
    main()
#Pandas

Data analysis library. For examples see Plotly.


import pandas as pd, matplotlib.pyplot as plt
Series

Ordered dictionary with a name.

>>> s = pd.Series([1, 2], index=['x', 'y'], name='a'); s
x    1
y    2
Name: a, dtype: int64
<S>  = pd.Series(<list>)                       
<S>  = pd.Series(<dict>)                       
<el> = <S>.loc[key]                            
<S>  = <S>.loc[coll_of_keys]                   
<S>  = <S>.loc[from_key : to_key_inc]          
<el> = <S>[key/i]                              
<S>  = <S>[coll_of_keys/coll_of_i]             
<S>  = <S>[<S_of_bools>]                       
<S>  = <S> > <el/S>                            
<S>  = <S> + <el/S>                            
<S>  = <S>.head/describe/sort_values()         
<S>  = <S>.str.strip/lower/contains/replace()  
<S>  = <S>.dt.year/month/day/hour              
<S>  = <S>.dt.to_period('y/m/d/h')             
<S>.plot.line/area/bar/pie/hist()              
plt.show()                                     
Series — Aggregate, Transform, Map:
<el> = <S>.sum/max/mean/std/idxmax/count()     
<S>  = <S>.rank/diff/cumsum/ffill/interpol…()  
<S>  = <S>.isna/fillna/isin([<el/coll>])       
┏━━━━━━━━━━━━━━┯━━━━━━━━━━━━━┯━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━┓
┃              │    'sum'    │   ['sum']   │ {'s': 'sum'}  ┃
┠──────────────┼─────────────┼─────────────┼───────────────┨
┃ s.apply(…)   │      3      │    sum  3   │     s  3      ┃
┃ s.agg(…)     │             │             │               ┃
┗━━━━━━━━━━━━━━┷━━━━━━━━━━━━━┷━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━┛

┏━━━━━━━━━━━━━━┯━━━━━━━━━━━━━┯━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━┓
┃              │    'rank'   │   ['rank']  │ {'r': 'rank'} ┃
┠──────────────┼─────────────┼─────────────┼───────────────┨
┃ s.apply(…)   │             │      rank   │               ┃
┃ s.agg(…)     │    x  1.0   │   x   1.0   │   r  x  1.0   ┃
┃              │    y  2.0   │   y   2.0   │      y  2.0   ┃
┗━━━━━━━━━━━━━━┷━━━━━━━━━━━━━┷━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━┛
DataFrame

Table with labeled rows and columns.

>>> df = pd.DataFrame([[1, 2], [3, 4]], index=['a', 'b'], columns=['x', 'y']); df
   x  y
a  1  2
b  3  4
<DF>   = pd.DataFrame(<list_of_rows>)          
<DF>   = pd.DataFrame(<dict_of_columns>)       
<el>   = <DF>.loc[row_key, col_key]            
<S/DF> = <DF>.loc[row_key/s]                   
<S/DF> = <DF>.loc[:, col_key/s]                
<DF>   = <DF>.loc[row_bools, col_bools]        
<S/DF> = <DF>[col_key/s]                       
<DF>   = <DF>[<S_of_bools>]                    
<DF>   = <DF>[<DF_of_bools>]                   
<DF>   = <DF> > <el/S/DF>                      
<DF>   = <DF> + <el/S/DF>                      
<DF>   = <DF>.set_index(col_key)               
<DF>   = <DF>.reset_index(drop=False)          
<DF>   = <DF>.sort_index(ascending=True)       
<DF>   = <DF>.sort_values(col_key/s)           
<DF>   = <DF>.head/tail/sample(<int>)          
<DF>   = <DF>.describe()                       
<DF>   = <DF>.query('<query>')                 
<DF>.plot.line/area/bar/scatter(x=col_key, …)  
plt.show()                                     
DataFrame — Merge, Join, Concat:
>>> df_2 = pd.DataFrame([[4, 5], [6, 7]], index=['b', 'c'], columns=['y', 'z']); df_2
   y  z
b  4  5
c  6  7
┏━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━┯━━━━━━━━━━━━┯━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                       │    'outer''inner''left'   │       Description         ┃
┠───────────────────────┼───────────────┼────────────┼────────────┼───────────────────────────┨
┃ df.merge(df_2,        │    x   y   z  │ x   y   z  │ x   y   z  │ Merges on column if 'on'  ┃
┃          on='y',      │ 0  1   2   .  │ 3   4   51   2   .  │ or 'left_on/right_on' are ┃
┃          how=…)       │ 1  3   4   5  │            │ 3   4   5  │ set, else on shared cols. ┃
┃                       │ 2  .   6   7  │            │            │ Uses 'inner' by default.  ┃
┠───────────────────────┼───────────────┼────────────┼────────────┼───────────────────────────┨
┃ df.join(df_2,         │    x yl yr  z │            │ x yl yr  z │ Merges on row keys.       ┃
┃         lsuffix='l',  │ a  1  2  .  . │ x yl yr  z │ 1  2  .  . │ Uses 'left' by default.   ┃
┃         rsuffix='r',  │ b  3  4  4  53  4  4  53  4  4  5 │ If Series is passed, it   ┃
┃         how=…)        │ c  .  .  6  7 │            │            │ is treated as a column.   ┃
┠───────────────────────┼───────────────┼────────────┼────────────┼───────────────────────────┨
┃ pd.concat([df, df_2], │    x   y   z  │     y      │            │ Adds rows at the bottom.  ┃
┃           axis=0,     │ a  1   2   .  │     2      │            │ Uses 'outer' by default.  ┃
┃           join=…)     │ b  3   4   .  │     4      │            │ A Series is treated as a  ┃
┃                       │ b  .   4   54      │            │ column. To add a row use  ┃
┃                       │ c  .   6   76      │            │ pd.concat([df, DF([s])]). ┃
┠───────────────────────┼───────────────┼────────────┼────────────┼───────────────────────────┨
┃ pd.concat([df, df_2], │    x  y  y  z │            │            │ Adds columns at the       ┃
┃           axis=1,     │ a  1  2  .  . │ x  y  y  z │            │ right end. Uses 'outer'   ┃
┃           join=…)     │ b  3  4  4  53  4  4  5 │            │ by default. A Series is   ┃
┃                       │ c  .  .  6  7 │            │            │ treated as a column.      ┃
┗━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━┷━━━━━━━━━━━━┷━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
DataFrame — Aggregate, Transform, Map:
<S>  = <DF>.sum/max/mean/std/idxmax/count()    
<DF> = <DF>.rank/diff/cumsum/ffill/interpo…()  
<DF> = <DF>.isna/fillna/isin([<el/coll>])      
┏━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━┓
┃                 │     'sum'     │    ['sum']    │ {'x': 'sum'}  ┃
┠─────────────────┼───────────────┼───────────────┼───────────────┨
┃ df.apply(…)     │      x  4     │        x  y   │     x  4      ┃
┃ df.agg(…)       │      y  6     │   sum  4  6   │               ┃
┗━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━┛

┏━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━┓
┃                 │     'rank'    │    ['rank']   │ {'x': 'rank'} ┃
┠─────────────────┼───────────────┼───────────────┼───────────────┨
┃ df.apply(…)     │               │       x    y  │               ┃
┃ df.agg(…)       │       x    y  │    rank rank  │         x     ┃
┃ df.transform(…) │  a  1.0  1.0  │  a  1.0  1.0  │    a  1.0     ┃
┃                 │  b  2.0  2.0  │  b  2.0  2.0  │    b  2.0     ┃
┗━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━┛
Multi-Index
<DF> = <DF>.loc[row_key_1]                     
<DF> = <DF>.loc[:, (slice(None), col_key_2)]   
<DF> = <DF>.set_index(col_keys)                
<DF> = <DF>.pivot_table(index=col_key/s)       
<S>  = <DF>.stack/unstack(level=-1)            
File Formats
<S/DF> = pd.read_json/pickle(<path/url/file>)  
<DF>   = pd.read_csv/excel(<path/url/file>)    
<list> = pd.read_html(<path/url/file>)         
<S/DF> = pd.read_parquet/feather/hdf(<path…>)  
<DF>   = pd.read_sql('<table/query>', <conn>)  
<DF>.to_json/csv/html/latex/parquet(<path>)    
<DF>.to_pickle/excel/feather/hdf(<path>)       
<DF>.to_sql('<table_name>', <connection>)      
GroupBy

Object that groups together rows of a dataframe based on the value of the passed column.

<GB> = <DF>.groupby(col_key/s)                 
<DF> = <GB>.apply/filter(<func>)               
<DF> = <GB>.get_group(<el>)                    
<S>  = <GB>.size()                             
<GB> = <GB>[col_key]                           
<DF> = <GB>.sum/max/mean/std/idxmax/count()    
<DF> = <GB>.rank/diff/cumsum/ffill()           
<DF> = <GB>.fillna(<el>)                       
Divides rows into groups and sums their columns. Result has a named index that creates column 'z' on reset_index():
>>> df = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 6]], list('abc'), list('xyz'))
>>> gb = df.groupby('z'); gb.apply(print)
   x  y  z
a  1  2  3
   x  y  z
b  4  5  6
c  7  8  6
>>> gb.sum()
    x   y
z
3   1   2
6  11  13
Rolling

Object for rolling window calculations.

<RS/RDF/RGB> = <S/DF/GB>.rolling(win_size)     
<RS/RDF/RGB> = <RDF/RGB>[col_key/s]            
<S/DF>       = <R>.mean/sum/max()              
#Plotly

import plotly.express as px, pandas as pd
<Fig> = px.line(<DF> [, y=col_key/s [, x=col_key]])   
<Fig>.update_layout(paper_bgcolor='#rrggbb')          
<Fig>.write_html/json/image('<path>')                 
<Fig> = px.area/bar/box(<DF>, x=col_key, y=col_keys)  
<Fig> = px.scatter(<DF>, x=col_key, y=col_keys)       
<Fig> = px.scatter_3d(<DF>, x=col_key, y=col_key, …)  
<Fig> = px.histogram(<DF>, x=col_keys, y=col_key)     
Displays a line chart of total COVID-19 deaths per million grouped by continent:
covid = pd.read_csv('https://raw.githubusercontent.com/owid/covid-19-data/8dde8ca49b'
                    '6e648c17dd420b2726ca0779402651/public/data/owid-covid-data.csv',
                    usecols=['iso_code', 'date', 'population', 'total_deaths'])
continents = pd.read_csv('https://gto76.github.io/python-cheatsheet/web/continents.csv',
                         usecols=['Three_Letter_Country_Code', 'Continent_Name'])
df = pd.merge(covid, continents, left_on='iso_code', right_on='Three_Letter_Country_Code')
df = df.groupby(['Continent_Name', 'date']).sum().reset_index()
df['Total Deaths per Million'] = df.total_deaths * 1e6 / df.population
df = df[df.date > '2020-03-14']
df = df.rename({'date': 'Date', 'Continent_Name': 'Continent'}, axis='columns')
px.line(df, x='Date', y='Total Deaths per Million', color='Continent')
Displays a multi-axis line chart of total COVID-19 cases and changes in prices of Bitcoin, Dow Jones and gold:

import pandas as pd, selenium.webdriver, io, plotly.graph_objects as go

def main():
    covid, (bitcoin, gold, dow) = get_covid_cases(), get_tickers()
    df = wrangle_data(covid, bitcoin, gold, dow)
    display_data(df)

def get_covid_cases():
    url = 'https://catalog.ourworldindata.org/garden/covid/latest/compact/compact.csv'
    df = pd.read_csv(url, parse_dates=['date'])
    df = df[df.country == 'World']
    s = df.set_index('date').total_cases
    return s.rename('Total Cases')

def get_tickers():
    with selenium.webdriver.Chrome() as driver:
        driver.implicitly_wait(10)
        symbols = {'Bitcoin': 'BTC-USD', 'Gold': 'GC=F', 'Dow Jones': '%5EDJI'}
        return [get_ticker(driver, name, symbol) for name, symbol in symbols.items()]

def get_ticker(driver, name, symbol):
    url = f'https://finance.yahoo.com/quote/{symbol}/history/'
    driver.get(url + '?period1=1579651200&period2=9999999999')
    if buttons := driver.find_elements('xpath', '//button[@name="reject"]'):
        buttons[0].click()
    html = io.StringIO(driver.page_source)
    dataframes = pd.read_html(html, parse_dates=['Date'])
    s = dataframes[0].set_index('Date').Open
    return s.rename(name)

def wrangle_data(covid, bitcoin, gold, dow):
    df = pd.concat([bitcoin, gold, dow], axis=1)  
    df = df.sort_index().interpolate()            
    df = df.loc['2020-02-23':'2021-12-20']        
    df = (df / df.iloc[0]) * 100                  
    df = df.join(covid)                           
    return df.sort_values(df.index[-1], axis=1)   

def display_data(df):
    figure = go.Figure()
    for col_name in reversed(df.columns):
        yaxis = 'y1' if col_name == 'Total Cases' else 'y2'
        trace = go.Scatter(x=df.index, y=df[col_name], yaxis=yaxis, name=col_name)
        figure.add_trace(trace)
    figure.update_layout(
        width=944,
        height=423,
        yaxis1=dict(title='Total Cases', rangemode='tozero'),
        yaxis2=dict(title='%', rangemode='tozero', overlaying='y', side='right'),
        colorway=['#EF553B', '#636EFA', '#00CC96', '#FFA152'],
        legend=dict(x=1.08)
    )
    figure.show()

if __name__ == '__main__':
    main()
#Appendix Cython

Library that compiles Python-like code into C.


import pyximport; pyximport.install()                
import <cython_script>                               
All 'cdef' definitions are optional, but they contribute to the speed-up:
cdef <type> <var_name> [= <obj/var>]                 
cdef <ctype> *<pointer_name> [= &<var>]              
cdef <ctype>[size] <array_name> [= <coll/array>]     
cdef <ctype> *<array_name> [= <coll/array/pointer>]  
cdef <type> <func_name>(<type> [*]<arg_name>): ...   
cdef class <class_name>:                             
    cdef public <type> [*]<attr_name>                
    def __init__(self, <type> <arg_name>):           
        self.<attr_name> = <arg_name>                
Virtual Environments

System for installing libraries directly into project's directory.

$ python3 -m venv NAME      
$ source NAME/bin/activate  
$ pip3 install LIBRARY      
$ python3 FILE              
$ deactivate                
Basic Script Template

Run the script with '$ python3 FILE' or '$ chmod u+x FILE; ./FILE'. To automatically start the debugger when uncaught exception occurs run '$ python3 -m pdb -cc FILE'.






from sys import argv, exit
from collections import defaultdict, namedtuple
from dataclasses import make_dataclass
from enum import Enum
import functools as ft, itertools as it, operator as op, re


def main():
    pass






def read_file(filename):
    with open(filename, encoding='utf-8') as file:
        return file.readlines()


if __name__ == '__main__':
    main()
#Index

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4