Python 3
Quick Reference

This is a one-(long-)page overview of the Python 3 (3.7.1) programming language in the form of commented lines of code. This is a work in progress.

See also Python 2 quick reference.

Contents

Python Script Execution

Shebang

#!/usr/bin/env python3
#!/usr/bin/env python3.7
#!/usr/bin/env python3.7.1
With one of the above shebangs as the first line of the script, most Unix/Linux systems will automatically pass the script to the latest installed version 3.x.x, 3.7.x, or 3.7.1 Python interpreter when the script is run as a command. This also works on Windows if the script is passed to (or the typical script extension .py is associated with) the Python launcher py.exe.

Syntax

Statement Boundaries

a = 3                   # Statements are usually separated by newlines
print(a)                # ...
b = 'hi'; print(b)      # (Non-compound) statements may be separated by semicolon
c = 4;                  # and optionally terminated by semicolon
                        # but using semicolons is discouraged (PEP 8)
d = a + b + \
    c                   # Any statement can be split across multiple lines
                        # using backslash + newline (nothing allowed between the two)
s = 'hel\
  lo'                   # s = 'hel  lo' (any indention is included in string)
s = 'hel' \
    'lo'                # s = 'hello' (adjacent string literals are concatenated)
d = a + (b +            # No backslash needed inside parentheses/brackets/...
    c)
print('hel'             # Prints 'hello' (adjacent string literals are concatenated;
    'lo')               # no backslash needed inside parentheses)

Comments and Docstrings

# Comments start with the '#' and end at the end of the same line,
# so a comment spanning multiple lines must have '#' at the start
# of each line.
a = 3                   # Here's a comment following some code
b = a + \               # ILLEGAL comment after backslash
    2 +                 # and backslash WON'T WORK after comment either -> \
    3                   # Comment must be on last line when using backslashes

"""Another way to make a multiline comment
is to put it inside a multiline string which
is not assigned to anything."""

def f():
    # Here's a docstring for this function (similar for classes, modules):
    """When a string is the first statement of a function (or class
    or module), it becomes that object's docstring, accessible via
    the __doc__ attribute. All lines traditionally have the same
    indentation, and those spaces become part of the string.
    """
    return 3.14

print(f.__doc__)        # Prints f's docstring (or None if none): 'When a string ...'
help(f)                 # Prints information about f - including f's docstring

Compound Statement Format

if len(mylist) > 0:     # A compound statement contains a header
    sum = 0             # and a suite of statements with same indentation
    for x in mylist:    # and possibly nested compound statements
        print(x)
        sum += x
    print(sum)
else:                   # and possibly another header
    print('Empty list') # and its associated suite

def func(x):            # A compound statement cannot have an empty suite
    pass                # but 'pass' can be used to do nothing

if x < y: x = y; y = 0  # Single-line compound statement (discouraged)
                        # (cannot contain nested compound statements)

Expression Lists

# Expression list
t = 4, a + 1, 'hi'      # Right-hand side expression list becomes tuple (4, 2, 'hi')
                        # (assuming a = 1)
a, (b, c) = 3, (4, 5)   # Multiple assignments a=3, b=4, c=5 using expression lists
                        # (all right-hand expressions are evaluated before any assignments)
a, (b, c) = [3, (4, 5)] # Some alternatives equivalent to above; [] could also be ()
[a, (b, c)] = 3, (4, 5) # ...
10,                     # Trailing comma is illegal/mandatory/optional if 0/1/more items
[4, a + 1, 'hi']        # List created from expression list
f(4, a + 1, 'hi')       # Function call using expression list as argument list

Types

Basic Types (Immutable)

# Int
i = -2                  # Assigns an int (infinite range and precision)
type(i)                 # Returns type object <class 'int'>
isinstance(i, int)      # Returns True
int('20')               # Returns 20 (an int)
int('20', 16)           # Returns 32 (second arg is base, 16 means hex)
i += 0xA + 0o12 + 0b10  # i is now 20 (-2 + 10 + 10 + 2); this is hex + octal + binary
03                      # ILLEGAL! (non-zero decimal numbers may not start with a zero -
                        # avoids confusion with obsolete octal format)
1_000_000 + 0b_1111_1111# Returns 1000255 (underscores improve readability)

# Float
x = -3.4                # Assigns a float
type(x)                 # Returns <class 'float'>
isinstance(x, float)    # Returns True
float(3)                # Returns 3.0
float('2.5e6')          # Returns 2500000.0
0.000_000_001           # Returns 1e-9 (underscores improve readability)

# Complex
c = 1+2j                # Assigns a complex (pair of floats)
type(c)                 # Returns <class 'complex'>
isinstance(c, complex)  # Returns True
c.real                  # 1.0
c.imag                  # 2.0
c.real = 3              # ILLEGAL! Raises AttributeError exception (complex is immutable)
c.conjugate()           # Returns (1-2j)
complex(1, 2)           # Returns (1+2j)
complex('1+2j')         # Returns (1+2j)
complex(1+2j, 10j)      # Returns (-9+2j)

# Bool
b = True                # Assigns a bool (True or False)
type(b)                 # Returns <class 'bool'>
isinstance(b, bool)     # Returns True
bool(0)                 # Returns False for 0 (else True)
bool('')                # Returns False for empty sequence type (else True)
bool(None)              # Returns False
int(True)               # Returns 1
int(False)              # Returns 0
3 + True                # Returns 4
False * 5               # Returns 0

# None
x = None                # Assigns null object (nothing, unassigned argument/return value)
type(x)                 # Returns <class 'NoneType'>
isinstance(x, type(None)) # Returns True
bool(x)                 # Returns False

# Slice
sl = slice(2)           # Assigns a slice object equivalent to the :2 in a[:2] (supports
                        # same parameters as range); more under classes
type(sl)                # Returns <class 'slice'>
isinstance(sl, slice)   # Returns True
print(sl)               # Prints 'slice(None, 2, None)'
'hello'[sl]             # Returns 'he' (same as 'hello'[:2])
sl.start, sl.stop, sl.step  # Returns (None, 2, None)

# Object
o = object()            # Assigns a featureless object; object is the base of all
                        # classes/types (about classes/types and objects)
type(o)                 # Returns <class 'object'>
isinstance(o, object)   # Returns True
isinstance(10, object)  # Returns True (int is a subclass of object)

# Type
t = int                 # Assigns a type; all classes/types are instances of 'type'
                        # (about classes/types and objects)
type(t)                 # Returns <class 'type'>
isinstance(t, type)     # Returns True

Basic Object Attributes

The following is a list of attributes (properties and methods) provided by instances of the basic types int, float, complex, bool, slice. (Some general object attributes and low-level attributes are omitted from this list).

Show attributes below:

o.__abs__()             # TBD
                        # applies to int,float,complex,bool
o.__add__()             # TBD
                        # applies to int,float,complex,bool
o.__and__()             # TBD
                        # applies to int,bool
o.__bool__()            # TBD
                        # applies to int,float,complex,bool
o.__ceil__()            # TBD
                        # applies to int,bool
o.__divmod__()          # TBD
                        # applies to int,float,complex,bool
o.__eq__()              # TBD
                        # applies to int,float,complex,bool,slice
o.__float__()           # TBD
                        # applies to int,float,complex,bool
o.__floor__()           # TBD
                        # applies to int,bool
o.__floordiv__()        # TBD
                        # applies to int,float,complex,bool
o.__ge__()              # TBD
                        # applies to int,float,complex,bool,slice
o.__getformat__()       # TBD
                        # applies to float
o.__getnewargs__()      # TBD
                        # applies to int,float,complex,bool
o.__gt__()              # TBD
                        # applies to int,float,complex,bool,slice
o.__index__()           # TBD
                        # applies to int,bool
o.__int__()             # TBD
                        # applies to int,float,complex,bool
o.__invert__()          # TBD
                        # applies to int,bool
o.__le__()              # TBD
                        # applies to int,float,complex,bool,slice
o.__lshift__()          # TBD
                        # applies to int,bool
o.__lt__()              # TBD
                        # applies to int,float,complex,bool,slice
o.__mod__()             # TBD
                        # applies to int,float,complex,bool
o.__mul__()             # TBD
                        # applies to int,float,complex,bool
o.__ne__()              # TBD
                        # applies to int,float,complex,bool,slice
o.__neg__()             # TBD
                        # applies to int,float,complex,bool
o.__or__()              # TBD
                        # applies to int,bool
o.__pos__()             # TBD
                        # applies to int,float,complex,bool
o.__pow__()             # TBD
                        # applies to int,float,complex,bool
o.__radd__()            # TBD
                        # applies to int,float,complex,bool
o.__rand__()            # TBD
                        # applies to int,bool
o.__rdivmod__()         # TBD
                        # applies to int,float,complex,bool
o.__rfloordiv__()       # TBD
                        # applies to int,float,complex,bool
o.__rlshift__()         # TBD
                        # applies to int,bool
o.__rmod__()            # TBD
                        # applies to int,float,complex,bool
o.__rmul__()            # TBD
                        # applies to int,float,complex,bool
o.__ror__()             # TBD
                        # applies to int,bool
o.__round__()           # TBD
                        # applies to int,float,bool
o.__rpow__()            # TBD
                        # applies to int,float,complex,bool
o.__rrshift__()         # TBD
                        # applies to int,bool
o.__rshift__()          # TBD
                        # applies to int,bool
o.__rsub__()            # TBD
                        # applies to int,float,complex,bool
o.__rtruediv__()        # TBD
                        # applies to int,float,complex,bool
o.__rxor__()            # TBD
                        # applies to int,bool
o.__set_format__()      # TBD
                        # applies to float
o.__sub__()             # TBD
                        # applies to int,float,complex,bool
o.__truediv__()         # TBD
                        # applies to int,float,complex,bool
o.__trunc__()           # TBD
                        # applies to int,float,bool
o.__xor__()             # TBD
                        # applies to int,bool
o.as_integer_ratio()    # TBD
                        # applies to float
o.bit_length()          # TBD
                        # applies to int,bool
o.conjugate()           # TBD
                        # applies to int,float,complex,bool
o.denominator           # TBD
                        # applies to int,bool
o.from_bytes()          # TBD
                        # applies to int,bool
o.fromhex()             # TBD
                        # applies to float
o.hex()                 # TBD
                        # applies to float
o.imag                  # TBD
                        # applies to int,float,complex,bool
o.indices()             # TBD
                        # applies to slice
o.is_integer()          # TBD
                        # applies to float
o.numerator             # TBD
                        # applies to int,bool
o.real                  # TBD
                        # applies to int,float,complex,bool
o.start                 # TBD
                        # applies to slice
o.step                  # TBD
                        # applies to slice
o.stop                  # TBD
                        # applies to slice
o.to_bytes()            # TBD
                        # applies to int,bool

Container Types

# Container type detection
import collections.abc                  # Imports abstract base class module
isinstance(o, collections.abc.Container)# Returns True if o is container object (e.g. 'hi')

Sequence Types

# Sequence type detection
import collections.abc                  # Imports abstract base class module
isinstance(o, collections.abc.Sequence) # Returns True if o is sequence object (e.g. 'hi')

# String
s1 = 'Say "hi"\n\'ho\'' # Assigns a string (immutable): Say "hi"(newline)'ho'
s2 = "Say 'hi'\n\"ho\"" # Same as above, but with swapped single- and double-quotes
                        # (Single-quotes allow embedded unescaped double-quotes, and vice
                        # versa, otherwise no difference in behavior)
s3 = """Say "hi"
'ho'"""                 # Same as s1 above; triple-quotes allow embedded unescaped newlines
                        # (usually used for docstrings)
s4 = '''Say 'hi'
"ho"'''                 # Same as s2 above (but triple single-quotes are not often used)
s5 = r'\n\''            # Raw string of length 4; backslashes are taken literally, but
                        # still escape quotes; often used for regular expressions
s6 = r"""\\
"""                     # Raw triple-quoted string of length 3: 2 backslashes and a newline
                        # (see s3 and s5 above)
s7 = '\xC6\u0E01\U0001F60E' # Assigns a string containing 3 Unicode characters; len(s7) is 3
s8 = r'\u0E01\n'        # \u escapes are not interpreted in raw strings; len(s8) is 8
                        # characters)
s9 = f'{2+5:03d}'       # Formatted string literal: '007'
u'hi'                   # Same as 'hi'; Python 3 ignores the u prefix (but ur'' is illegal)
s = ('hel'              # Adjacent string literals are concatenated (s = 'hello');
    "lo")               # useful for splitting string literals and commenting each part
                        # (see statement boundaries for other ways of breaking strings)
type(s)                 # Returns <class 'str'>
isinstance(s, str)      # Returns True
len(s)                  # Returns 5
'e' in s                # Returns True
s[0]                    # Returns 'h'
s[0] = 'a'              # ILLEGAL! Raises TypeError exception because string is immutable
s[-1]                   # Returns 'o'
s[1:3]                  # Returns 'el' (general slice syntax is [start:stop:step] with
                        # default values (if omitted) start=0, stop=end, step=1)
s[-2:]                  # Returns 'lo'
s[:-1]                  # Returns 'hell'
s[::-1]                 # Returns 'olleh'
s + ' there'            # Returns 'hello there'
s * 2                   # Returns 'hellohello'
str(4.1)                # Returns '4.1'

# List
a1 = [3, 'hello']       # Assigns a list (mutable)
type(a1)                # Returns <class 'list'>
isinstance(a1, list)    # Returns True
len(a1)                 # Returns 2
'hello' in a1           # Returns True
a1[-1]                  # Returns 'hello'
a1[0] = 4               # Assigns 4 to first item
a1.append('bye')        # a1 is now [4, 'hello', 'bye']
a1.extend([10, 11])     # a1 is now [4, 'hello', 'bye', 10, 11]
a1[-2:] = [9]           # a1 is now [4, 'hello', 'bye', 9]
del a1[-2:]             # a1 is now [4, 'hello']
a2 = a1                 # a2 now points to same list as a1
                        # (changes to a1 items affect a2 items)
a2 = a1[:]              # a2 is now a shallow copy of a1
                        # (changes to 1st level of a1 don't affect a2)
                        # (use a2 = copy.deepcopy(a1) to make a complete copy)
list('hello')           # Returns ['h', 'e', 'l', 'l', 'o']

# Tuple
t = (3, 'hello')        # Assigns a tuple (immutable)
t = 3, 'hello'          # Same as above but using unenclosed expression list
type(t)                 # Returns <class 'tuple'>
()                      # Returns () (empty tuple)
(4,)                    # Returns (4,) (single-item tuple)
(4)                     # Returns 4 (int, not tuple)
isinstance(t, tuple)    # Returns True
len(t)                  # Returns 2
'hello' in t            # Returns True
t[-1]                   # Returns 'hello'
t[-1] = 'a'             # ILLEGAL! Raises TypeError exception because tuple is immutable
tuple('hello')          # Returns ('h', 'e', 'l', 'l', 'o')
t2 = (4, [])            # Although tuples are immutable, they may contain mutable items
t2[-1].append(5)        # t2 is now (4, [5])

# Namedtuple types
import collections
NT = collections.namedtuple('Mynamedtuple', 'x,y,z')    # Assigns a new named tuple type;
                        # namedtuple itself is not a type but a function that makes a type
type(NT)                # Returns <class 'type'>
nt = NT(4, 5, z=6)      # Assigns a named tuple of type NT (immutable; like tuple, but
                        # allows items to be accessed by name)
type(nt)                # Returns <class '__main__.Mynamedtuple'>
isinstance(nt, NT)      # Returns True
nt.x                    # Returns 4 (unlike tuple)
nt[-1]                  # Returns 6 (like tuple)
5 in nt                 # Returns True (like tuple)
NT._make([6,7,8])       # Same as NT(6, 7, 8) or NT(*[6, 7, 8])

# Bytes
b1 = bytes(3)               # Assigns a bytes object b'\x00\x00\x00' (immutable)
b2 = bytes([65, 66, 67])    # Assigns a bytes object b'ABC' from a list (each value must be
                            # in the range 0-255)
b3 = bytes('\u0E01\u0E2E', 'utf_8')   # Assigns a bytes object b'\xe0\xb8\x81\xe0\xb8\xae'
                                      # from a string using the specified encoding
b4 = b'hi\n' + br'\n'       # Assigns a bytes object b'hi\n\\n' ('hi' + newline + backslash
                            # + 'n', see string type above) from ascii strings
list(b1)                    # Returns [0, 0, 0]
list(b2)                    # Returns [65, 66, 67]
list(b3)                    # Returns [224, 184, 129, 224, 184, 174]
list(b4)                    # Returns [104, 105, 10, 92, 110]
print(b2)                   # Prints "b'ABC'"
print(b2[0])                # Prints '65'
type(b1)                    # Returns <class 'bytes'>
isinstance(b1, bytes)       # Returns True
len(b1)                     # Returns 3
len(b3)                     # Returns 6
b1 += b2                    # b1 is now b'\x00\x00\x00ABC' (b1 is reassigned, not mutated)
b2.decode()                 # Returns string 'ABC'
'ABC'.encode()              # Returns b'ABC'

# Bytearray
b1 = bytearray(2)               # Assigns a bytearray (same as bytes, but mutable)
                                # containing 2 null bytes
b2 = bytearray([65, 66, 67])    # Assigns a bytearray from a list
                                # (each value must be in the range 0-255)
b3 = bytearray('\u0E01\u0E2E', 'utf_8')   # Assigns a bytearray from a string using the
                                          # specified encoding
b4 = bytearray(b'ABC')          # Assigns a bytearray from a bytes object (b4 == b2)
list(b1)                        # Returns [0, 0]
list(b2)                        # Returns [65, 66, 67]
list(b3)                        # Returns [224, 184, 129, 224, 184, 174]
print(b2)                       # Prints "bytearray(b'ABC')"
print(b2[0])                    # Prints '65'
type(b1)                        # Returns <class 'bytearray'>
isinstance(b1, bytearray)       # Returns True
len(b1)                         # Returns 2
b1[0] = 72                      # b1 now contains 72, 0
b1[1:] = b'ey'                  # b1 now contains 72, 101, 121
b1 += b2                        # b1 now contains 72, 101, 121, 65, 66, 67
print(b1)                       # Prints "bytearray(b'HeyABC')"

# Memoryview
b = bytes([4,5,6,7,8,9,254,255])    # Assigns a bytes object from a list
m = memoryview(b)       # Assigns a memoryview referencing object b
type(m)                 # Returns <class 'memoryview'>
isinstance(m, memoryview)   # Returns True
m.readonly              # Returns True (because the referenced object b is immutable)
m.tolist()              # Returns [4, 5, 6, 7, 8, 9, 254, 255]
m[-1]                   # Returns 255 (last element)
m[1:4]                  # Returns a new memoryview referencing b[1:4]
m2 = m.cast('b', [2,4]) # New 2D memoryview referencing b (1-byte signed elements)
m2.tolist()             # Returns [[4, 5, 6, 7], [8, 9, -2, -1]]
m2[1,2]                 # Returns -2
m3 = m.cast('H')        # New memoryview referencing b (2-byte unsigned elements)
m3.tolist()             # Returns [1284, 1798, 2312, 65534] if platform is little-endian,
                        # corresponding to [0x0504, 0x0706, 0x0908, 0xfffe]
m4 = m.cast('i')        # New memoryview referencing b (4-byte signed elements)
m4.tolist()             # Returns [117835012, -128760] if platform is little-endian

ba = bytearray(b'hello')# Assigns a bytearray from a bytes object
m5 = memoryview(ba)     # Assigns a memoryview referencing object ba
m5.readonly             # Returns False (because the referenced object ba is mutable)
m5[1] = ord('u')        # ba is now bytearray(b'hullo')

# Range
r = range(4)            # Assigns a range object (immutable) representing 0, 1, 2, 3 (from
                        # 0 to 4 (4 excluded)) without actually storing this sequence
type(r)                 # Returns <class 'range'>
print(r)                # Prints 'range(0, 4)'; r is an unexpanded range object
print(list(r))          # Prints '[0, 1, 2, 3]'; list(r) expands r to a list
print(tuple(r))         # Prints '(0, 1, 2, 3)'; tuple(r) expands r to a tuple
isinstance(r, range)    # Returns True
len(r)                  # Returns 4
r[-1]                   # Returns 3
range(2, 5)             # Returns range object representing sequence 2, 3, 4 (from 2 to 5
                        # (5 excluded) with step 1)
range(5, 2, -1)         # Returns range object representing sequence 5, 4, 3 (from 5 to 2
                        # (2 excluded) with step -1)

Other Container Types

# Set
u = {3, 'hello'}        # Assigns a set (mutable; unordered unique items)
type(u)                 # Returns <class 'set'>
set()                   # Returns empty set
{}                      # Returns empty dict, not set!
isinstance(u, set)      # Returns True
len(u)                  # Returns 2
'hello' in u            # Returns True
u.add(10)               # u is now {'hello', 10, 3} (undefined order)
u.remove(10)            # u is now {'hello', 3}
u.remove(10)            # Raises KeyError exception (no such item)
u.discard(3)            # u is now {'hello'}
u.discard(3)            # u is unchanged (did not contain 3)
set('hello')            # Returns {'l', 'o', 'h', 'e'} (only one 'l')

# Frozenset
w = frozenset((3, 'hi'))    # Assigns a frozenset (like a set, but immutable, so can be
                            # used as a dictionary key or element of a set)
type(w)                     # Returns <class 'frozenset'>
isinstance(w, frozenset)    # Returns True

# Dict
d = {'a':10, 'b':5}     # Assigns a dictionary (mutable ordered mapping (preserves
                        # insertion order); unique keys; was unordered until Python 3.7)
type(d)                 # Returns <class 'dict'>
{}                      # Returns {} (empty dict, not set)
isinstance(d, dict)     # Returns True
len(d)                  # Returns 2
'a' in d                # Returns True
d['a'] = 11             # d is now {'a': 11, 'b': 5}
dk = d.keys()           # Assigns a live view of d's keys
type(dk)                # Returns <class 'dict_keys'>
list(dk)                # Returns ['a', 'b']
dv = d.values()         # Assigns a live view of d's values
type(dv)                # Returns <class 'dict_values'>
list(dv)                # Returns [11, 5]
di = d.items()          # Assigns a live view of d's items
type(di)                # Returns <class 'dict_items'>
list(di)                # Returns [('a', 11), ('b', 5)]
del d['a']              # d is now {'b': 5}
list(dk)                # Returns ['b']
list(dv)                # Returns [5]
list(di)                # Returns [('b', 5)]
dict((('a',10),('b',5))) # Returns {'a': 10, 'b': 5}
dict(a=10, b=5)         # Returns {'a': 10, 'b': 5}

# Defaultdict
import collections
dd = collections.defaultdict(int, {'a': 3}) # Assigns a defaultdict (same as dict, but the
                        # first arg is called with no args to provide the default value for
                        # nonexistent keys; here, int() returns the default value 0)
type(dd)                # Returns <class 'collections.defaultdict'>
isinstance(dd, collections.defaultdict) # Returns True
dd['a']                 # Returns 3
dd['b']                 # Returns 0 (because that's what int() returns);
                        # dd is now defaultdict(int, {'a': 3, 'b': 0})
dd['c'] += 1            # dd is now defaultdict(int, {'a': 3, 'b': 0, 'c': 1})

# OrderedDict
import collections
od = collections.OrderedDict([('a',10), ('b',11), ('c',12)]) # Assigns an OrderedDict (like
                            # dict but has more functionality and different performance)
type(od)                    # Returns <class 'collections.OrderedDict'>
isinstance(od, collections.OrderedDict) # Returns True
od.move_to_end('a')         # od is now OrderedDict([('b',11), ('c',12), ('a',10)])
od.move_to_end('a',last=False)  # od is now OrderedDict([('a',10), ('b',11), ('c',12)])
od.popitem()                # Returns ('c',12); od is now OrderedDict([('a',10), ('b',11)])
od.popitem(last=False)      # Returns ('a',10); od is now OrderedDict([('b',11)])

# Counter
import collections
c = collections.Counter('abaab')    # Assigns a Counter (like a dict, but the values are
                        # counts for the keys, i.e. {'a': 3, 'b': 2})
type(c)                 # Returns <class 'collections.Counter'>
isinstance(c, collections.Counter)  # Returns True
c['a']                  # Returns 3
c['x']                  # Returns 0
c['c'] += 2             # c is now Counter({'a': 3, 'b': 2, 'c': 2})
c.update(['a', 'c'])    # c is now Counter({'a': 4, 'b': 2, 'c': 3})
c.update({'a': 5})      # c is now Counter({'a': 9, 'b': 2, 'c': 3})
c.most_common(2)        # Returns [('a', 9), ('c', 3)] (ordered with most common first);
                        # if no arg, all items are returned

# Deque (double-ended queue)
import collections
q = collections.deque((3, 'hi'))    # Assigns a deque (a bit like list but with faster
                        # adding/removing of items at both ends and slower indexing in the
                        # middle)
type(q)                 # Returns <class 'collections.deque'>
isinstance(q, collections.deque)    # Returns True
q.append('right')       # q is now deque([3, 'hi', 'right'])
q.appendleft('left')    # q is now deque(['left', 3, 'hi', 'right'])
if q:                   # If q is not empty...
    q.pop()             # Returns 'right'; q is now deque(['left', 3, 'hi'])
q.popleft()             # Returns 'left'; q is now deque([3, 'hi'])
q.extend([4,5])         # q is now deque([3, 'hi', 4, 5])
q.extendleft([2,1])     # q is now deque([1, 2, 3, 'hi', 4, 5])

Container Object Attributes

The following is a list of attributes (properties and methods) provided by instances of the container types str, list, tuple, (types produced by) collections.namedtuple, bytes, bytearray, memoryview, range, set, frozenset, dict, collections.defaultdict, collections.OrderedDict, collections.Counter, collections.deque. (Some general object attributes and low-level attributes are omitted from this list).

Show attributes below:

o.__add__(o2)           # Implements o + o2 (concatenation); 'hi' + 'ho' returns 'hiho';
                        # for Counter the counts of equal keys are added;
                        # applies to str,list,tuple,namedtuple,bytes,bytearray,Counter,
                        # deque
o.__alloc__()           # Returns number of bytes allocated to o;
                        # bytearray('hi').__alloc__() returns 3;
                        # applies to bytearray
o.__and__(o2)           # Implements o & o2 (intersection); {1,'a',3} & {'a',3,4} returns
                        # {'a',3}; for Counter the intersection applies to the keys and the
                        # smallest count is chosen for equal keys;
                        # applies to set,frozenset,Counter
o.__bool__()            # TBD
                        # applies to range,deque
o.__contains__(x)       # Implements x in o (membership test); 'b' in 'abc' returns True;
                        # applies to str,list,tuple,namedtuple,bytes,bytearray,range,set,
                        # frozenset,dict,defaultdict,OrderedDict,Counter,deque
o.__copy__()            # Implements copy.copy(o) (shallow copy);
                        # applies to defaultdict,deque
o.__delitem__(x)        # Implements del o[x] (item deletion); if o = [4,5] then del o[0]
                        # makes o [5]; o.__delitem__(slice(x,y,z)) implements del o[x:y:z];
                        # applies to list,bytearray,memoryview,dict,defaultdict,
                        # OrderedDict,Counter,deque
o.__enter__()           # TBD
                        # applies to memoryview
o.__eq__(o2)            # Implements o == o2;
                        # applies to str,list,tuple,namedtuple,bytes,bytearray,memoryview,
                        # range,set,frozenset,dict,defaultdict,OrderedDict,Counter,deque
o.__exit__()            # TBD
                        # applies to memoryview
o.__ge__(o2)            # Implements o >= o2;
                        # applies to str,list,tuple,namedtuple,bytes,bytearray,memoryview,
                        # range,set,frozenset,dict,defaultdict,OrderedDict,Counter,deque
o.__getitem__(x)        # Implements o[x];
                        # o.__getitem__(slice(x,y,z)) implements o[x:y:z];
                        # applies to str,list,tuple,namedtuple,bytes,bytearray,memoryview,
                        # range,dict,defaultdict,OrderedDict,Counter,deque
o.__getnewargs__()      # TBD (pickle protocol)
                        # applies to str,tuple,namedtuple,bytes
o.__gt__(o2)            # Implements o > o2;
                        # applies to str,list,tuple,namedtuple,bytes,bytearray,memoryview,
                        # range,set,frozenset,dict,defaultdict,OrderedDict,Counter,deque
o.__iadd__(o2)          # Implements o += o2 (in-place concatenation); if o = [1,2] then
                        # o += [3,4] makes o [1,2,3,4];
                        # applies to list,bytearray,Counter,deque
o.__iand__(o2)          # Implements o &= o2 (in-place intersection);
                        # applies to set,Counter
o.__imul__(x)           # Implements o *= x (in-place repetition); if o = [1,2] then o *= 3
                        # makes o [1,2,1,2,1,2];
                        # applies to list,bytearray,deque
o.__ior__(o2)           # Implements o |= o2 (in-place union);
                        # applies to set,Counter
o.__isub__(o2)          # Implements o -= o2 (in-place difference);
                        # applies to set,Counter
o.__iter__()            # Returns an iterator for iterable o;
                        # applies to str,list,tuple,namedtuple,bytes,bytearray,range,set,
                        # frozenset,dict,defaultdict,OrderedDict,Counter,deque
o.__ixor__(o2)          # Implements o ^= o2 (in-place symmetric difference);
                        # applies to set
o.__le__(o2)            # Implements o <= o2;
                        # applies to str,list,tuple,namedtuple,bytes,bytearray,memoryview,
                        # range,set,frozenset,dict,defaultdict,OrderedDict,Counter,deque
o.__len__()             # Implements len(o) (item count); len([5,6]) returns 2;
                        # applies to str,list,tuple,namedtuple,bytes,bytearray,memoryview,
                        # range,set,frozenset,dict,defaultdict,OrderedDict,Counter,deque
o.__lt__(o2)            # Implements o < o2;
                        # applies to str,list,tuple,namedtuple,bytes,bytearray,memoryview,
                        # range,set,frozenset,dict,defaultdict,OrderedDict,Counter,deque
o.__missing__(x)        # Implements o[x] if x is not one of o's keys; returns the default
                        # value for a missing key;
                        # applies to defaultdict,Counter
o.__mod__(x)            # Implements o % x (formatting); '%-3s%03u' % ('hi', 9) returns
                        # 'hi 009';
                        # applies to str,bytes,bytearray
o.__mul__(x)            # Implements o * x (repetition); [1,2] * 3 returns [1,2,1,2,1,2];
                        # applies to str,list,tuple,namedtuple,bytes,bytearray,deque
o.__ne__(o2)            # Implements o != o2;
                        # applies to str,list,tuple,namedtuple,bytes,bytearray,memoryview,
                        # range,set,frozenset,dict,defaultdict,OrderedDict,Counter,deque
o.__neg__()             # TBD
                        # applies to Counter
o.__or__(o2)            # Implements o | o2 (union); {1,'a',3} | {'a',3,4} returns
                        # {1,'a',3,4}; for Counter the union applies to the keys and the
                        # largest count is chosen for equal keys;
                        # applies to set,frozenset,Counter
o.__pos__()             # TBD
                        # applies to Counter
o.__rand__(o2)          # Implements o2 & o (reverse intersection);
                        # applies to set,frozenset
o.__reversed__()        # Implements reversed(o); returns a reverse order iterator for o;
                        # applies to list,range,OrderedDict,deque
o.__rmod__(o2)          # Implements o2 % o (reverse formatting);
                        # applies to str,bytes,bytearray
o.__rmul__(x)           # Implements x * o (reverse repetition); 3 * [1,2] returns
                        # [1,2,1,2,1,2];
                        # applies to str,list,tuple,namedtuple,bytes,bytearray,deque
o.__ror__(o2)           # Implements o2 | o (reverse union);
                        # applies to set,frozenset
o.__rsub__(o2)          # Implements o2 - o (reverse difference);
                        # applies to set,frozenset
o.__rxor__(o2)          # Implements o2 ^ o (reverse symmetric difference);
                        # applies to set,frozenset
o.__setitem__(x, v)     # Implements o[x] = v;
                        # o.__setitem__(slice(x,y,z), v) implements o[x:y:z] = v;
                        # applies to list,bytearray,memoryview,dict,defaultdict,
                        # OrderedDict,Counter,deque
o.__sub__(o2)           # Implements o - o2 (difference); {1,'a',3} - {'a',3,4} returns {1};
                        # for Counter the counts of equal keys are subtracted and only keys
                        # with positive counts are retained;
                        # applies to set,frozenset,Counter
o.__xor__(o2)           # Implements o ^ o2 (symmetric difference); {1,'a',3} ^ {'a',3,4}
                        # returns {1,4};
                        # applies to set,frozenset
o._asdict()             # TBD
                        # applies to namedtuple
o._fields               # TBD
                        # applies to namedtuple
o._fields_defaults      # TBD
                        # applies to namedtuple
o._keep_positive()      # TBD
                        # applies to Counter
o._make()               # TBD
                        # applies to namedtuple
o._replace()            # TBD
                        # applies to namedtuple
o.add(x)                # Puts x into o; if o = {3} then o.add(5) makes o {3,5};
                        # applies to set
o.append(x)             # Inserts x at end of o; if o = [3] then o.append(5) makes o [3,5];
                        # applies to list,bytearray,deque
o.appendleft(x)         # Inserts x at start of o; if o = deque([3]) then o.appendleft(5)
                        # makes o deque([5, 3]);
                        # applies to deque
o.c_contiguous          # TBD
                        # applies to memoryview
o.capitalize()          # Returns o with first character capitalized; 'hi ho'.capitalize()
                        # returns 'Hi ho';
                        # applies to str,bytes,bytearray
o.casefold()            # TBD
                        # applies to str
o.cast()                # TBD
                        # applies to memoryview
o.center(w,c)           # Returns o centered in a string of length w filled with c (space
                        # if no c); returns o if len(o) >= w;
                        # 'hi'.center(5,'*') returns '**hi*';
                        # applies to str,bytes,bytearray
o.clear()               # Makes o empty; if o = {3:9,5:25} then o.clear() makes o {};
                        # applies to list,bytearray,set,dict,defaultdict,OrderedDict,
                        # Counter,deque
o.contiguous            # TBD
                        # applies to memoryview
o.copy()                # Returns a shallow copy of o (similar to copy.copy(o) but doesn't
                        # call o.__copy__()); if o = {4:[5]} then o.copy() returns a new
                        # {4:[5]} referencing the same list [5] as o;
                        # applies to list,bytearray,set,frozenset,dict,defaultdict,
                        # OrderedDict,Counter,deque
o.count(x,a,b)          # Returns count of non-overlapping occurrences of x in o[a:b];
                        # a,b are optional; 'hohohoho'.count('hoho') returns 2;
                        # applies to str,list,tuple,namedtuple,bytes,bytearray,range,deque
o.decode(enc,err)       # Returns string equal to o decoded using encoding enc
                        # (default 'utf-8') and error scheme err (default 'strict')
                        # b'A\xc7\xbf'.decode() returns 'A\u01ff';
                        # b'A\xc0'.decode() raises UnicodeDecodeError;
                        # b'A\xc0'.decode('utf-8','ignore') returns 'A';
                        # b'A\xc0'.decode('utf-8','replace') returns 'A\ufffd';
                        # applies to bytes,bytearray
o.default_factory       # TBD
                        # applies to defaultdict
o.difference(o2,...)        # Same as o - set(o2) - ... (doesn't call o.__sub__());
                            # applies to set,frozenset
o.difference_update(o2,...) # Same as o -= set(o2) | ... (doesn't call o.__isub__());
                            # applies to set
o.discard(x)            # Removes item x from o; does nothing if x is not in o;
                        # if o = {3,5} then o.discard(5) makes o {3};
                        # applies to set
o.elements()            # TBD
                        # applies to Counter
o.encode(enc,err)       # Returns bytes object equal to o encoded using encoding enc
                        # (default 'utf-8') and error scheme err (default 'strict')
                        # 'A\u01ff'.encode() returns b'A\xc7\xbf';
                        # 'A\u0080'.encode('ascii') raises UnicodeEncodeError;
                        # 'A\u0080'.encode('ascii','ignore') returns b'A';
                        # 'A\u0080'.encode('ascii','replace') returns b'A?';
                        # 'A\u0080'.encode('ascii','xmlcharrefreplace') returns b'A&#128;';
                        # 'A\u0080'.encode('ascii','backslashreplace') returns b'A\\x80';
                        # applies to str
o.endswith(x,a,b)       # Returns True if o[a:b] ends with x (or with an item in tuple x);
                        # 'abc'.endswith(('bc','z')) returns True;
                        # applies to str,bytes,bytearray
o.expandtabs(n)         # Returns a copy of o with tab characters replaced by up to n
                        # spaces (enough spaces to reach the next tab column);
                        # '\ta\tbc\td'.expandtabs(3) returns '   a  bc d';
                        # applies to str,bytes,bytearray
o.extend(o2)            # Same as o += o2 (doesn't call o.__iadd__());
                        # applies to list,bytearray,deque
o.extendleft()          # TBD
                        # applies to deque
o.f_contiguous          # TBD
                        # applies to memoryview
o.find(o2,a,b)          # Returns index of first occurrence of substring o2 in o[a:b] (a=0,
                        # b=-1 if not given), or -1 if none found;
                        # 'abab'.find('ab') returns 0; 'abab'.find('ab',1,3) returns -1;
                        # applies to str,bytes,bytearray
o.format(...)           # Returns a string representing the arguments formatted according
                        # to the directives in o; see string formatting;
                        # applies to str,memoryview
o.format_map()          # TBD
                        # applies to str
o.fromhex(s)            # Class method; returns object of same class as o containing bytes
                        # corresponding to pairs of hex digits in string s;
                        # bytes.fromhex('4142 43 0a') returns b'ABC\n';
                        # applies to bytes,bytearray
o.fromkeys(o2,x)        # Class method; returns object of same class as o containing all
                        # items of sequence o2 as keys with all values equal to x (default
                        # None); dict.fromkeys(('a','b'), 5) returns {'a':5, 'b':5};
                        # applies to dict,defaultdict,OrderedDict
o.get()                 # TBD
                        # applies to dict,defaultdict,OrderedDict,Counter
o.hex()                 # Returns string containing pairs of hex digits corresponding to
                        # bytes in o; b'ABC\n'.hex() returns '4142430a';
                        # applies to bytes,bytearray,memoryview
o.index(x,a,b)          # Returns index of first occurrence of item x in o[a:b] (a=0, b=-1
                        # if not given); raises ValueError if x is not in o[a:b];
                        # for str,bytes,bytearray: x may be a substring of o;
                        # [4,5,4].index(4) returns 0; 'abab'.index('ab',1) returns 2;
                        # applies to str,list,tuple,namedtuple,bytes,bytearray,range,deque
o.insert(i,x)           # Inserts item x in o at index i; same as o[i:i] = [x];
                        # if o = [4,5,6] then o.insert(2,'a') makes o [4,5,'a',6];
                        # applies to list,bytearray,deque
o.intersection(o2,...)          # Same as o & set(o2) & ... (doesn't call o.__and__());
                                # applies to set,frozenset
o.intersection_update(o2,...)   # Same as o &= set(o2) & ... (doesn't call o.__iand__());
                                # applies to set
o.isalnum()             # Returns True if o is not empty and contains only alphanumeric
                        # characters (alphabetic or numeric characters);
                        # applies to str,bytes,bytearray
o.isalpha()             # Returns True if o is not empty and contains only alphabetic
                        # characters;
                        # applies to str,bytes,bytearray
o.isascii()             # TBD
                        # applies to str,bytes,bytearray
o.isdecimal()           # Returns True if o is not empty and contains only decimal
                        # characters (a subset of digits (the official doc is wrong));
                        # for characters '2๒': '2\u0e52'.isdecimal() returns True;
                        # for character '²':    '\u00b2'.isdecimal() returns False;
                        # for character '½':    '\u00bd'.isdecimal() returns False;
                        # applies to str
o.isdigit()             # Returns True if o is not empty and contains only digits
                        # (a subset of numeric characters);
                        # for characters '2๒': '2\u0e52'.isdigit() returns True;
                        # for character '²':    '\u00b2'.isdigit() returns True;
                        # for character '½':    '\u00bd'.isdigit() returns False;
                        # applies to str,bytes,bytearray
o.isdisjoint(o2)        # Returns True if o and o2 have no common items;
                        # applies to set,frozenset
o.isidentifier()        # TBD
                        # applies to str
o.islower()             # Returns True if o contains at least 1 cased character and all
                        # cased characters are lowercase; 'ver2.0'.islower() returns True;
                        # applies to str,bytes,bytearray
o.isnumeric()           # Returns True if o is not empty and contains only numeric
                        # characters;
                        # for characters '2๒': '2\u0e52'.isnumeric() returns True;
                        # for character '²':    '\u00b2'.isnumeric() returns True;
                        # for character '½':    '\u00bd'.isnumeric() returns True;
                        # applies to str
o.isprintable()         # TBD
                        # applies to str
o.isspace()             # Returns True if o is not empty and contains only whitespace
                        # characters; ' \t\n\r\f\v'.isspace() returns True;
                        # applies to str,bytes,bytearray
o.issubset(o2)          # Same as o <= o2 (doesn't call o.__le__());
                        # applies to set,frozenset
o.issuperset(o2)        # Same as o >= o2 (doesn't call o.__ge__());
                        # applies to set,frozenset
o.istitle()             # Returns True if o contains at least 1 uppercase character, no
                        # uppercase character follows a cased character, and any lowercase
                        # character follows a cased character;
                        # '2B|Not 2B'.istitle() returns True;
                        # applies to str,bytes,bytearray
o.isupper()             # Returns True if o contains at least 1 cased character and all
                        # cased characters are uppercase; 'VER2.0'.isupper() returns True;
                        # applies to str,bytes,bytearray
o.items()               # TBD
                        # applies to dict,defaultdict,OrderedDict,Counter
o.itemsize              # TBD
                        # applies to memoryview
o.join(o2)              # Returns the string obtained by concatenating all items of o2
                        # using o as separator; '/'.join('abc') returns 'a/b/c';
                        # '=='.join(['x','42']) returns 'x==42';
                        # applies to str,bytes,bytearray
o.keys()                # TBD
                        # applies to dict,defaultdict,OrderedDict,Counter
o.ljust(w,c)            # Returns o left-justified in a string of length w filled with c
                        # (space if no c); returns o if len(o) >= w;
                        # 'hi'.ljust(5,'*') returns 'hi***';
                        # applies to str,bytes,bytearray
o.lower()               # Returns a copy of o with all uppercase characters converted to
                        # lowercase; '2B|Not 2B'.lower() returns '2b|not 2b';
                        # applies to str,bytes,bytearray
o.lstrip(s)             # Returns a copy of o with first characters removed if present in
                        # string s (whitespace if no s); 'abcd'.lstrip('dba') returns 'cd';
                        # applies to str,bytes,bytearray
o.maketrans()           # TBD
                        # applies to str,bytes,bytearray
o.maxlen                # TBD
                        # applies to deque
o.most_common()         # TBD
                        # applies to Counter
o.move_to_end()         # TBD
                        # applies to OrderedDict
o.nbytes                # TBD
                        # applies to memoryview
o.ndim                  # TBD
                        # applies to memoryview
o.obj                   # TBD
                        # applies to memoryview
o.partition()           # TBD
                        # applies to str,bytes,bytearray
o.pop(i)                # Removes and returns item o[i] (o[-1] if no i);
                        # for set: removes and returns arbitrary item (no i allowed);
                        # raises IndexError (list) or KeyError (set, dict) if no item;
                        # applies to list,bytearray,set,dict,defaultdict,OrderedDict,
                        # Counter,deque
o.popitem()             # TBD
                        # applies to dict,defaultdict,OrderedDict,Counter
o.popleft()             # TBD
                        # applies to deque
o.readonly              # TBD
                        # applies to memoryview
o.release()             # TBD
                        # applies to memoryview
o.remove(x)             # Removes item x from o; raises KeyError if x is not in o;
                        # if o = [3,5] then o.remove(5) makes o [3];
                        # applies to list,bytearray,set,deque
o.replace()             # TBD
                        # applies to str,bytes,bytearray
o.reverse()             # Reverses the items of o; same as o[::-1] = o;
                        # if o = [4,5,6] then o.reverse() makes o [6,5,4];
                        # applies to list,bytearray,deque
o.rfind(o2,a,b)         # Same as o.find(), except last occurrence is chosen;
                        # applies to str,bytes,bytearray
o.rindex(x,a,b)         # Same as o.index(), except last occurrence is chosen;
                        # applies to str,bytes,bytearray
o.rjust(w,c)            # Returns o right-justified in a string of length w filled with c
                        # (space if no c); returns o if len(o) >= w;
                        # 'hi'.rjust(5,'*') returns '***hi';
                        # applies to str,bytes,bytearray
o.rotate()              # TBD
                        # applies to deque
o.rpartition()          # TBD
                        # applies to str,bytes,bytearray
o.rsplit()              # TBD
                        # applies to str,bytes,bytearray
o.rstrip(s)             # Returns a copy of o with last characters removed if present in
                        # string s (whitespace if no s); 'abcd'.rstrip('cda') returns 'ab';
                        # applies to str,bytes,bytearray
o.setdefault()          # TBD
                        # applies to dict,defaultdict,OrderedDict,Counter
o.shape                 # TBD
                        # applies to memoryview
o.sort(key=kf,reverse=r)# Sorts the items of o using key function kf (kf(x) extracts a
                        # comparison key from each item x, and is lambda x:x if not given);
                        # two items x and y are always compared using kf(x).__lt__(kf(y));
                        # sort order is reversed if r is True (r is False if not given);
                        # if o = [-6,5,10] then o.sort(reverse=True) makes o [10,5,-6], and
                        # o.sort(key=abs) makes o [5,-6,10];
                        # applies to list
o.split()               # TBD
                        # applies to str,bytes,bytearray
o.splitlines()          # TBD
                        # applies to str,bytes,bytearray
o.start                 # TBD
                        # applies to range
o.startswith(x,a,b)     # Returns True if o[a:b] starts with x (or with an item in tuple x);
                        # 'abc'.startswith(('ab','z')) returns True;
                        # applies to str,bytes,bytearray
o.step                  # TBD
                        # applies to range
o.stop                  # TBD
                        # applies to range
o.strides               # TBD
                        # applies to memoryview
o.strip(s)              # Returns a copy of o with characters removed from both ends if
                        # present in string s (whitespace if no s);
                        # '0+a+b!'.strip('!+0') returns 'a+b';
                        # applies to str,bytes,bytearray
o.suboffsets            # TBD
                        # applies to memoryview
o.subtract()            # TBD
                        # applies to Counter
o.swapcase()            # TBD
                        # applies to str,bytes,bytearray
o.symmetric_difference(o2)          # Same as o ^ o2 (doesn't call o.__xor__());
                                    # applies to set,frozenset
o.symmetric_difference_update(o2)   # Same as o ^= o2 (doesn't call o.__ixor__());
                                    # applies to set
o.title()               # TBD
                        # applies to str,bytes,bytearray
o.tobytes()             # TBD
                        # applies to memoryview
o.tolist()              # TBD
                        # applies to memoryview
o.translate()           # TBD
                        # applies to str,bytes,bytearray
o.union(o2,...)         # Same as o | set(o2) | ... (doesn't call o.__or__());
                        # applies to set,frozenset
o.update(o2,...)        # Updates o with items from o2, ...;
                        # for set: same as o |= set(o2) | ... (doesn't call o.__ior__());
                        # applies to set,dict,defaultdict,OrderedDict,Counter
o.upper()               # Returns a copy of o with all lowercase characters converted to
                        # uppercase; '2B|Not 2B'.upper() returns '2B|NOT 2B';
                        # applies to str,bytes,bytearray
o.values()              # TBD
                        # applies to dict,defaultdict,OrderedDict,Counter
o.zfill()               # TBD
                        # applies to str,bytes,bytearray

Iterator Types

# Iterator and iterable type detection
import collections.abc                  # Imports abstract base class module
isinstance(o, collections.abc.Iterator) # Returns True if o is an iterator object
isinstance(o, collections.abc.Iterable) # Returns True if o is an iterable object (e.g.
                        # container or iterator), in which case iter(o) returns an iterator
                        # for o

# Iterator types
si = iter('hello')      # Assigns a string iterator
type(si)                # Returns <class 'str_iterator'>
next(si)                # Returns 'h', i.e. next item; raises StopIteration exception
                        # when no more items; iterators normally can't be restarted (one
                        # exception is a file f which can be restarted with f.seek(0))
next(si, '.')           # Returns 'e'; returns '.' when no more items

li = iter([3, 'hi'])    # Assigns a list iterator
type(li)                # Returns <class 'list_iterator'>
next(li)                # Returns 3

ti = iter((3, 'hi'))    # Assigns a tuple iterator
type(ti)                # Returns <class 'tuple_iterator'>
next(ti)                # Returns 3

seti = iter({3, 'hi'})  # Assigns a set iterator (iteration sequence is unpredictable)
type(seti)              # Returns <class 'set_iterator'>
next(seti)              # Returns 3

d = {'a':10, 'b':5}     # Assigns a dictionary (iteration sequence is unpredictable)
dki = iter(d)           # Assigns a dictionary key iterator (same as iter(d.keys()))
type(dki)               # Returns <class 'dict_keyiterator'>
next(dki)               # Returns 'a'
dvi = iter(d.values())  # Assigns a dictionary value iterator
type(dvi)               # Returns <class 'dict_valueiterator'>
next(dvi)               # Returns 10
dii = iter(d.items())   # Assigns a dictionary item iterator
type(dii)               # Returns <class 'dict_itemiterator'>
next(dii)               # Returns ('a', 10)

bi = iter(b'hello')     # Assigns a bytes iterator
type(bi)                # Returns <class 'bytes_iterator'>
next(bi)                # Returns 104 (ascii value of 'h')

bai = iter(bytearray([65, 0])) # Assigns a bytearray iterator
type(bai)               # Returns <class 'bytearray_iterator'>
next(bai)               # Returns 65

ri = iter(range(5))     # Assigns a range iterator
type(ri)                # Returns <class 'range_iterator'>
next(ri)                # Returns 0

se = enumerate('hello') # Assigns an enumerate object (iterator) for a string
type(se)                # Returns <class 'enumerate'>
isinstance(se, enumerate)   # Returns True
next(se)                # Returns (0, 'h'); first item in this tuple is count
next(se)                # Returns (1, 'e')
xe = enumerate(ri, 100) # Assigns an enumerate object for a range iterator (see above)
                        # with count starting at 100; ri already iterated once above, so
                        # first xe iteration triggers second ri iteration
next(xe)                # Returns (100, 1)
next(xe)                # Returns (101, 2)
next(ri)                # Returns 3; xe uses ri to iterate, so ri is also at item 3

z = zip('ab',[3,4])     # Assigns a zip object (iterator)
type(z)                 # Returns <class 'zip'>
isinstance(z, zip)      # Returns True
next(z)                 # Returns ('a', 3)
next(z)                 # Returns ('b', 4)
Generator objects (see generator expressions and generator functions) and files are also iterators.

More Types

"Everything is an object", so see these other object types:

Control Flow Manipulation

Conditional Execution

# 'If' statement
if x == 3:
    x = y               # Lines at same nesting level must have same indentation
    if not z:           # (see compound statement format)
        y += 1
elif y != 4:
    pass                # Does nothing (placeholder for empty statement list)
else:
    y = x
    # Single-line 'if'
    if z: x = 1; y = 2  # Semi-colon binds tighter than colon, so doesn't end the 'if'
    else: y = 1; x = 2
See also conditional expressions.

Loops

# While loop
while x < 10:
    x += 1
    if x == 5:
        continue        # Skips rest of loop body and goes back to testing loop condition
    print(x)
    if x == y:
        break           # Exits loop and skips 'else' part
else:                   # Optional; does something if loop condition tested false,
                        # i.e. when no more iterations and no break
    print('no break')

# For loop
for x in alist:         # x becomes each item of alist in turn; alist is evaluated once
                        # (Note: alist can be any iterable type or iterator)
    print(x)
    for i in range(x):  # range(x) is a sequence of integers from 0 through x - 1
        print(i)
else:                   # Optional; do something when no more iterations and no break
    pass

Exception Handling

# Try (with all parts)
try:
    x = 1 / 0           # Raises exception which triggers 1st 'except' & 'finally'
except ZeroDivisionError as e:  # Executed on specific exception in try part
    print('Oops:', e)   # Prints 'Oops: division by zero'
except:                 # Executed on any (not already handled) exception in try part
    print('Bad!')
else:                   # Optional; executed only if no exception in try part; same as
                        # putting code at end of try part, but exceptions are not handled
    print('All OK')
finally:                # Optional; always executed as last step, even on unhandled
                        # exception or return/break/continue (in try/except/else parts)
    print('Clean up')

# Try (with finally only)
try:
    raise RuntimeError  # Raises exception which is not handled here
finally:                # but finally part is executed
    print('Clean up')

Script Termination

import sys              # Imports the sys module
sys.exit()              # Raises a SystemExit exception which terminates the script with
                        # exit code 0 (usually considered to mean success) -
                        # unless the exception is caught by a try statement
sys.exit(2)             # Same as above, but uses the specified exit code
sys.exit('Oops!')       # Same as above, but prints the specified string and uses
                        # exit code 1 (usually considered to mean failure)
sys.exit(obj)           # Same as above, but converts the specified object to a string,
                        # prints it, and uses exit code 1, unless obj is None, in which
                        # case nothing is printed and exit code is 0
exit()                  # Not recommended for use in scripts; intended for use in the
                        # interactive interpreter where it works like sys.exit()

Input/Output

Script Arguments

import sys              # Imports the sys module
sys.argv                # Returns a list containing the script name and command line args
print(sys.argv[0])      # Prints script name (possibly full path)
if len(sys.argv) > 1:   # If there are any command line arguments, then ...
    print(sys.argv[1])  # ... print first one

Standard In/Out/Error

# Stdout
x = 10
d = {'a': 4, 'b': 5}
print('d =', d)         # Prints 'd = {'a': 4, 'b': 5}' + newline to stdout;
                        # args are separated by a space
print('x =', x, end=' ')# Prints 'x = 10 ' to stdout without newline (default end is '\n')
print('(decimal)')      # Prints '(decimal)', so whole line is 'x = 10 (decimal)'
print('x', x, sep=' = ')# Prints 'x = 10' + newline to stdout (default sep is ' ')

# Stderr
import sys                          # Imports sys module
print('x =', x, end='', file=sys.stderr)  # Prints 'x = 10' to stderr without newline;
                                          # (default file is sys.stdout)
print(' (decimal)', file=sys.stderr)  # Prints ' (decimal)'; whole line: 'x = 10 (decimal)'
sys.stderr.write('x = %d' % x)      # Prints 'x = 10' to stderr (never automatic newline)
sys.stderr.write(' (decimal)\n')    # Prints ' (decimal)' + newline;
                                    # whole line printed to stderr: 'x = 10 (decimal)'
a1 = ['hi\n', 'ho\n']               # List of strings incl. newlines
sys.stderr.writelines(a1)           # Prints 'hi' + newline + 'ho' + newline

# Stdin
q = input('Q: ')        # Prints 'Q: ' to stdout (without newline), then reads a line from
                        # stdin as a string, strips the newline, and assigns it to q
s = sys.stdin.read()    # Reads stdin until end of file and assigns the whole thing
                        # (incl. newlines) as a string to s
s = sys.stdin.readline()    # Reads one line from stdin as string incl. newline;
                            # returns empty string if no more lines
a = sys.stdin.readlines()   # Reads all lines from stdin as list of strings incl. newlines

Files

A file can be opened as either a text file or a binary file, and (unlike in Python 2) the class of the opened file object and the supported operations depend on whether the file was opened as text or binary.

Files Opened as Text

Text file operations deal with str objects (i.e. Unicode text) and provide automatic platform dependent newline conversion (i.e. Python newlines '\n' are converted to/from whatever the platform uses in text files, e.g. '\r\n' for MS Windows). The default newline conversion can be controlled/disabled via the newline keyword parameter to open().

The file pointer of a file opened in text mode should only be moved (using f.seek()) to positions previously returned by f.tell(), or to the start or end of the file. No assumptions should be made about the meaning of a value returned by f.tell(), except that it can be passed to f.seek() to get back to the same position in the file. In other words, f.tell() does not necessarily return the number of bytes from the start of the file.

import io                   # Import io module containing file related extras

# Creating/truncating + writing text file, and misc. file methods
fname = 'txtfile.txt'
f = open(fname, 'w')        # Creates/truncates and opens file in text mode for writing
                            # from position 0; optional newline parameter controls newline
                            # handling:
                            #   newline=None   ('\n' maps to os.linesep, this is default)
                            #   newline=''     (no conversion)
                            #   newline='\n'   ('\n' maps to '\n', i.e. no conversion)
                            #   newline='\r'   ('\n' maps to '\r', i.e. Mac style)
                            #   newline='\r\n' ('\n' maps to '\r\n', i.e. Windows style)
type(f)                     # Returns <class '_io.TextIOWrapper'> (same for all text modes)
isinstance(f, io.TextIOWrapper) # Returns True
isinstance(f, io.TextIOBase)    # Returns True (superclass of all text files)
isinstance(f, io.IOBase)        # Returns True (superclass of both text and binary files)
f.tell()                    # Returns 0 (position of file pointer in some sense)
x = 10
print('x =', x, end=' ', file=f)    # Writes 'x = 10 ' to file without newline
print('m', file=f)                  # Writes 'm' + newline;
                                    # whole line: 'x = 10 m'
f.write('x = %d' % x)       # Writes 'x = 10' to file (never automatic newline) and returns
                            # 6 (number of chars written)
f.write(' m\n')             # Writes ' m' + newline and returns 3 (chars written);
                            # whole line: 'x = 10 m'
f.tell()                    # Returns 20 on Windows (position of file pointer in some sense)
a1 = ['hi\n', 'ho\n']       # List of strings incl. newlines
f.writelines(a1)            # Writes 'hi\n' + 'ho\n' to file
f.tell()                    # Returns 28 on Windows (position of file pointer in some sense)
f.close()                   # Closes file
                            # File now contains 'x = 10 m\nx = 10 m\nhi\nho\n'

# Exclusively creating text file (only if it doesn't already exist)
f = open(fname, 'x')        # Raises FileExistsError exception because file already exists;
                            # same as mode 'w' if file doesn't exist
                            # File still contains 'x = 10 m\nx = 10 m\nhi\nho\n'

# Reading text file, and misc. file methods
f = open(fname, 'r')        # Opens existing file in text mode for reading from pos 0
                            # ('r' is optional); optional newline parameter controls
                            # newline handling:
                            #   newline=None   (any newline maps to '\n' and separates lines,
                            #                  this is default)
                            #   newline=''     (no conversion, any newline separates lines)
                            #   newline='\n'   (no conversion, only '\n' separates lines)
                            #   newline='\r'   (no conversion, only '\r' separates lines)
                            #   newline='\r\n' (no conversion, only '\r\n' separates lines)
f.tell()                    # Returns 0 (position of file pointer in some sense)
s = f.read()                # Reads entire file as string
f.tell()                    # Returns 28 on Windows (position of file pointer in some sense)
f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
f.seek(20)                  # Moves file pointer to position 20 in some sense (we don't
                            # know what 20 means, but we previously got it from f.tell()
                            # before writing 'hi\nho\n', so we know it is that position)
s = f.read()                # Reads remainder of file from current position: 'hi\nho\n'
f.seek(0, io.SEEK_END)      # Moves file pointer to end of file and returns 28 on Windows
                            # (position of file pointer in some sense);
f.seek(-10, io.SEEK_END)    # Raises io.UnsupportedOperation exception because non-zero
                            # move from end of file is not supported for text files
f.seek(0, io.SEEK_CUR)      # Moves file pointer nowhere (no move) and returns 28 on Windows
f.seek(-10, io.SEEK_CUR)    # Raises io.UnsupportedOperation exception because non-zero
                            # move from current position is not supported for text files
f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
s = f.readline()            # Reads next line from file as string incl. newline;
                            # returns empty string if no more lines
f.tell()                    # Returns 10 on Windows (position of file pointer in some sense)
a = f.readlines()           # Reads all remaining lines from file as list of strings
                            # incl. newlines
f.tell()                    # Returns 28 on Windows (position of file pointer in some sense)
f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
s = next(f)                 # Same as f.readline() but raises StopIteration at end of file
                            # (files are iterators with additional control via f.seek())
for s in f: print(s, end='')# Iterates through remaining lines in file and prints each one
f.close()                   # Closes file
                            # File still contains 'x = 10 m\nx = 10 m\nhi\nho\n'

# 'With' statement (good practice)
with open(fname) as f:      # 'with' ensures that file is closed when the 'with' suite of
    s = f.read()            # statements ends or raises an exception
                            # File still contains 'x = 10 m\nx = 10 m\nhi\nho\n'

# Appending to text file (creating it if needed)
f = open(fname, 'a')        # (Creates and) opens file in text mode for appending
                            # (writing at end)
f.tell()                    # Returns 28 on Windows (position of file pointer in some sense
                            # - irrelevant for mode 'a')
print('hum', file=f)        # Appends 'hum\n' to end of file
f.tell()                    # Returns 33 on Windows (position of file pointer in some sense)
f.close()                   # Closes file
                            # File now contains 'x = 10 m\nx = 10 m\nhi\nho\nhum\n'

# Creating/truncating + writing & reading text file
f = open(fname, 'w+')       # Creates/truncates and opens file in text mode for writing
                            # and reading
s = f.read()                # Reads entire file as string: '' because file was truncated
print('hi', file=f)         # Writes 'hi\n' to file
f.tell()                    # Returns 4 on Windows (position of file pointer in some sense)
f.close()                   # Closes file
                            # File now contains 'hi\n'

# Reading & writing text file
f = open(fname, 'r+')       # Opens existing file in text mode for reading and writing
                            # (no truncating) from start of file
s = f.read(1)               # Reads 1 char from file as string: 'h'
f.tell()                    # Returns 1 on Windows (position of file pointer in some sense)
f.seek(0, io.SEEK_CUR)      # Doesn't move file pointer but flushes line buffer (needed for
                            # text files when switching between reading and writing) and
                            # returns 1 on Windows (position of file pointer in some sense)
print('o', end='', file=f)  # Writes 'o' to file - overwriting previous 'i' in 'hi\n'
f.tell()                    # Returns 2 on Windows (position of file pointer in some sense)
f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
s = f.read()                # Reads entire file as string: 'ho\n'
f.close()                   # Closes file
                            # File now contains 'ho\n'

# Appending to & reading text file (creating it if needed)
f = open(fname, 'a+')       # (Creates and) opens file in text mode for appending and
                            # reading from end of file
f.tell()                    # Returns 4 on Windows (position of file pointer in some sense)
f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
s = f.read()                # Reads entire file as string: 'ho\n'
f.tell()                    # Returns 4 on Windows (position of file pointer in some sense)
f.seek(0)                   # Moves file pointer back to start of file (doesn't affect
                            # append operation)
print('hum', file=f)        # Appends 'hum\n' to end of file; file is now 'ho\nhum\n'
f.tell()                    # Returns 9 on Windows (position of file pointer in some sense)
f.read()                    # Reads and returns remainder of file: '' because file pointer
                            # was at end of file
f.tell()                    # Returns 9 on Windows (position of file pointer in some sense)
f.close()                   # Closes file
                            # File now contains 'ho\nhum\n'

Files Opened as Binary

Binary file operations deal with bytes-like objects and do not perform any newline conversion.

The file pointer of a file opened in binary mode can be moved (using f.seek()) to any byte position within the file, and f.tell() returns the number of bytes from the start of the file to the position of the file pointer.

import io                   # Import io module containing file related extras

# Creating/truncating + writing binary file, and misc. file methods
fname = 'binfile.txt'
f = open(fname, 'wb')       # Creates/truncates and opens file in binary mode for writing
                            # from position 0
type(f)                     # Returns <class '_io.BufferedWriter'>
isinstance(f, io.BufferedWriter)# Returns True
isinstance(f, io.BufferedIOBase)# Returns True (superclass of all binary files)
isinstance(f, io.IOBase)        # Returns True (superclass of both text and binary files)
f.tell()                    # Returns 0 (position of file pointer in bytes)
x = 10
f.write(b'x = %d' % x)      # Writes 'x = 10' to file (no newline) and returns 6 (number of
                            # bytes written - always equal to size of argument)
f.write(b' (decimal)\n')    # Writes ' (decimal)' + newline and returns 11 (bytes written);
                            # whole line: 'x = 10 (decimal)'
a1 = [b'hi\n', b'ho\n']     # List of strings incl. newlines
f.writelines(a1)            # Writes 'hi\n' + 'ho\n' to file
f.tell()                    # Returns 23 (position of file pointer in bytes)
f.close()                   # Closes file
                            # File now contains b'x = 10 (decimal)\nhi\nho\n'

# Exclusively creating binary file (only if it doesn't already exist)
f = open(fname, 'xb')       # Raises FileExistsError exception because file already exists;
                            # same as mode 'wb' if file doesn't exist
                            # File still contains b'x = 10 (decimal)\nhi\nho\n'

# Reading binary file, and misc. file methods
f = open(fname, 'rb')       # Opens existing file in binary mode for reading from pos 0
type(f)                     # Returns <class '_io.BufferedReader'>
isinstance(f, io.BufferedReader)# Returns True
isinstance(f, io.BufferedIOBase)# Returns True (superclass of all binary files)
f.tell()                    # Returns 0 (position of file pointer in bytes)
b = f.read()                # Reads entire file as bytes object
f.tell()                    # Returns 23 (position of file pointer in bytes)
f.seek(-10, io.SEEK_END)    # Moves file pointer 10 bytes back from end of file and returns
                            # 13 (new position of file pointer in bytes)
f.tell()                    # Returns 13 (position of file pointer in bytes)
f.seek(-10, io.SEEK_CUR)    # Moves file pointer 10 bytes back from current position and
                            # returns 3 (position of file pointer in bytes)
f.seek(10)                  # Moves file pointer 10 bytes forward from start of file and
                            # returns 10 (position of file pointer in bytes)
f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
b = f.readline()            # Reads next line from file as bytes object incl. newline;
                            # returns empty bytes object if no more lines
f.tell()                    # Returns 17 (position of file pointer in bytes)
a = f.readlines()           # Reads all remaining lines from file as list of bytes objects
                            # incl. newlines
f.tell()                    # Returns 23 (position of file pointer in bytes)
f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
b = next(f)                 # Same as f.readline() but raises StopIteration at end of file
                            # (files are iterators with additional control via f.seek())
for b in f: print(b.decode(), end='')   # Iterates through remaining lines in file and
                                        # prints each one (after decoding to str)
f.close()                   # Closes file
                            # File still contains b'x = 10 (decimal)\nhi\nho\n'

# 'With' statement (good practice)
with open(fname, 'rb') as f:# 'with' ensures that file is closed when the 'with' suite of
    b = f.read()            # statements ends or raises an exception
                            # File still contains b'x = 10 (decimal)\nhi\nho\n'

# Appending to binary file (creating it if needed)
f = open(fname, 'ab')       # (Creates and) opens file in binary mode for appending
                            # (writing at end)
type(f)                     # Returns <class '_io.BufferedWriter'>
isinstance(f, io.BufferedWriter)# Returns True
isinstance(f, io.BufferedIOBase)# Returns True (superclass of all binary files)
f.tell()                    # Returns 23 (position of file pointer; irrelevant for mode 'a')
f.write(b'hum\n')           # Appends 'hum\n' to end of file and returns 4 (bytes written)
f.tell()                    # Returns 27 (position of file pointer in bytes)
f.close()                   # Closes file
                            # File now contains b'x = 10 (decimal)\nhi\nho\nhum\n'

# Creating/truncating + writing & reading binary file
f = open(fname, 'w+b')      # Creates/truncates and opens file in binary mode for writing
                            # and reading
type(f)                     # Returns <class '_io.BufferedRandom'>
isinstance(f, io.BufferedRandom)# Returns True
isinstance(f, io.BufferedIOBase)# Returns True (superclass of all binary files)
b = f.read()                # Reads entire file as bytes object: b'' because file was
                            # truncated
f.write(b'hi\n')            # Writes 'hi\n' to file and returns 3 (bytes written)
f.tell()                    # Returns 3 (position of file pointer in bytes)
f.close()                   # Closes file
                            # File now contains b'hi\n'

# Reading & writing binary file
f = open(fname, 'r+b')      # Opens existing file in binary mode for reading and writing
                            # (no truncating) from start of file
type(f)                     # Returns <class '_io.BufferedRandom'>
isinstance(f, io.BufferedRandom)# Returns True
isinstance(f, io.BufferedIOBase)# Returns True (superclass of all binary files)
b = f.read(1)               # Reads 1 byte from file as bytes object: b'h'
f.tell()                    # Returns 1 (position of file pointer in bytes)
f.write(b'o')               # Writes 'o' to file - overwriting previous 'i' in 'hi\n' - and
                            # returns 1 (bytes written)
f.tell()                    # Returns 2 (position of file pointer in bytes)
f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
b = f.read()                # Reads entire file as bytes object: b'ho\n'
f.close()                   # Closes file
                            # File now contains b'ho\n'

# Appending to & reading binary file (creating it if needed)
f = open(fname, 'a+b')      # (Creates and) opens file in binary mode for appending and
                            # reading from end of file
type(f)                     # Returns <class '_io.BufferedRandom'>
isinstance(f, io.BufferedRandom)# Returns True
isinstance(f, io.BufferedIOBase)# Returns True (superclass of all binary files)
f.tell()                    # Returns 3 (position of file pointer in bytes)
f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
b = f.read()                # Reads entire file as bytes object: b'ho\n'
f.tell()                    # Returns 3 (position of file pointer in bytes)
f.seek(0)                   # Moves file pointer back to start of file (doesn't affect
                            # append operation)
f.write(b'hum\n')           # Appends 'hum\n' to end of file and returns 4 (bytes written);
                            # file is now 'ho\nhum\n'
f.tell()                    # Should return 7 but returns wrong value after append when
                            # file pointer was not at end of file before append (bug?);
                            # file pointer is actually at position 7, though
f.read()                    # Reads and returns remainder of file: b'' because file pointer
                            # was at end of file
f.tell()                    # Returns 7 (position of file pointer in bytes)
f.close()                   # Closes file
                            # File now contains b'ho\nhum\n'

Expressions

Operators

All operators are listed below (highlighted) in precedence groups from highest to lowest.
Within each group, x op y op z == (x op y) op z, unless otherwise noted.
###########################################################################################
(2 + 3)                 # Returns 5
(2, 3, 4)               # Returns tuple (2, 3, 4)
[2, 3, 4]               # Returns list [2, 3, 4]
{2: 3, 4: 5}            # Returns dict {2: 3, 4: 5}
{2, 3, 4}               # Returns set {2, 3, 4}
###########################################################################################
x[2]                    # Returns item/value with index/key 2 from tuple/list/dict/string x
                        # (or other object with __getitem__() method)
x[1:6:2]                # Returns tuple/list/... by extracting slice (indices 1,3,5) from x
x[2, 6:0:-2             # Returns item(s) from x selected by expression list of indices/
    slice(6,0,-2), ...] # slices/Ellipsis; built-in types other than memoryview allow only
                        # 1 item between [] (not Ellipsis); numpy module allows any
f(2, 3, 4)              # Returns result of calling function f with given arguments
x.y                     # Returns member y of object x
###########################################################################################
await asyncio.sleep(1,9)# Suspends current coroutine, runs sleep coroutine (for 1 second),
                        # resumes this coroutine, and returns 9 (return value from sleep)
###########################################################################################
2**3                    # Returns 8 (exponentiation); 4**3**2 == 4**(3**2) == 262144;
                        # -2**-2 == -(2**(-2)) == -0.25
###########################################################################################
+1                      # Returns 1
-1                      # Returns -1
~1                      # Returns -2 (bitwise NOT)
###########################################################################################
2 * 3                   # Returns 6
'hi' * 3                # Returns 'hihihi' (sequence repetition)
x @ y                   # Matrix multiplication (supported by numpy module, not by built-in
                               # types)
-5 / 2                  # Returns -2.5 (always a float)
-5.0 // 2               # Returns -3.0 (floor div); for int: -5 // 2 == -3
-5 % 3                  # Returns 1 (modulo); x == floor(x/y)*y + x%y
'%0*d %X' % (5, 3, 12)  # Returns '00003 C' (string formatting)
###########################################################################################
2 + 3                   # Returns 5
[1,2] + [3,4]           # Returns [1, 2, 3, 4] (sequence concatenation)
2 - 3                   # Returns -1
{1,2,3} - {3,4}         # Returns {1,2} (set difference)
###########################################################################################
6 << 2                  # Returns 24 (left shift); x << y == x * 2**y; y >= 0
-6 >> 2                 # Returns -2 (right shift); x >> y == x / 2**y; y >= 0
###########################################################################################
6 & 3                   # Returns 2 (bitwise AND)
{1,2,3} & {3,4}         # Returns {3} (set intersection)
###########################################################################################
6 ^ 3                   # Returns 5 (bitwise XOR)
{1,2,3} ^ {3,4}         # Returns {1,2,4} (set symmetric difference)
###########################################################################################
6 | 3                   # Returns 7 (bitwise OR)
{1,2,3} | {3,4}         # Returns {1,2,3,4} (set union)
###########################################################################################
# Comparisons and tests (chainable, i.e. x < y < z means x < y and y < z (but y is
# evaluated only once)):
5 in (3, 5, 8)          # Returns True (membership test)
'a' not in 'hi'         # Returns True (non-membership test)
[] is []                # Returns False (identity test); these lists are not same object
                        # (but immutable objects might be identical, e.g. maybe 5 is 5)
{} is not {}            # Returns True (non-identity test)
2 < 3                   # Returns True
'ab' <= 'abc'           # Returns True (lexicographic Unicode comparison)
[2,3] > [2]             # Returns True (lexicographic comparison of corresponding items)
(3,) >= (2,5)           # Returns True (lexicographic comparison of corresponding items)
{2,3} > {3}             # Returns True (proper superset)
2 != '2'                # Returns True (different types generally compare unequal)
2 == 2.0                # Returns True (comparison works across different numeric types)
###########################################################################################
not 2                   # Returns False (boolean NOT)
###########################################################################################
2 and 3                 # Returns 3 (boolean AND, returns 1st arg if False, else 2nd arg;
                        # 2nd arg is not evaluated if 1st arg is returned)
###########################################################################################
0 or 'a'                # Returns 'a' (boolean OR, returns 1st arg if True, else 2nd arg;
                        # 2nd arg is not evaluated if 1st arg is returned)
###########################################################################################
2 if True else 3        # Returns 2 (conditional expression);
                        # 3rd arg is not evaluated if 1st arg is returned, and vice versa;
                        # (x if a else y if b else z) == (x if a else (y if b else z))
###########################################################################################
lambda x,y: x + y       # Returns anonymous function which will return sum of its 2 args
                        # (lambda expression)
###########################################################################################
#=========================================================================================#
# The "operators" below this point are not officially operators, but are included here to #
# show their effective relative precedence in the special contexts where they are valid   #
#=========================================================================================#
###########################################################################################
f(x=2)                  # Passes named argument to function f, i.e. binds f's formal param
                        # x to object 2 regardless of x's position in f's parameter list
f(*[4, 'hi'])           # Passes all items of given iterable as args to function f
                        # (same as f(4, 'hi'))
x,*y,z = range(5)       # Unpacks iterable (same as x,y,z = 0,[1,2,3],4)
f(**{'x': 2, 'y':3})    # Passes key/value pairs of given dictionary as named args to f
                        # (same as f(x=2, y=3))
###########################################################################################
2, 3                    # Returns tuple (2, 3) or expression list (see enclosing operators
                        # above and multiple assignments below for uses)
###########################################################################################
yield 2                 # Returns 2 to caller of next() or send() on generator produced by
                        # function containing this yield, suspends generator until next
                        # call to next()/send(), then returns None or send's argument as
                        # return value of yield expression
yield from range(5)     # Same as yield but takes next item from range(5) on each pass
###########################################################################################
# Normal assignments (chainable, i.e. x = y = z means x = z, then y = z (but z is
# evaluated only once); note the counterintuitive chaining order!):
x = 2                   # Binds name x to object 2
o[0] = 2                # Sets item 0 of mutable object o to object 2
                        # (by calling o.__setitem__(0, 2))
o.x = 2                 # Sets attribute x of mutable object o to object 2
                        # (by calling o.__setattr__('x', 2))
x, o[0], o.x = 2, 2, 2  # Multiple assignments using expression lists
# Augmented assignments (not chainable; supports same targets as above except expression
# lists):
x += 2                  # Same as x = x + 2, but x is evaluated only once and updated in
                        # place if possible
x -= 2                  # x = x - 2 (but see x += 2)
x *= 2                  # x = x * 2 (but see x += 2)
x @= y                  # x = x @ y (not supported by built-in types)
x /= 2                  # x = x / 2 (but see x += 2)
x //= 2                 # x = x // 2 (but see x += 2)
x %= 2                  # x = x % 2 (but see x += 2)
x **= 2                 # x = x ** 2 (but see x += 2)
x >>= 2                 # x = x >> 2 (but see x += 2)
x <<= 2                 # x = x << 2 (but see x += 2)
x &= 2                  # x = x & 2 (but see x += 2)
x ^= 2                  # x = x ^ 2 (but see x += 2)
x |= 2                  # x = x | 2 (but see x += 2)
###########################################################################################

String Operations

'hello' + ' there\n'    # Returns 'hello there\n' ('\n' is a single newline)
'-' * 5                 # Returns '-----'
ord('A')                # Returns 65
chr(65)                 # Returns 'A'
ord('\u0E01')           # Returns 3585
chr(3585)               # Returns '\u0E01' (1 character)
ord('\U0001F60E')       # Returns 128526
chr(128526)             # Returns '\U0001F60E' (1 character)

String Formatting

There are several ways in which special codes embedded in a string can be replaced at run-time with objects converted to strings. The various methods are listed below in order of increasing flexibility (and decreasing simplicity).
# Misc initializations for use below
nbr, astr = 1, 'thing'
alist = [nbr, astr]
adict = {'nbr':nbr, 'astr':astr}
class Aclass: nbr = nbr; astr = astr

anobj = Aclass()

# Template class formatting; simple approach similar to Unix shell variables
from string import Template
Template('$n $x or ${x}y $$').substitute(x=astr, n=nbr)     # Returns '1 thing or thingy $'

# Old C printf-style formatting; many formatting options
'%(n)03d %(x).4s %(x)sy %%' % {'x':astr, 'n':nbr}           # Returns '001 thin thingy %'
'%03d %.4s %sy' % (nbr, astr, astr)                         # Returns '001 thin thingy'
'%0*d %.*s %sy' % (3, nbr, 4, astr, astr)                   # Returns '001 thin thingy'
'"%-6s" "%6s"' % ('left', 'right')                          # Returns '"left  " " right"'
'%4.1f %.0e %c' % (9, 500, ord('A'))                        # Returns ' 9.0 5e+02 A'
'%#x 0x%02X %#o' % (10, 10, 10)                             # Returns '0xa 0x0A 0o12'

# New str.format() formatting; more formatting and object access options than printf-style
'{0:03d} {x:.4} {x}y {{'.format(nbr, x=astr)                # Returns '001 thin thingy {'
'{0:{1}{2}d} {x:.{n}} {x}y'.format(nbr, 0, 3, x=astr, n=4)  # Returns '001 thin thingy'
'{:03d} {:.4} {}y'.format(nbr, astr, astr)                  # Returns '001 thin thingy'
'{0[0]:03d} {0[1]:.4} {0[1]}y'.format(alist)                # Returns '001 thin thingy'
'{0[nbr]:03d} {0[astr]:.4} {0[astr]}y'.format(adict)        # Returns '001 thin thingy'
'{0.nbr:03d} {0.astr:.4} {0.astr}y'.format(anobj)           # Returns '001 thin thingy'
'{:#<6} {:#^6} {:#>6}'.format('left', 'mid', 'right')       # Returns 'left## #mid## #right'
'{:4.1f} {:.0e} {:c}'.format(9, 500, ord('A'))              # Returns ' 9.0 5e+02 A'
'{:#x} 0x{:02X} {:#o} {:#b}'.format(10, 10, 10, 7)          # Returns '0xa 0x0A 0o12 0b111'
'{:,.2f} {:06_d}'.format(8e3, 1234)                         # Returns '8,000.00 01_234'

# Even newer f-strings (formatted string literals, added in Python 3.6); same formatting
# options as str.format() but arbitrary expressions can be specified within the format
# string; however, unlike the other methods above, f-strings cannot be stored for later
# formatting - they are immediately evaluated into string objects
f'{nbr:03d} {astr:.4} {astr+("y" if nbr==1 else "ies")} {{' # Returns '001 thin thingy {'
f'{nbr:{nbr-1}{3*nbr}{"abcd"[3]}} {astr:.{2+2}} {astr+"y"}' # Returns '001 thin thingy'
f'{alist[0]:03d} {alist[1]:.4} {alist[1]}y'                 # Returns '001 thin thingy'
f'{adict["nbr"]:03d} {adict["astr"]:.4} {adict["astr"]}y'   # Returns '001 thin thingy'
f'{anobj.nbr:03d} {anobj.astr:.4} {anobj.astr}y'            # Returns '001 thin thingy'
f'{"left":#<6} {"mid":#^6} {"right":#>6}'                   # Returns 'left## #mid## #right'
f'{9:4.1f} {500:.0e} {ord("A"):c}'                          # Returns ' 9.0 5e+02 A'
f'{10:#x} 0x{10:02X} {10:#o} {7:#b}'                        # Returns '0xa 0x0A 0o12 0b111'
f'{8e3:,.2f} {1234:06_d}'                                   # Returns '8,000.00 01_234'

Conditional Expressions

r = x if a else y       # Assigns x to r if a is True (y is not evaluated),
                        # otherwise assigns y to r (x is not evaluated)
r = x if a \
    else y if b \
    else z              # (Note: backslashes used to break single line)

Regular Expressions

Compiled regular expression objects are highlighted below for clarity, as many module functions (re.xxx()) have compiled object method equivalents (myobj.xxx()), but do not support quite the same parameters (module functions support flags; compiled object methods support start/end indexes).
import re                   # Imports regular expression module

# Compile and match
rs1 = r'(\w)(.*?)([0-5](Z)?)'   # Assigns a (raw) string containing a regular expression
rc1 = re.compile(rs1)       # Compiles regular expr for faster repeated execution
s1 = 'abc950'               # Some string to search for matches
m1 = re.match(rs1, s1)      # Finds a match at start of string s1, and returns
                            # a match object - or None if no match was found
m1 = rc1.match(s1)          # Same as above, but uses compiled regular expression object
if m1:                      # If a match was found, then...
    print(m1.group())       # Prints 'abc95' - the part of s1 matched by rs1
    print(m1.group(1))      # Prints 'a' - captured by 1st '()' in rs1
    print(m1.group(3, 2))   # Prints "('5', 'bc9')" - from 3rd & 2nd '()' in rs1
    print(m1.groups())      # Prints "('a', 'bc9', '5', None)" - from all '()' in rs1
                            # Note: non-matching '()' returns None
    print(m1.start())       # Prints 0 - start index of match in s1
    print(m1.end())         # Prints 5 - end index + 1 of match in s1
    print(m1.span())        # Prints '(0, 5)' - start and end of match
    print(m1.start(2))      # Prints 1 - start index of 2nd '()' capture in s1
    print(m1.end(2))        # Prints 4 - end index + 1 of 2nd '()' capture in s1
    print(m1.span(2))       # Prints '(1, 4)' - start and end of 2nd '()'

# Fullmatch
m1 = rc1.fullmatch(s1)      # Like rc1.match() but finds a match to whole string s1
print(m1.group())           # Prints 'abc950' - the part of s1 matched by rs1
print(m1.groups())          # Prints "('a', 'bc95', '0', None)" - from all '()' in rs1

# Backreferences
m1 = re.match(r'(\w+)\1', 'hihi')   # \1 matches same as 1st '()' (can't use \g<1> here)
print(m1.groups())                  # Prints "('hi',)"

# Start/end index parameters
# (WARNING: ONLY compiled object methods (e.g. rc1.match()) support these!
# If used with module functions (e.g. re.match()), they may be interpreted
# as flags and you may not get an error - just strange behavior!)
m1 = rc1.match(s1, 2)       # Finds a match at start of string s1[2:]
if m1:                      # If a match was found, then...
    print(m1.groups())      # Prints "('c', '9', '5', None)" - from all '()' in rs1
print(rc1.match(s1, 1, 4))  # Prints 'None' because rs1 does not match s1[1:4] ('bc9')

# Search
s2 = '.20 391Z'                 # A new string to search for matches
m2 = rc1.search(s2)             # Finds first match in string s2
if m2:
    print(m2.groups())          # Prints "('2', '', '0', None)" - from all '()' in rs1
m2 = rc1.search(s2, m2.end())   # Finds first match in string s2 starting from previous end
if m2:
    print(m2.groups())          # Prints "('3', '9', '1Z', 'Z')" - from all '()' in rs1

# Finditer
ri1 = rc1.finditer(s2)          # Returns an iterator
type(ri1)                       # Returns <class 'callable_iterator'>
print(next(ri1).groups())       # Prints "('2', '', '0', None)"
print(next(ri1).groups())       # Prints "('3', '9', '1Z', 'Z')"

# Findall
print(rc1.findall(s2))          # Prints "[('2', '', '0', ''), ('3', '9', '1Z', 'Z')]"
                                # Note: non-matching '()' returns '' (not None)
rs3 = r'\d\d'                   # String containing regular expression with no '()'
s3 = ' 12.345-6789a'            # A new string to search for matches
print(re.findall(rs3, s3))      # Prints "['12', '34', '67', '89']"

# Split
print(re.split(rs3, s3))        # Prints "[' ', '.', '5-', '', 'a']"

# Sub and subn (substitution)
print(re.sub(rs3, 'xy', s3))        # Prints ' xy.xy5-xyxya'
print(re.subn(rs3, 'xy', s3))       # Prints "(' xy.xy5-xyxya', 4)" (4 substitutions)
print(rc1.sub(r'_\1_\g<1>4_', s1))  # Prints '_a_a4_0' (\1 = \g<1> = 1st captured group)
print(rc1.sub(r'(\g<0>)', s1))      # Prints '(abc95)0' (\g<0> = whole match)

# Flags
# (WARNING: ONLY module functions (e.g. re.match()) support these!
# If used with compiled object methods (e.g. rc1.match()), they may be interpreted
# as indexes and you may not get an error - just strange behavior!)
rs4 = r'^hi.\w+$'
rc4 = re.compile(rs4,
        re.I|re.S|re.M)     # Flags: re.I: ignore case, re.S: '.' matches also newline,
                            # re.M: '^' and '$' match start/end of each line within string
s4 = 'Hi\nHo\nHi\nHUM'
print(rc4.findall(s4))      # Prints "['Hi\nHo', 'Hi\nHUM']"

Comprehensions

For each iteration of the inner (last) 'for' loop, the expression highlighted below is evaluated to produce another item in the resulting list - unless an 'if' condition is false, in which case no item is produced for that iteration.
# List comprehension
[x * y for x in [1, -1] for y in range(4) if y > x] # Returns list [2, 3, 0, -1, -2, -3]

# Dictionary comprehension
{x: y for x, y in ((0, 3), (1, 4), (2, 3))}         # Returns dict {0: 3, 1: 4, 2: 3}

# Set comprehension
{x**2 for x in range(4)}                            # Returns set {0, 1, 4, 9}

# Tuple comprehension - has no dedicated syntax,
# but a generator expression can be passed to tuple()
tuple(chr(x) for x in range(65, 67))                # Returns tuple ('A', 'B')

Generator Expressions

g = (x for x in 'hello' if x < 'm')     # Assigns a generator object prepared to produce
                                        # the sequence 'h', 'e', 'l', 'l';
                                        # generator objects are also iterators
type(g)                                 # Returns <class 'generator'>
next(g)                                 # Returns 'h', i.e. next (first) item
next(g)                                 # Returns 'e', i.e. next item
list(g)                                 # Returns ['l', 'l'], i.e. all remaining items;
                                        # g is useless now and can't be restarted
list(g)                                 # Returns []; no more items
next(g)                                 # Raises StopIteration exception; no more items

g = (x**2 for x in range(5))            # Assigns a new generator object
for i in g:                             # Assigns each generated item to i in turn
    if i == 9:                          # If item is 9, then...
        try:
            i = next(g)                 # ... skip to next item if any
        except StopIteration:
            i = 'end'                   # If no more, set i to 'end' (will not happen)
    print(i)                            # Prints '0', '1', '4', '16', one by one
See also generator functions.

Lambda Expressions

f = lambda x, y: x + y  # Assigns a lambda expression (anonymous function) that takes 2
                        # arguments and returns the sum of these; this is basically the
                        # same as 'def f(x, y): return x + y', except a lambda doesn't
                        # need to be bound to a name, and is limited to one expression
type(f)                 # Returns <class 'function'>
f(3,5)                  # Calls lambda expression bound to name f; returns 8
map(lambda x: x**2, range(4))   # Applies lambda to range and returns iterator for sequence
                                # 0, 1, 4, 9
g = lambda x: lambda y: x + y   # Binds g to a function which returns a function
g(3)                            # Returns a function which adds 3 to stuff
g(3)(4)                         # Returns 7

Functions

Function Definitions and Calls

# Function definitions
def f1(x, y=0):         # Arguments may have default values (calculated only once when
                        # 'def' is executed, so beware if using mutable values, e.g. y=[])

    # Here's a docstring for this function:
    """This docstring is accessible via f1.__doc__
    """

    print(x, y)
    if x > y:
        return          # Exits function with return value None
    if x < y:
        return y, x     # Exits function with expression list as return value
                        # Return value is None if function ends without 'return'

def f2(x, *args, **keyargs): # special * and ** syntax explained below
    print(x, end=' ')   # Prints first argument (and a space, no newline)
    print(args, end=' ')# Prints a tuple of all remaining unnamed arguments
    print(keyargs)      # Prints a dict of all remaining named arguments

def f3(x):
    def g(y):           # Defines an inner function (function object) inside f3
        return x + y    # Function g uses object referenced by f3's local x, so keeps that
                        # object in existence after f3 returns
    return g            # Function f3 returns the created function object (in this case a
                        # 'closure' because it keeps data (x) in an outer scope (f3) alive
                        # even though that scope has ended when the function is later
                        # called)

type(f1)                # Returns <class 'function'> (functions are also objects)

# Function calls
f1(3)                   # Calls f1 which prints '3 0' and returns None
print(f1(3,5))          # Calls f1 which prints '3 5', then prints result '(5, 3)'
f1(y=5, x=3)            # Passes named arguments to f1 which prints '3 5'
a1 = [3, 5]
f1(a1, [4])             # Passes a1 and [4] to f1 which prints '[3, 5] [4]' and returns
                        # ([4], [3, 5]) because [3,5] is lexicographically smaller than [4]
f1(*a1)                 # Passes each item of a1 as an argument to f1 which prints '3 5'
                        # and returns (5, 3)
d = {'y':5, 'x':3}      # Creates a dictionary
f1(**d)                 # Passes values of d as named arguments to f1 which prints '3 5'
f1(*[3], **{'y':5})     # Passes items of list and values of dictionary as arguments
                        # to f1 which prints '3 5'
f2(3)                   # Prints '3 () {}'
f2(3, 4, 5, a=6)        # Prints "3 (4, 5) {'a': 6}"

add10 = f3(10)          # Calls f3 which returns new function that adds 10 to its argument
print(add10(9))         # Calls function add10 and prints return value '19'

f2 = f1                 # (Re-)binds name f2 to same function object as f1
f2(3)                   # Calls f2 (now same as f1) which prints '3 0' and returns None
Notes:

Generator Functions

# Using 'yield'
def f1(m):              # The yield statement in the body of this function causes it to
                        # return a generator object, which produces a new item whenever
                        # the yield statement is reached;
                        # generator objects are also iterators
    print('1st')        # Prints '1st' when first item is requested from generator (first
                        # call to next())
    end = 5 * m + 1
    for x in range(m, end, m):
        yield x                 # Returns x to caller of next() on generator object, and
                                # stops execution until next() is called again, whereafter
                                # execution continues after yield statement

# Using 'yield from'
def f2(m):              # Identical to f1 above, but uses 'yield from' instead of 'yield'
    print('1st')
    end = 5 * m + 1
    yield from range(m, end, m) # Returns items one by one from iterable to caller of
                                # next(), stopping execution each time

g = f1(3)               # Assigns the generator object returned from function f1
type(g)                 # Returns <class 'generator'>
next(g)                 # Prints '1st' and returns 3, i.e. next (first) item of generator
next(g)                 # Returns 6, i.e. next item
list(g)                 # Returns [9, 12, 15], i.e. all remaining items;
                        # g is useless now and can't be restarted (but f1 can be called
                        # again to get a new generator object)
list(g)                 # Returns []; no more items
next(g)                 # Raises StopIteration exception; no more items

g = f2(3)               # Assigns the generator object returned from function f2
next(g)                 # Prints '1st' and returns 3, i.e. next (first) item of generator

# Using 'send' and return value from 'yield'
def f3(m):              # Identical to f1 above, but allows values to be sent into the
                        # generator at any time (and returned from yield) to modify its
                        # behavior while iterating over it
    print('1st')
    end = 5 * m + 1
    x = m
    while x < end:
        y = yield x     # Returns x to caller of next() or send(), stops execution until
                        # next() or send() is called again, then returns None (for next())
                        # or argument to send(), and resumes execution here
        x = x + m if y is None else y   # Update next item or use value provided by send()

g = f3(3)               # Assigns the generator object returned from function f3
g.send(4)               # Raises TypeError exception; can't send non-None value to
                        # just-started generator (no yield to receive it)
next(g)                 # Prints '1st' and returns 3, i.e. next (first) item of generator
next(g)                 # Returns 6, i.e. next item
g.send(4)               # Sends 4 into generator, which sets next item to 4 and returns 4
next(g)                 # Returns 7, i.e. next item
list(g)                 # Returns [10, 13], i.e. all remaining items;
See also generator expressions.

Decorators

from functools import wraps # Imports the 'wraps' decorator factory which copies attributes
                            # (__name__, __doc__, __module__) from the wrapped function to
                            # the wrapper function to make the wrapping more transparent

def deco1(f):               # Defines a function deco1 which takes another function and
                            # returns a modified version of it; any function that takes a
                            # function or class as its sole argument can be used as a
                            # decorator regardless of what it returns (see how to use deco1
                            # below)
    @wraps(f)               # Applies the 'wraps' decorator factory to f_wrapper1
    def f_wrapper1(*args):                      # Defines the wrapper function which
        return 2 * f(args[0] * 10, *args[1:])   # calls the wrapped/decorated function
    return f_wrapper1       # Returns the wrapper function which will later be called
                            # instead of the wrapped/decorated function

def deco_factory(inscale, outscale):    # Defines a function deco_factory which uses its
                            # arguments to produce a function that can be used as a
                            # decorator; any function that does this can be used as a
                            # decorator factory (see how to use deco_factory below)
    def deco2(f):           # Defines a function deco2 similar to deco1 above, but this
                            # one is customized based on the arguments to deco_factory
        @wraps(f)
        def f_wrapper2(*args):
            return outscale * f(args[0] * inscale, *args[1:])
        return f_wrapper2
    return deco2            # Returns the deco2 function

# The following line decorates the myadd1 function with the deco1 function;
# same as doing myadd1 = deco1(myadd1) after defining myadd1,
# so the name myadd1 will end up referring to f_wrapper1 which, when called,
# will call the original myadd1 defined below
@deco1
def myadd1(x, y):
    return x + y

# The following line calls deco_factory and uses the returned function (deco2)
# as a decorator for the myadd2 function;
# same as doing myadd2 = deco_factory(100, 10)(myadd2) after defining myadd2,
# so the name myadd2 will end up referring to f_wrapper2 which, when called,
# will call the original myadd2 defined below
@deco_factory(100, 10)
def myadd2(x, y):
    return x + y

# Any number of decorators can be applied to the same function; they are applied
# in reverse order;
# the following is the same as doing myadd3 = deco_factory(100, 10)(deco1(myadd3))
# after defining myadd3
@deco_factory(100, 10)
@deco1
def myadd3(x, y):
    return x + y

myadd1(3, 4)                # Calls f_wrapper1 which calls the original myadd1 and returns
                            # 68 (the result of 2 * (3 * 10 + 4)); 
myadd2(3, 4)                # Calls f_wrapper2 which calls the original myadd2 and returns
                            # 3040 (the result of 10 * (3 * 100 + 4))
myadd3(3, 4)                # Calls f_wrapper2 which calls f_wrapper1 which calls the
                            # original myadd3; returns 60080 (10 * (2 * (3 * 100 * 10 + 4))
Examples of standard functions often used as decorators are: classmethod(), staticmethod(), property(), functools.total_ordering(). Most decorators take a function and return a function, but property() takes a function and returns a property object, and functools.total_ordering() takes a class and returns a class. Examples of standard functions often used as decorator factories are: functools.wraps().

Built-in Functions

__build_class__()       # TBD
__import__()            # TBD
abs(-3+4j)              # Returns 5.0
all([True,4,'0'])       # Returns True (Are all items True after conversion to bool? Yes)
any([False,0,''])       # Returns False (Are any items True after conversion to bool? No)
ascii()                 # Same as repr() but uses escapes for non-ascii characters
bin(12)                 # Returns '0b1100' (binary representation of 12)
bool()                  # Returns a new bool; see basic types
breakpoint()            # TBD
bytearray()             # Returns a new bytearray; see sequence types
bytes()                 # Returns a new bytes object; see sequence types
callable(f)             # Returns True if f appears to be callable (i.e. a function, class,
                        # or other object with a __call__ method); note that some objects
                        # may appear to be callable but will fail when called
chr(65)                 # Returns 'A' (character with Unicode code 65)
classmethod(f)          # Returns a class method for function f (usually used as decorator
                        # @classmethod, see classes)
compile('x=3\nprint(x)', '', 'exec') # Returns a code object which can be executed by exec()
compile('2+5', '', 'eval')          # Returns a code object which can be evaluated by eval()
complex()               # Returns a new complex; see basic types
delattr(o, 'x')         # Deletes object o's attribute x; same as del o.x
dict()                  # Returns a new dict; see other container types
dir(o)                  # Returns a list of o's attributes, or a list of names in the
                        # current local scope if no argument is given
divmod(-5, 3)           # Returns (-2, 1); same as (-5 // 3, -5 % 3)
enumerate(x)            # Returns a new enumerate; see iterator types
eval('2+3')             # Returns 5; evaluates any Python expression (or compile() object)
exec('if True:\n print("hi")') # Prints 'hi'; executes code in a string or compile() object
filter(f, 'hello')      # Returns iterator for sequence 'h','l','l','o' assuming f is:
                        # def f(x): return x > 'g'
filter(None, [3,0,''])  # Returns iterator for sequence 3 (all True items in list)
float()                 # Returns a new float; see basic types
format(4, '<03')        # Returns '400' (same as '{:<03}'.format(4), see string operations)
frozenset()             # Returns a new frozenset; see other container types
getattr(o, 'x')         # Returns the value of object o's attribute x; same as o.x
globals()               # Returns a dict representing the current global symbol table;
                        # globals()['x'] = 3 is equivalent to global x; x = 3
hasattr(o, 'x')         # Returns True if object o has attribute x
hash()                  # TBD
help(o)                 # Prints documentation on object o - or topic o if o is a string
hex(254)                # Returns '0xfe' (hexadecimal respresentation of 254)
id(o)                   # Returns the unique id (integer) of object o
input('Input: ')        # Prints 'Input: ', reads a line from stdin, and returns the line
                        # (excluding the final newline)
int()                   # Returns a new int; see basic types
isinstance(o, c)        # Returns True if o is an instance of class c or of a subclass of c
                        # - or of any item in c if c is a tuple of classes
issubclass(c1, c2)      # Returns True if c1 is a subclass of, or identical to, c2
                        # - or any item in c2 if c2 is a tuple of classes
iter(o)                 # Returns an iterator for iterable o; see iterator types
len([6,7,8])            # Returns 3 (number of items in list/tuple/set/...)
list()                  # Returns a new list; see sequence types
locals()                # Returns a dict representing the current local symbol table (this
                        # dict should not be modified)
map(f, [5,2,6], (3,4))  # Returns iterator for sequence '53','24' assuming f is:
                        # def f(x,y): return str(x)+str(y);
                        # the number of sequences must match the number of arguments to f
max(3,5,2)              # Returns 5
max([3,5,2])            # Returns 5
memoryview()            # Returns a new memoryview; see sequence types
min(3,5,2)              # Returns 2
min([3,5,2])            # Returns 2
next(i)                 # Returns next item from iterator i; see iterator types
object()                # Returns a new object; see basic types
oct(8)                  # Returns '0o10' (octal representation of 8)
open('file', 'w')       # Opens 'file' for writing and returns a file object; see files
ord('A')                # Returns 65 (Unicode code of character 'A')
pow(3.0, 2.0)           # Returns 9.0; same as 3.0**2.0;
pow(3, 2, 4)            # Returns 1; same as 3**2 % 4 but more efficient; all args must be
                        # integers
property()              # Returns a new property
range()                 # Returns a new range; see sequence types
repr(o)                 # Returns a formal string representation of o, preferably one that
                        # can be executed by eval() to recreate o
reversed([1,2,3])       # Returns an iterator for the sequence 3,2,1
reversed('hello')       # Returns an iterator for the sequence 'o','l','l','e','h'
round(25.16)            # Returns 25 (25.16 rounded to 0 digits after the point)
round(25.16, 0)         # Returns 25.0 (25.16 rounded to 0 digits after the point)
round(25.16, 1)         # Returns 25.2 (25.16 rounded to 1 digit after the point)
round(25.16, -1)        # Returns 30.0 (25.16 rounded to 1 digit before the point)
set()                   # Returns a new set; see other container types
setattr(o, 'x', 3)      # Sets object o's attribute x to 3; same as o.x = 3
slice()                 # Returns a new slice; see basic types
sorted([10,-1,9])       # Returns [-1, 9, 10] (takes the same additional args as o.sort())
staticmethod(f)         # Returns a static method for function f (usually used as decorator
                        # @staticmethod, see classes)
str()                   # Returns a new str; see sequence types
sum([1,2,3,4])          # Returns 10 (the sum of all items)
sum([2,3,4], 1)         # Returns 10 (the sum of all items and the 2nd argument)
super(C, self).m()      # Calls method m of class C's parent/sibling class (the next class
                        # after C in the method resolution order of self's class) and
                        # passes object self to that method; see class inheritance;
                        # arguments C and self are optional inside class definitions
tuple()                 # Returns a new tuple; see sequence types
type()                  # Returns a new type; see basic types
vars()                  # TBD
zip([5,2,6], (3,4))     # Returns an iterator for sequence (5, 3), (2, 4);
                        # any number of collections are supported;
                        # zip can also unzip, because if x is a list of same-length tuples,
                        # and y = list(zip(*x)), then x = list(zip(*y))

Classes

About Classes/Types and Objects

Types and classes are two terms for the same thing, and they are all instances/objects of class type and subclasses of (i.e. inherit from) class object. Even type and object are instances of type.

Other objects than classes will not be instances of type (their __class__ attribute will refer to some other class) and will not have a superclass tuple (they will not have the __bases__ attribute).

The UML diagram below illustrates the relationships between various types of objects ("int:type" means object int is an instance of class type, and arrows point from subclasses to their superclasses/bases).

Objects Classes Other Objects object:type type:type int:type Myclass:type Mysubclass:type 42:int x:Myclass y:Mysubclass o:object

Class Creation and Instantiation

# Class definitions
class Myclass:          # Defines a class (which inherits only from 'object')

    # Here's a docstring for this class:
    """This docstring is accessible via Myclass.__doc__
    or e.g. o1.__doc__ where o1 is an instance of Myclass.
    """

    n = 3               # Defines a class variable, shared by all instances of this class

    @staticmethod       # Decorator that defines a static method to be invoked on the class
    def setn(n):        # itself (or optionally on instances of the class)
        Myclass.n = n   # Updates the class variable

    @classmethod        # Decorator that defines a class method to be invoked on the class
    def setn2(cls, n):  # itself (or optionally on instances of the class)
        cls.n = n       # Updates the class variable

    def __init__(self, x):  # Defines the instance constructor; first arg is the instance,
                            # conventionally named 'self' (like 'this' in C++)
        self.x = x          # Creates an instance variable belonging to the given instance

    def add(self, y):       # Defines an instance method to be invoked on a given instance
        self.x += (y *      # Updates the previously created instance variable
            self.n)         # Class variables may be read (not written!) via 'self'
                            # (if written, a new instance variable is created hiding the
                            # class variable!)

    def __str__(self):      # Defines informal nicely printable string representation of
                            # an instance of this class
        return str(self.x)  # Returns instance variable converted to string

    def __repr__(self):     # Defines formal string representation of an instance of this
                            # class, preferably executable by eval() to recreate instance
        return 'Myclass(%d)' % self.x

    def __getitem__(self, item):        # Defines special method for getting indexed item
        print('get', item)
        t = item if isinstance(item, tuple) else (item,) # Make item a tuple if not already
        for i in t:                                      # Step through tuple
            if isinstance(i, slice):                     # Handle slice by expanding it to
                print(range(*i.indices(self.n)), end=' ')# list (self.n sets index limit)
            elif i == Ellipsis:                          # Handle Ellipsis object by just
                print('...', end=' ')                    # printing 3 dots
            else:
                print(i, end=' ')
        print()
        return self.x

    def __setitem__(self, key, val):    # Defines special method for setting indexed item
        print('set', key, val)

    def __add__(self, other):           # Defines special method overriding '+' operator
        return self.x + other

    def __radd__(self, other):          # Defines special method overriding '+' operator if
                                        # this object is 2nd arg and other.__add__() failed
        return self.x + other + self.n

type(Myclass)               # Returns <class 'type'>; same as Myclass.__class__
isinstance(Myclass, type)   # Returns True
issubclass(Myclass, object) # Returns True
Myclass.__name__            # Returns 'Myclass'
Myclass.__bases__           # Returns (<class 'object'>,) (tuple of base classes)
Myclass.mro()               # Returns [<class '__main__.Myclass'>, <class 'object'>]
                            # (method resolution order: order in which classes are searched
                            # for a method definition)
Myclass.n                   # Returns 3
type(Myclass.setn)          # Returns <class 'function'>
type(Myclass.setn2)         # Returns <class 'method'>
type(Myclass.add)           # Returns <class 'function'>

# Dynamically defined classes
type('Mydynclass', (Myclass,), {'n': 4})    # Creates and returns a class with __name__ ==
                        # 'Mydynclass' but not bound to any name in current namespace;
                        # this class inherits from Myclass and sets class variable n to 4;
                        # the class will be lost unless a reference to it is saved, e.g.
                        # Someclass = type('Mydynclass', ...)

# Instantiation
o1 = Myclass(10)        # Creates an object as an instance of class 'Myclass' and runs
                        # the __init__ constructor with parameter x = 10
type(o1)                # Returns <class '__main__.Myclass'>; same as o1.__class__
o2 = Myclass(20)        # Creates a second instance of the same class using x = 20
o1.x                    # Returns 10
o2.x                    # Returns 20
o1.n                    # Returns 3 (the value of class variable n)
str(o1)                 # Returns '10' (return value from o1.__str__())
repr(o1)                # Returns 'Myclass(10)' (return value from o1.__repr__())
dir(o1)                 # Returns list of all o1's attributes: [..., '__doc__', ...,
                        # '__init__', ..., 'add', 'n', 'setn', 'setn2', 'x']

o1[4]                   # Calls o1.__getitem__(4)
o1[::-1] = 2            # Calls o1.__setitem__(slice(None,None,-1),2); see slice
o1[2,:3,...]            # Calls o1.__getitem__((2,slice(None,3,None),Ellipsis))
                        # (note: this extended syntax is not supported by built-in types
                        # such as list and tuple)

o1 + 4                  # Calls o1.__add__(4) which returns 14
5 + o1                  # Calls o1.__radd__(5) (when 5 + o1 fails) which returns 18
o1.add(2)               # Passes 2 to the 'add' method of o1 which updates o1's x
o1.x                    # Returns 16 (2 * 3 was added to the previous value 10)
o2.x                    # Returns 20 (no change)

Myclass.setn(5)         # Changes the class variable n value to 5
Myclass.setn2(5)        # Same as above
Myclass.n = 5           # Same as above
o1.setn(5)              # Same as above (o1 is only used to access Myclass)
o1.setn2(5)             # Same as above (o1 is only used to access Myclass)
                        # (don't do o1.n = 5, it hides the class variable from o1)
o1.n                    # Returns 5
o2.n                    # Returns 5 (same class var n is accessed from any instance)

o2.add(-1)
o1.x                    # Returns 16
o2.x                    # Returns 15 (-1 * 5 was added to 20)

o1.s = 'hi'             # Creates a new instance variable on o1 only
Myclass.k = 100         # Creates a new class variable (visible in all existing and new
                        # instances)

Class Inheritance

class A(list):                          # Defines a class A which inherits from list (which
                                        # inherits from object)
    def __str__(self):                  # Overrides list's __str__ method in order to...
        return ('A:' +                  # ... prepend 'A:' to...
            super().__str__())          # ... whatever is returned from __str__() of the
                                        # next classes in the method resolution order (i.e.
                                        # the previous classes in the inheritance order);
                                        # the next class is list when self is an instance
                                        # of A, but B when self is an instance of C!

class B(list):                          # Defines a class B just like A, except...
    def __str__(self):
        return ('B:' +                  # ... prepend 'B:' to...
            super().__str__())          # ... whatever is returned from __str__() of the
                                        # next classes in the method resolution order; the
                                        # next class is list when self is an instance of
                                        # either B or C

class C(A, B):                          # Defines a class C which inherits primarily from A
                                        # and secondarily from B
    def __str__(self):                  # Overrides the __str__ method in order to...
        return ('C:' +                  # ... prepend 'C:' to...
            super().__str__())          # ... whatever is returned from __str__() of the
                                        # next classes in the method resolution order; the
                                        # next class is A when self is an instance of C

C.__bases__ # Returns (<class '__main__.A'>, <class '__main__.B'>)

# Method resolution order (MRO) for classes A, B, and C (see notes)
A.mro()     # Returns [<class '__main__.A'>, <class 'list'>, <class 'object'>]; this means
            # that A().__str__() will first look for an __str__ method in class A, then in
            # class list, then in class object, until a class is found which has the method
B.mro()     # Returns [<class '__main__.B'>, <class 'list'>, <class 'object'>]
C.mro()     # Returns [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>,
            # <class 'list'>, <class 'object'>]

a = A([0])  # Assigns an instance of class A initialized by calling a.__init__([0]) which
            # resolves to list.__init__(a,[0]) (list is 1st class with __init__ in A.mro())
            # which sets the initial value to [0]
b = B([1])  # Assigns an instance of class B initialized to [1] by list.__init__(b,[1])
c = C([2])  # Assigns an instance of class C initialized to [2] by list.__init__(c,[2])

print(a)    # Prints 'A:[0]', because print calls a.__str__()
            # which resolves to A.__str__(a) (A is a's class and has __str__)
            # which calls super(A, a).__str__()
            # which resolves to list.__str__(a) (list follows A in A.mro() and has __str__)
            # which returns '[0]' to A.__str__
            # which returns 'A:[0]' to print
print(b)    # Prints 'B:[1]', because print calls b.__str__()
            # which resolves to B.__str__(b) (B is b's class and has __str__)
            # which calls super(B, b).__str__()
            # which resolves to list.__str__(b) (list follows B in B.mro() and has __str__)
            # which returns '[1]' to B.__str__
            # which returns 'B:[1]' to print
print(c)    # Prints 'C:A:B:[2]', because print calls c.__str__()
            # which resolves to C.__str__(c) (C is c's class and has __str__)
            # which calls super(C, c).__str__()
            # which resolves to A.__str__(c) (A follows C in C.mro() and has __str__)
            # which calls super(A, c).__str__()
            # which resolves to B.__str__(c) (B follows A in C.mro() and has __str__)
            # which calls super(B, c).__str__()
            # which resolves to list.__str__(c) (list follows B in C.mro() and has __str__)
            # which returns '[2]' to B.__str__
            # which returns 'B:[2]' to A.__str__
            # which returns 'A:B:[2]' to C.__str__
            # which returns 'C:A:B:[2]' to print
Notes on method resolution order (MRO):

Property Attributes

The built-in function property(), which creates a property object, can be used as a decorator to define functions to be called whenever a certain class attribute is read, written, or deleted.
class C(object):
    def __init__(self, v):  # Defines the instance constructor
        self._x = float(v)  # Initializes an instance variable which is not supposed to be
                            # accessed directly from outside class C

    @property               # Creates a property attribute x whose __get__() method is
    def x(self):            # this function (function name becomes property name)
        return self._x

    @x.setter               # Sets the __set__() method of property x to
    def x(self, v):         # this function (use same name for function and property)
        self._x = float(v)

    @x.deleter              # Sets the __delete__() method of property x to
    def x(self):            # this function (use same name for function and property)
        del self._x

type(C.x)                   # Returns <class 'property'>
isinstance(C.x, property)   # Returns True

c = C(1)                    # Assigns a new instance of class C with c._x set to 1.0
c._x                        # Returns 1.0 (but we're not supposed to access _x directly)
c.x                         # Returns 1.0 (calls our getter C.x.__get__(c))
c.x = 2                     # Sets c._x to 2.0 (calls our setter C.x.__set__(c, 2))
c.x                         # Returns 2.0 (calls our getter C.x.__get__(c))
del c.x                     # Deletes c._x (calls our deleter C.x.__delete__(c))
c.x                         # Raises AttributeError exception because c._x doesn't exist
c.x = 3                     # Sets c._x to 3.0 (calls our setter C.x.__set__(c, 3))
c.x                         # Returns 3.0 (calls our getter C.x.__get__(c))

Modules

Module Creation and Usage

File mymodule.py:
# Here's a docstring for this module:
"""Any Python file can be imported as a module,
or run as a top level script.
"""

def f(x):
    return x * 2

if __name__ == '__main__':      # If this file is run as a script, its module name is
                                # '__main__',
    print(f(10))                # in which case call f and print the result '20'
else:                           # Otherwise, this file is imported as a module,
    print('Module:', __name__)  # so print 'Module: mymodule'
Some other Python file:
import mymodule         # Runs mymodule.py; puts all its names into namespace 'mymodule';
                        # the module prints 'Module: mymodule'
type(mymodule)          # Returns <class 'module'>
print(mymodule.f(8))    # Calls mymodule's function f, and prints result '16'
print(mymodule.__doc__) # Prints mymodule's docstring: 'Any Python file can be ...'
print(__doc__)          # Prints 'None' (this module has no docstring)
Some other Python file:
import mymodule as m    # Runs mymodule.py; puts all its names into namespace 'm';
                        # the module prints 'Module: mymodule'
print(m.f(8))           # Calls mymodule's function f, and prints result '16'
Some other Python file:
from mymodule import f  # Runs mymodule.py; puts its name f into our namespace;
                        # the module prints 'Module: mymodule'
print(f(8))             # Calls function f (defined in mymodule), and prints result '16'
Some other Python file:
from mymodule import f as g # Runs mymodule.py; binds name g in our namespace to whatever
                            # mymodule's name f is bound to;
                            # the module prints 'Module: mymodule'
print(g(8))             # Calls function g (f in mymodule), and prints result '16'
Some other Python file:
from mymodule import *  # Runs mymodule.py; puts all its names into our namespace;
                        # the module prints 'Module: mymodule'
print(f(8))             # Calls function f (defined in mymodule), and prints result '16'

Some Standard Modules

Python has a larger number of standard modules. A few are mentioned here.
import sys
import os
import os.path
import logging
import atexit

import math             # Math functions, e.g. sqrt
import cmath            # Complex math functions, e.g. sqrt
import decimal          # Class for precise representation of decimal numbers, e.g. 0.1
import random           # Random number generation

import re               # See regular expressions
import collections      # See container types
import copy             # Object copying functions (deep and shallow copy)

import time
import datetime

Names

Binding Names to Objects

Everything (values, functions, classes, types) is an object - mutable or immutable. Names are created when they are bound (assigned) to objects and may be rebound to different objects later, or deleted. An object may have multiple names bound to it, and becomes irrelevant (possibly deleted) when there are no more references to it. Names are NOT permanent references to fixed storage locations which can be filled with values as in some other languages (e.g. C).
x = 10                  # (Creates and) binds name x to (immutable) object 10
y = x                   # Binds name y to same object as name x
del x                   # Forgets name x; its previously bound object is still bound to y
z = 10                  # Binds name z to (immutable) object 10 (possibly same object 10
                        # that y is bound to; mutable objects will never be reused like
                        # this)
y = 11                  # Binds name y to a different object than before
p = q = ['hi']          # Binds names p and q to same (mutable) object (first p, then q!)
p, z = z, p             # Swaps objects bound to names p and z (so p = 10, z = ['hi'])

def f1(b):              # Binds name f1 to function object defined here, and binds name b
                        # to object passed as argument to f1
    b = 3               # Binds name b to different object than was passed to f1 (this
                        # does not alter the passed object nor rebind whatever name was
                        # used to refer to that object when calling f1)
    return b            # Returns object bound to name b (and name b goes out of scope)

x = f1(y)               # Calls function object bound to name f1, and passes object bound
                        # to name y as argument (name y itself is not passed and can't be
                        # rebound from within f1);
                        # also binds name x to object returned by function call

class C1(object):       # Binds name C1 to class object defined here
    pass

c = C1()                # Binds name c to new instance object created from class object
                        # bound to name C1

Name Scope

def f1(x, y):
    global d, e             # Allows this function to modify module level names d & e
    print(b, x)             # Prints '1 1'; no need for 'global' to read external b, but
                            # this will fail if b is assigned anywhere within f1
                            # (UnboundLocalError exception if assigned after this line)
                            # (except if we cheat and assign to globals()['b'])
    c, d, e = 10, 11, 12    # Creates local c hiding external c (because no 'global')
                            # (but we can still cheat and read/write globals()['c']);
                            # also creates e at module level (did not exist before this!)
    f[0] = 13               # f refers to mutable object which can be changed even though
                            # f is not listed as 'global' (but without 'global' external f
                            # can't be changed to reference another object)
    x = 14                  # x was same as external b, but is now 14, while b is still 1
    y[0] = 15               # y refers to same object as external g, and that object can
                            # be changed via y (but g can't be changed to refer to another
                            # object)
    f2()                    # Calls external function f2
    if x == 14:             # Function definitions may be conditional like any statement
                            # (the 'if' body does not have its own local name scope)
        def f3(d):          # f3 is defined within f1, so can read f1's locals
            print(d)        # Prints local parameter d which is hiding external d
            global c        # Gives f3 access to module level c - not local c in f1
            c = x           # Assigns f1's local x to module level c (now c = 14)
            nonlocal h      # Gives f3 access to outer scope h (excl. module level)
            h = 'C'         # Changes f1's h from 'B' to 'C'

    h = 'B'                 # Creates local h hiding external h
    f3(30)                  # Calls inner function f3 which prints '30'
    print(b,c,d,e,f,g,h)    # Prints '1 10 11 12 [13] [15] C'; f3 changed h

def f2():
    pass                    # f2 is not defined within f1, so can't read f1's locals

b, c, d = 1, 2, 3           # Names read by function f1 must be defined before call to f1
f, g, h = [4], [5], 'A'     # but not necessarily before definition of f1
f1(b, g)                    # Calls function f1 and sets parameters x = b and y = g
print(b,c,d,e,f,g,h)        # Prints '1 14 11 12 [13] [15] A'; f1 changed d, e, and objects
                            # referenced by f & g (but didn't change f & g themselves);
                            # f3 changed c
Notes:

Coroutines/Tasks/Threads/Processes

import asyncio              # Support for multiple concurrent tasks/coroutines
import threading            # Support for multiple threads
import multiprocessing      # Support for multiple processes
import concurrent.futures   # Used here for thread and process pool executors
import contextlib           # Used here to suppress exceptions in a with statement
import os                   # Used here to get process id
import datetime             # Used here to get/format current time and do time calculations

# A class to handle thread-safe and process-safe logging
class Logger:
    def __init__(self, job_id, lock):
        self.job_id = job_id
        self.lock = lock

    # The __call__() method is called automatically when an instance of this class is
    # called as a function
    def __call__(self, msg):
        # Grab the global lock before printing to avoid simultaneous printing from
        # different threads/processes
        with self.lock:
            print('%s, job %s (proc %d, thread %d): %s' % (
                datetime.datetime.now().strftime('%H:%M:%S:%f'),
                self.job_id, os.getpid(), threading.get_ident(), msg))

# A coroutine function identified by the async keyword; returns a coroutine object
# representing the code in the function body, which is capable of cooperatively sharing
# the same thread with other coroutines by occasionally allowing itself to be suspended
# (e.g. by doing an await); execution of and switching between coroutines is handled by an
# event loop
async def concurrent_job(job_id, n, lock):
    log = Logger(job_id, lock)
    log('Started! Input=%d' % n)
    for i in range(n):
        log(str(i))
        # Suspend this task for 1 second
        await asyncio.sleep(1)
    r = asyncio.get_event_loop().time()
    log('Done! Result=%g' % r)
    return r

# Another coroutine function whose coroutine object runs forever until cancelled
async def endless_concurrent_job(job_id, lock):
    log = Logger(job_id, lock)
    log('Started!')
    loop = asyncio.get_event_loop()
    while True:
        log(str(loop.time()))
        # Suspend this task for 1 second
        await asyncio.sleep(1)

# A normal non-cooperative function which blocks the whole thread until it returns, so it
# should be run on a separate thread or in a separate process if the main thread needs to
# do other things in parallel
def blocking_job(job_id, step, lock):
    log = Logger(job_id, lock)
    start_time = datetime.datetime.now()
    end_time = start_time + datetime.timedelta(seconds=5)
    log('Started! Input=%d' % step)
    i = 0
    while datetime.datetime.now() < end_time:
        i += step
    log('Done! Result=%d' % i)
    return i

def main():
    # Create a single global lock to be passed to all threads and processes to ensure that
    # they don't corrupt each other's output (the simpler threading.Lock() can be used for
    # single-process programs, and no lock is needed for single-thread programs)
    lock = multiprocessing.Manager().Lock()

    log = Logger('Main', lock)
    log('Started!')

    # Get default event loop for our thread
    loop = asyncio.get_event_loop()

    # Start two concurrent jobs/coroutines in new separate tasks (in same thread as ours;
    # return value is a task which is a subclass of a 'future' which represents the job's
    # promised result when it completes; in addition to being a 'future' a task handles the
    # execution of the wrapped coroutine object)
    con1_task = loop.create_task(concurrent_job('Con1', 8, lock))
    con2_task = loop.create_task(endless_concurrent_job('Con2', lock))

    # Start parallel blocking job in new separate thread (in same process as ours; 1st arg
    # None selects default executor concurrent.futures.ThreadPoolExecutor, next arg
    # blocking_job is function to call in new thread, and remaining args are passed to that
    # function; return value is a 'future' object representing this job's promised result
    # when it completes)
    blk1_future = loop.run_in_executor(None, blocking_job, 'Blk1', 1, lock)

    # Start parallel blocking job in new separate process (a separate Python interpreter is
    # started in that process, loads this module, and calls function blocking_job with
    # specified args; WARNING: make sure all this code is not run again when this module is
    # loaded in that new process, or else it will again spawn a new process etc.)
    process_executor = concurrent.futures.ProcessPoolExecutor()
    blk2_future = loop.run_in_executor(process_executor, blocking_job, 'Blk2', -1, lock)

    # Let event loop run until all jobs (except the endless one) complete, then get their
    # results as a list (list items have same order as args to gather())
    results = loop.run_until_complete(asyncio.gather(con1_task, blk1_future, blk2_future))

    # Stop endless job
    con2_task.cancel()
    # Wait until job actually stops (this will always throw a CancelledError exception, so
    # suppress that)
    with contextlib.suppress(asyncio.CancelledError):
        loop.run_until_complete(con2_task)

    loop.close()
    log('Job C1 result: %d' % results[0])
    log('Job B1 result: %d' % results[1])
    log('Job B2 result: %d' % results[2])
    log('Done!')

# Make sure that main() only gets called when this module is run as a script, not when it
# is imported as a module (as it will be inside the subprocess spawned by main() - see
# WARNING above)
if __name__ == '__main__':
    main()
Example of output from above code:
01:18:00:410188, job Main (proc 7120, thread 6608): Started!
01:18:00:410188, job Blk1 (proc 7120, thread 9620): Started! Input=1
01:18:01:363241, job Con1 (proc 7120, thread 6608): Started! Input=8
01:18:01:394493, job Blk2 (proc 11876, thread 3436): Started! Input=-1
01:18:01:472595, job Con1 (proc 7120, thread 6608): 0
01:18:01:535107, job Con2 (proc 7120, thread 6608): Started!
01:18:01:597603, job Con2 (proc 7120, thread 6608): 14018.921
01:18:02:581886, job Con1 (proc 7120, thread 6608): 1
01:18:02:660005, job Con2 (proc 7120, thread 6608): 14019.984
01:18:03:691176, job Con1 (proc 7120, thread 6608): 2
01:18:03:800544, job Con2 (proc 7120, thread 6608): 14021.109
01:18:04:784844, job Con1 (proc 7120, thread 6608): 3
01:18:04:894210, job Con2 (proc 7120, thread 6608): 14022.218
01:18:05:425418, job Blk1 (proc 7120, thread 9620): Done! Result=6126588
01:18:05:831651, job Con1 (proc 7120, thread 6608): 4
01:18:05:956641, job Con2 (proc 7120, thread 6608): 14023.296
01:18:06:409731, job Blk2 (proc 11876, thread 3436): Done! Result=-6198597
01:18:06:836405, job Con1 (proc 7120, thread 6608): 5
01:18:06:977019, job Con2 (proc 7120, thread 6608): 14024.312
01:18:07:836330, job Con1 (proc 7120, thread 6608): 6
01:18:07:978596, job Con2 (proc 7120, thread 6608): 14025.312
01:18:08:837906, job Con1 (proc 7120, thread 6608): 7
01:18:08:994143, job Con2 (proc 7120, thread 6608): 14026.328
01:18:09:838515, job Con1 (proc 7120, thread 6608): Done! Result=14027.2
01:18:09:838515, job Main (proc 7120, thread 6608): Job C1 result: 14027
01:18:09:838515, job Main (proc 7120, thread 6608): Job B1 result: 6126588
01:18:09:838515, job Main (proc 7120, thread 6608): Job B2 result: -6198597
01:18:09:838515, job Main (proc 7120, thread 6608): Done!