diff --git a/Comprehensive Python Cheatsheet.mhtml b/Comprehensive Python Cheatsheet.mhtml new file mode 100644 index 000000000..ba5d1bdbb --- /dev/null +++ b/Comprehensive Python Cheatsheet.mhtml @@ -0,0 +1,9874 @@ +From: +Snapshot-Content-Location: https://gto76.github.io/python-cheatsheet/ +Subject: Comprehensive Python Cheatsheet +Date: Thu, 20 Jul 2023 21:45:57 -0000 +MIME-Version: 1.0 +Content-Type: multipart/related; + type="text/html"; + boundary="----MultipartBoundary--woPjoy8Y4Af6z7kPeFw2jGCIU9O3A2jLmleyvZRmJk----" + + +------MultipartBoundary--woPjoy8Y4Af6z7kPeFw2jGCIU9O3A2jLmleyvZRmJk---- +Content-Type: text/html +Content-ID: +Content-Transfer-Encoding: quoted-printable +Content-Location: https://gto76.github.io/python-cheatsheet/ + + + =20 + + Comprehensive Python Cheatsheet + + + + + + + + =20 + + + + + + + + + + + + + + + + + + + + + + +
+ + Jure =C5=A0orn +
+ +

Comprehensive Python Cheat= +sheet

Download text file, Buy = +PDF, Fork me on = +GitHub, Check out FAQ or Switch to dark theme. +

3D"Monty


= +#Contents

ToC =3D {
+    '1. Col=
+lections': [List, Dictionary, Set, Tuple, Range, Enumerate, Iterator, Generator],
+    '2. Typ=
+es':       [Type, String, Regular_Exp, Format, Numbers, Combinatorics, Datetime],
+    '3. Syn=
+tax':      [Args, Inline, Import, Decorator, Class, Duck_Types, Enum, Exception],
+    '4. Sys=
+tem':      [Exit, Print, Input, Command_Line_Arguments, Open, Path, OS_Commands],
+    '5. Dat=
+a':        [JSON, Pickle, CSV, SQLite, Bytes, Struct, Array, Memory_View, Deque],
+    '6. Adv=
+anced':    [Threading, Operator, Introspection, Metaprograming, Eval, Coroutine],
+    '7. Lib=
+raries':   [Progress_Bar, Plot, Table, Curses, Logging, Scraping, Web, Profile,
+                       NumPy, Image, Audio, Games, D=
+ata]
+}
+
+ + + + + + +

#Main

if __name__ =3D=3D '__main__':     # Runs=
+ main() if file wasn't imported.
+    main()
+
+ +

#List

<list> =3D <list>[<slice>]       # Or: <list>[from_inclusive : to_exclusive : =C2=B1step]=
+
+
+ +
<list>.append(<el=
+>)            # Or: <list> +=3D [<=
+el>]
+<list>.extend(<collection>)    # O=
+r: <list> +=3D <collection>
+
+
<list>.sort()       =
+           # Sorts in ascending order.
+<list>.reverse()               # Reverse=
+s the list in-place.
+<list> =3D sorted(<collection>)  #=
+ Returns a new sorted list.
+<iter> =3D reversed(<list>)      #=
+ Returns reversed iterator.
+
+
sum_of_elements  =3D sum(&=
+lt;collection>)
+elementwise_sum  =3D [sum(pair) for pai=
+r in zip(list_a, list_b)]
+sorted_by_second =3D sorted(<collection>, key=3Dlambda el: el[1])
+sorted_by_both   =3D sorted(<collection>, key=3Dlambda el: (el[1], el[0]))
+flatter_list     =3D list(itertools.chain.from_iterable(<list>))
+product_of_elems =3D functools.reduce(lambda out, el: out * el, <collection>)
+list_of_chars    =3D list(<str>)
+
+
    +
  • For details about sorted(), min() and max() see sortable. +
  • Module operator provides functions itemgetter() and mul() that offer t= +he same functionality as lambda expressions above.
  • +
+
<list>.insert(<in=
+t>, <el>)     # Inserts item at index=
+ and moves the rest to the right.
+<el>  =3D <list>.pop([<int>])    # Removes and returns item at index or from the end.
+<int> =3D <list>.count(<el>)     # Returns number of occurrences. Also works on strings.
+<int> =3D <list>.index(<el>)     # Returns index of the first occurrence or raises ValueError.
+<list>.remove(<el>)            # R=
+emoves first occurrence of the item or raises ValueError.
+<list>.clear()                 # Removes=
+ all items. Also works on dictionary and set.
+
+

#Dictionary

<view> =3D <dict>.keys()      =
+                    # Coll. of keys that refle=
+cts changes.
+<view> =3D <dict>.values()                        # Coll. of values that reflects changes.
+<view> =3D <dict>.items()                         # Coll. of key-value tuples that reflects chgs.
+
+ +
value  =3D <dict>.ge=
+t(key, default=3DNone)          # Returns default if key is missing.
+value  =3D <dict>.setdefault(key, default=3DNone)   # Returns and writes defaul=
+t if key is missing.
+<dict> =3D collections.defaultdict(<type>)        # Returns a dict with default value of type.
+<dict> =3D collections.defaultdict(lambd=
+a: 1)     # Returns a dict with default value 1.
+
+
<dict> =3D dict(<=
+collection>)                     # Creates =
+a dict from coll. of key-value pairs.
+<dict> =3D dict(zip(keys, values))                # Creates a dict from two collections.
+<dict> =3D dict.fromkeys(keys [, value])          # Creates a dict from collection of keys.
+
+
<dict>.update(<di=
+ct>)                           # Adds items=
+. Replaces ones with matching keys.
+value =3D <dict>.pop(key)                         # Removes item or raises KeyError.
+{k for k, v in <dict>.items() if v =
+=3D=3D value}    # Returns set of keys that po=
+int to the value.
+{k: v for k, v in <dict>.items() if =
+k in keys}  # Returns a dictionary, filtered by keys.
+
+

Counter

>>> from collections import Counter
+>>> colors =3D ['blue', 'blue', 'blue', 'red', 'red']
+>>> counter =3D Counter(colors)
+>>> counter['yellow'] +=3D 1
+Counter({'blue': 3, 'red': 2, 'yellow': 1})
+>>> counter.most_common()[0]
+('blue', 3)
+
+ +

#Set

<set> =3D set()                                   # `{}` returns a dictionary.
+
+ +
<set>.add(<el>=
+)                                 # Or: <se=
+t> |=3D {<el>}
+<set>.update(<collection> [, ...])              # Or: <set> |=3D <set>
+
+
<set>  =3D <set&g=
+t;.union(<coll.>)                   # Or=
+: <set> | <set>
+<set>  =3D <set>.intersection(<coll.>)            # Or: <set> & <set>
+<set>  =3D <set>.difference(<coll.>)              # Or: <set> - <set>
+<set>  =3D <set>.symmetric_difference(<coll.>)    # Or: <set> ^ <set>
+<bool> =3D <set>.issubset(<coll.>)                # Or: <set> <=3D <set>
+<bool> =3D <set>.issuperset(<coll.>)              # Or: <set> >=3D <set>
+
+
<el> =3D <set>=
+.pop()                              # Raises K=
+eyError if empty.
+<set>.remove(<el>)                              # Raises KeyError if missing.
+<set>.discard(<el>)                             # Doesn't raise an error.
+
+

Frozen Set

    +
  • Is immutable and hashable.
  • +
  • That means it can be used as a key in a dictionary or as an ele= +ment in a set.
  • +
<frozenset> =3D=
+ frozenset(<collection>)
+
+ + +

#Tuple

Tuple is an immutable and = +hashable list.

<tuple> =3D ()                                # Empty tuple.
+<tuple> =3D (<el>,)                           # Or: <el>,
+<tuple> =3D (<el_1>, <el_2> [, ...])          # Or: <el_1>, <el_2> [, ...]
+
+ + +

Named Tuple

Tuple's subclass with= + named elements.

>>> from collections import named=
+tuple
+>>> Point =3D namedtuple('Point', 'x y')
+>>> p =3D Point(1, y=3D2)
+Point(x=3D1, y=3D2)
+>>> p[0]
+1
+>>> p.x
+1
+>>> getattr(p, 'y')
+2
+
+ + +

#Range

Immutable and hashable seq= +uence of integers.

<range> =3D range(stop)                       # range(to_exclusive)
+<range> =3D range(start, stop)                # range(from_inclusive, to_exclusive)
+<range> =3D range(start, stop, =C2=B1step)         # range(from_inclusive, to_exclusive, =C2=B1step_size)
+
+ + +
=
+>>> [i for i in range(3)]
+[0, 1=
+, 2]
+
+

#Enumerate

for i, el <=
+span class=3D"hljs-keyword">in enumerate(<collection> [, i_sta=
+rt]):
+    ...
+
+ +

#Iterator

<iter> =3D iter(<collection>)          =
+       # `iter(<iter>)` returns unmodifi=
+ed iterator.
+<iter> =3D iter(<function>, to_exclusive)     # A sequence of return values until 'to_exclusive'.
+<el>   =3D next(<iter> [, default])           # Raises StopIteration or returns 'default' on end.
+<list> =3D list(<iter>)                       # Returns a list of iterator's remaining elements.
+
+ +

Itertools

import itertools as it
+
+ +
<iter> =3D it.count(=
+start=3D0, step=3D1)          # Returns updated val=
+ue endlessly. Accepts floats.
+<iter> =3D it.repeat(<el> [, times])          # Returns element endlessly or 'times' times.
+<iter> =3D it.cycle(<collection>)             # Repeats the sequence endlessly.
+
+
<iter> =3D it.chain(=
+<coll>, <coll> [, ...])   # Emptie=
+s collections in order (figuratively).
+<iter> =3D it.chain.from_iterable(<coll>)     # Empties collections inside a collection in order.
+
+
<iter> =3D it.islice=
+(<coll>, to_exclusive)    # Only returns=
+ first 'to_exclusive' elements.
+<iter> =3D it.islice(<coll>, from_inc, =E2=80=A6)     # `to_exclusive, +step_size`. Indices can be None.
+
+

#Generator

    +
  • Any function that contains a yield statement returns a generato= +r.
  • +
  • Generators and iterators are interchangeable.
  • +
def count(start, step):
+    while =
+True:
+        yield start
+        start +=3D step
+
+ + +
=
+>>> counter =3D count(10=
+, 2)
+>>> next(counter), next(counter),=
+ next(counter)
+(10, 12, 14)
+
+

#Type

    +
  • Everything is an object.
  • +
  • Every object has a type.
  • +
  • Type and class are synonymous.
  • +
<type> =3D type=
+(<el>)                          # Or: &l=
+t;el>.__class__
+<bool> =3D isinstance(<el>, <type>)            # Or: issubclass(type(<el>), <type>)
+
+ + +
=
+>>> type('a'), 'a'.__class__, str
+(<class 'str'>, <cl=
+ass 'str'>, <class 'str'>)
+
+

Some typ= +es do not have built-in names, so they must be imported:

from=
+ types import FunctionType, MethodType,=
+ LambdaType, GeneratorType, ModuleType
+
+ +

Abstract Base Classes

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

>>> from collection=
+s.abc import Iterable, Collection, Sequ=
+ence
+>>> isinstance([1, 2, 3], Iterable)
+True
+
+ + +
=E2=94=8F=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=93
+=E2=94=83                  =E2=94=82  Iterable  =E2=94=82 Collection =E2=94=
+=82  Sequence  =E2=94=83
+=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
+=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
+=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=A8
+=E2=94=83 list, range, str =E2=94=82     =E2=9C=93      =E2=94=82     =E2=
+=9C=93      =E2=94=82     =E2=9C=93      =E2=94=83
+=E2=94=83 dict, set        =E2=94=82     =E2=9C=93      =E2=94=82     =E2=
+=9C=93      =E2=94=82            =E2=94=83
+=E2=94=83 iter             =E2=94=82     =E2=9C=93      =E2=94=82          =
+  =E2=94=82            =E2=94=83
+=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=9B
+
+
=
+>>> from numbers import Number, Complex, Real, Rational, Integ=
+ral
+>>> isinstance(123, Number)
+True
+
+
=E2=94=8F=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=93
+=E2=94=83                    =E2=94=82  Number  =E2=94=82  Complex =E2=94=
+=82   Real   =E2=94=82 Rational =E2=94=82 Integral =E2=94=83
+=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=
+=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
+=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
+=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
+=E2=94=80=E2=94=A8
+=E2=94=83 int                =E2=94=82    =E2=9C=93     =E2=94=82    =E2=9C=
+=93     =E2=94=82    =E2=9C=93     =E2=94=82    =E2=9C=93     =E2=94=82    =
+=E2=9C=93     =E2=94=83
+=E2=94=83 fractions.Fraction =E2=94=82    =E2=9C=93     =E2=94=82    =E2=9C=
+=93     =E2=94=82    =E2=9C=93     =E2=94=82    =E2=9C=93     =E2=94=82    =
+      =E2=94=83
+=E2=94=83 float              =E2=94=82    =E2=9C=93     =E2=94=82    =E2=9C=
+=93     =E2=94=82    =E2=9C=93     =E2=94=82          =E2=94=82          =
+=E2=94=83
+=E2=94=83 complex            =E2=94=82    =E2=9C=93     =E2=94=82    =E2=9C=
+=93     =E2=94=82          =E2=94=82          =E2=94=82          =E2=94=83
+=E2=94=83 decimal.Decimal    =E2=94=82    =E2=9C=93     =E2=94=82          =
+=E2=94=82          =E2=94=82          =E2=94=82          =E2=94=83
+=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=9B
+
+

#String

<str>  =3D <str>.strip()                       =
+# Strips all whitespace characters from both e=
+nds.
+<str>  =3D <str>.strip('<chars&g=
+t;')              # Strips all passed c=
+haracters from both ends.
+
+ +
<list> =3D <str&g=
+t;.split()                       # Splits on o=
+ne or more whitespace characters.
+<list> =3D <str>.split(sep=3DNone<=
+/span>, maxsplit=3D-1)  # Splits on 'sep' str at most 'maxsplit' times.
+<list> =3D <str>.splitlines(keepends=3DFalse)    # On [\n\r\f\v\x1c-\x1e\=
+x85\u2028\u2029] and \r\n.
+<str>  =3D <str>.join(<coll_of_strings>)       # Joins elements using string as a separator.
+
+
<bool> =3D <sub_s=
+tr> in <str>                  =
+# Checks if string contains the substring.
+<bool> =3D <str>.startswith(<sub_str>)         # Pass tuple of strings for multiple options.
+<bool> =3D <str>.endswith(<sub_str>)           # Pass tuple of strings for multiple options.
+<int>  =3D <str>.find(<sub_str>)               # Returns start index of the first match or -1.
+<int>  =3D <str>.index(<sub_str>)              # Same, but raises ValueError if missing.
+
+
<str>  =3D <str&g=
+t;.replace(old, new [, count])   # Replaces 'o=
+ld' with 'new' at most 'count' times.
+<str>  =3D <str>.translate(<table>)            # Use `str.maketrans(<dict>)` to generate table.
+
+
<str>  =3D chr(<i=
+nt>)                          # Converts in=
+t to Unicode character.
+<int>  =3D ord(<str>)                          # Converts Unicode character to int.
+
+
    +
  • Also: '= +lstrip()', 'rstrip()' and 'rsplit()'.
  • +
  • Also: '= +lower()', 'upper()', 'capitalize()' and 'title()'.
  • +
+

Property Methods

=E2=94=8F=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=93
+=E2=94=83               =E2=94=82 [ !#$%=E2=80=A6] =E2=94=82 [a-zA-Z] =E2=
+=94=82  [=C2=BC=C2=BD=C2=BE]   =E2=94=82  [=C2=B2=C2=B3=C2=B9]   =E2=94=82 =
+ [0-9]   =E2=94=83
+=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
+=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
+=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=
+=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=A8
+=E2=94=83 isprintable() =E2=94=82    =E2=9C=93     =E2=94=82    =E2=9C=93  =
+   =E2=94=82    =E2=9C=93     =E2=94=82    =E2=9C=93     =E2=94=82    =E2=
+=9C=93     =E2=94=83
+=E2=94=83 isalnum()     =E2=94=82          =E2=94=82    =E2=9C=93     =E2=
+=94=82    =E2=9C=93     =E2=94=82    =E2=9C=93     =E2=94=82    =E2=9C=93  =
+   =E2=94=83
+=E2=94=83 isnumeric()   =E2=94=82          =E2=94=82          =E2=94=82    =
+=E2=9C=93     =E2=94=82    =E2=9C=93     =E2=94=82    =E2=9C=93     =E2=94=
+=83
+=E2=94=83 isdigit()     =E2=94=82          =E2=94=82          =E2=94=82    =
+      =E2=94=82    =E2=9C=93     =E2=94=82    =E2=9C=93     =E2=94=83
+=E2=94=83 isdecimal()   =E2=94=82          =E2=94=82          =E2=94=82    =
+      =E2=94=82          =E2=94=82    =E2=9C=93     =E2=94=83
+=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=9B
+
+ +
    +
  • 'isspac= +e()' checks for whitespaces: '[ \t\n\r\f\v\x1c-\x1f\x85\xa0\u1680=E2=80=A6]'.
  • +
+

#Regex

import re
+<str>   =3D re.sub(<regex>, new, text, count=3D0)  # Substitutes all occur=
+rences with 'new'.
+<list>  =3D re.findall(<regex>, text)            # Returns all occurrences as strings.
+<list>  =3D re.split(<regex>, text, maxsplit=3D0)  # Use brackets in regex=
+ to include the matches.
+<Match> =3D re.search(<regex>, text)             # Searches for first occurrence of the pattern.
+<Match> =3D re.match(<regex>, text)              # Searches only at the beginning of the text.
+<iter>  =3D re.finditer(<regex>, text)           # Returns all occurrences as Match objects.
+
+ +
    +
  • Argument 'new' can be a function that accepts a Match object an= +d returns a string.
  • +
  • Search() and match() return None if they can't find a match.
  • +
  • Argument 'flags=3Dre.IGNORECASE' can be used with all functions.
  • +
  • Argument 'flags=3Dre.MULTILINE' makes '^' and '$' match the start/end of each = +line.
  • +
  • Argument 'flags=3Dre.DOTALL' makes '.' also accept the '\n'.
  • +
  • Use r'\= +1' or '\\1' for backreference ('\1' returns a character with octal code= + 1).
  • +
  • Add '?'= + after '*' and '+' to make them non-greedy.
  • +
+

Match Object

<str>   =3D <Match>.group()                 =
+     # Returns the whole match. Also group(0).=
+
+<str>   =3D <Match>.group(1)=
+                     # Returns part in the fir=
+st bracket.
+<tuple> =3D <Match>.groups()                     # Returns all bracketed parts.
+<int>   =3D <Match>.start()                      # Returns start index of the match.
+<int>   =3D <Match>.end()                        # Returns exclusive end index of the match.
+
+ +

Special Sequences

'\d' =3D=3D=
+ '[0-9]'                                =
+# Matches decimal characters.
+'\w' =3D=3D =
+'[a-zA-Z0-9_]'                         =
+# Matches alphanumerics and underscore.
+'\s' =3D=3D =
+'[ \t\n\r\f\v]'                        =
+# Matches whitespaces.
+
+ +
    +
  • By default, decimal characters, alphanumerics and whitespaces f= +rom all alphabets are matched unless 'flags=3Dre.ASCII' argument is used.
  • +
  • As shown above, it restricts all special sequence matches to th= +e first 128 characters and prevents '\s' from accepting '[\x1c-\x1f]' (the so-called = +separator characters).
  • +
  • Use a capital letter for negation (all non-ASCII characters wil= +l be matched when used in combination with ASCII flag).
  • +
+

#Format

=
+<str> =3D f'{&=
+lt;el_1>}, {<el_2>}'            # Curly brackets can also contai=
+n expressions.
+<str> =3D '{}, {}'.format(<el_1=
+>, <el_2>)  # Or: '{0}, {a}'.format(&=
+lt;el_1>, a=3D<el_2>)
+<str> =3D '%s, %s' % (<el_1>=
+, <el_2>)      # Redundant and inferior =
+C-style formatting.
+
+ +

Example

>>> Person =3D collecti=
+ons.namedtuple('Person', 'name height')
+>>> person =3D Person('Jean-Luc', 187)
+>>> f=
+'{person.name} is {person.height / 100} meters =
+tall.'
+'Jean-Luc is 1.87 meters tall.'
+
+ +

General Options

{<el>:<10}                               # '<el&g=
+t;      '
+{<el>:^10}                        =
+       # '   <el>   '
+{<el>:>10}                     =
+          # '      <el>'
+{<el>:.<10}                    =
+          # '<el>......'
+{<el>:0}                          =
+       # '<el>'
+
+ +
    +
  • Options can be generated dynamically: f'{<el>:{&l= +t;str/int>}[=E2=80=A6]}'.
  • +
  • Adding = +'=3D' to the expression prepends it to the output: f'= +{1+1= +=3D}' returns '1+1=3D2'.
  • +
  • Adding = +'!r' to the expression converts object to string by calling i= +ts repr() = +method.
  • +
+

Strings

{'abcde':10}                             =
+# 'abcde     '
+{'abcde':10.=
+3}                           # 'abc    =
+   '
+{'abcde':.3<=
+/span>}                             # 'abc'
+{'abcde'!r:1=
+0}                           # "'abcde'=
+   "
+
+ +

Numbers

{123456:10}                              # '    123456'
+{123456:10,}                             # '   123,=
+456'
+{123456:10_}                             # '   123_=
+456'
+{123456:+10<=
+/span>}                             # '   +123=
+456'
+{123456:=3D+=
+10}                            # '+   1=
+23456'
+{123456: }                              =
+ # ' 123456'
+{-123456: }                             =
+ # '-123456'
+
+ +

Floats

{1.23456:10.3}                           # =
+'      1.23'
+{1.23456:10.=
+3f}                          # '     1.=
+235'
+{1.23456:10.=
+3e}                          # ' 1.235e=
++00'
+{1.23456:10.=
+3%}                          # '  123.4=
+56%'
+
+ +

Comparison of presentation ty= +pes:

=E2=94=8F=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=93
+=E2=94=83              =E2=94=82    {<float>}   =E2=94=82   {<floa=
+t>:f}  =E2=94=82   {<float>:e}  =E2=94=82   {<float>:%}  =E2=
+=94=83
+=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
+=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=
+=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
+=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
+=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=A8
+=E2=94=83  0.000056789 =E2=94=82   '5.6789e-05' =E2=94=82    '0.000057'  =
+=E2=94=82 '5.678900e-05' =E2=94=82    '0.005679%' =E2=94=83
+=E2=94=83  0.00056789  =E2=94=82   '0.00056789' =E2=94=82    '0.000568'  =
+=E2=94=82 '5.678900e-04' =E2=94=82    '0.056789%' =E2=94=83
+=E2=94=83  0.0056789   =E2=94=82   '0.0056789'  =E2=94=82    '0.005679'  =
+=E2=94=82 '5.678900e-03' =E2=94=82    '0.567890%' =E2=94=83
+=E2=94=83  0.056789    =E2=94=82   '0.056789'   =E2=94=82    '0.056789'  =
+=E2=94=82 '5.678900e-02' =E2=94=82    '5.678900%' =E2=94=83
+=E2=94=83  0.56789     =E2=94=82   '0.56789'    =E2=94=82    '0.567890'  =
+=E2=94=82 '5.678900e-01' =E2=94=82   '56.789000%' =E2=94=83
+=E2=94=83  5.6789      =E2=94=82   '5.6789'     =E2=94=82    '5.678900'  =
+=E2=94=82 '5.678900e+00' =E2=94=82  '567.890000%' =E2=94=83
+=E2=94=83 56.789       =E2=94=82  '56.789'      =E2=94=82   '56.789000'  =
+=E2=94=82 '5.678900e+01' =E2=94=82 '5678.900000%' =E2=94=83
+=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=9B
+
+=E2=94=8F=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=93
+=E2=94=83              =E2=94=82  {<float>:.2}  =E2=94=82  {<float=
+>:.2f} =E2=94=82  {<float>:.2e} =E2=94=82  {<float>:.2%} =E2=
+=94=83
+=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
+=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=
+=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
+=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
+=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=A8
+=E2=94=83  0.000056789 =E2=94=82    '5.7e-05'   =E2=94=82      '0.00'    =
+=E2=94=82   '5.68e-05'   =E2=94=82      '0.01%'   =E2=94=83
+=E2=94=83  0.00056789  =E2=94=82    '0.00057'   =E2=94=82      '0.00'    =
+=E2=94=82   '5.68e-04'   =E2=94=82      '0.06%'   =E2=94=83
+=E2=94=83  0.0056789   =E2=94=82    '0.0057'    =E2=94=82      '0.01'    =
+=E2=94=82   '5.68e-03'   =E2=94=82      '0.57%'   =E2=94=83
+=E2=94=83  0.056789    =E2=94=82    '0.057'     =E2=94=82      '0.06'    =
+=E2=94=82   '5.68e-02'   =E2=94=82      '5.68%'   =E2=94=83
+=E2=94=83  0.56789     =E2=94=82    '0.57'      =E2=94=82      '0.57'    =
+=E2=94=82   '5.68e-01'   =E2=94=82     '56.79%'   =E2=94=83
+=E2=94=83  5.6789      =E2=94=82    '5.7'       =E2=94=82      '5.68'    =
+=E2=94=82   '5.68e+00'   =E2=94=82    '567.89%'   =E2=94=83
+=E2=94=83 56.789       =E2=94=82    '5.7e+01'   =E2=94=82     '56.79'    =
+=E2=94=82   '5.68e+01'   =E2=94=82   '5678.90%'   =E2=94=83
+=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=9B
+
+ + +
    +
  • '{<f= +loat>:g}' is '{<float>:.6}' with stripped zeros, exponent= + starting at 7 figures.
  • +
  • When both rounding up and rounding down are possible, the one t= +hat returns result with even last digit is chosen. That makes '{6.5:.0f}' a '6' and= + '{7.5:.0f}'= + an '8'.
  • +
  • This rule only effects numbers that can be represented exactly = +by a float (.5, .25, =E2=80=A6).
  • +
+

Ints

{90:c}                              =
+     # 'Z'
+{90:b}                                  =
+ # '1011010'
+{90:X}                                  =
+ # '5A'
+
+ +

#Numbers

<int>      =3D int(<float/str/bool>)       =
+         # Or: math.floor(<float>)
+<float>    =3D float(<int/str/bool>)                # Or: <real>e=C2=B1<int>
+<complex>  =3D complex(real=3D0, i=
+mag=3D0)              # Or: <real> =C2=B1 <real>j
+<Fraction> =3D fractions.Fraction(0, 1)             # Or: Fraction(numerator=3D0, denominator=3D1)
+<Decimal>  =3D decimal.Decimal(<str/int>)           # Or: Decimal((sign, digits, exponent))
+
+ +
    +
  • 'int(&l= +t;str>)' and 'float(<str>)' raise ValueError on malformed= + strings.
  • +
  • Decimal numbers are stored exactly, unlike most floats where '1.1 + 2.2 !=3D 3.3'<= +/span>.
  • +
  • Floats can be compared with: 'math.isclose(<float>, <float>)'.
  • +
  • Precision of decimal operations is set with: 'decimal.getcontext().prec =3D <in= +t>'.
  • +
+

Basic Functions

<num> =3D pow(<num>, <num>)     =
+                    # Or: <num> ** <n=
+um>
+<num> =3D abs(<num>)                                # <float> =3D abs(<complex>)
+<num> =3D round(<num> [, =C2=B1ndigits])                 # `round(126, -1) =3D=3D 130`
+
+ +

Math

from math import e, pi, inf, nan, isinf, isnan    # `<el> =3D=3D nan` is always False.
+from math =
+import sin, cos, tan, asin, acos, atan  # Also: degrees, radians.
+from math =
+import log, log10, log2                 # Log can accept base as second arg.
+
+ +

Statistics

from statistics import mean, median, variance     # Also: stdev, quantiles, groupby.
+
+ +

Random

from random import random, randint, choice        # Also: shuffle, gauss, triangular, seed.
+<float> =3D random()                                # A float inside [0, 1).
+<int>   =3D randint(from_inc, to_inc)               # An int inside [from_inc, to_inc].
+<el>    =3D choice(<sequence>)                      # Keeps the sequence intact.
+
+ +

Bin, Hex

<int> =3D =C2=B10b<bi=
+n>                                  # Or: =
+=C2=B10x<hex>
+<int> =3D int('=C2=B1<bin>',=
+ 2)                          # Or: int('=C2=B1<hex>', 16)
+<int> =3D int('=C2=B10b<bin>', 0)                        # Or: int('=C2=B10x<hex>', 0)
+<str> =3D bin(<int>)                                # Returns '[-]0b<bin>'.
+
+ +

Bitwise Operators

<int> =3D <int> & <int> =
+                            # And (0b1100 &=
+; 0b1010 =3D=3D 0b1000).
+<int> =3D <int> | <int>                             # Or  (0b1100 | 0b1010 =3D=3D 0b1110).
+<int> =3D <int> ^ <int>                             # Xor (0b1100 ^ 0b1010 =3D=3D 0b0110).
+<int> =3D <int> << n_bits                           # Left shift. Use >> for right.
+<int> =3D ~<int>                                    # Not. Also -<int> - 1.
+
+ +

#Combinatorics

    +
  • Every function returns an iterator.
  • +
  • If you want to print the iterator, you need to pass it to the l= +ist() function first!
  • +
import itertools as it
+
+ + +
=
+>>> it.product([0, 1], repeat=3D3)
+[(0, 0, 0), (0, 0, 1), (0, =
+1, 0), (0, 1, 1),
+ (1, 0, 0), (1, 0, 1), (1, =
+1, 0), (1, 1, 1)]
+
+
=
+>>> it.product('abc', 'abc')                     #   a  b  c
+[('a', 'a'), ('a', 'b'), ('a', 'c'),             # a x  x  x<=
+/span>
+ ('b', 'a'), ('b', 'b'), ('b', 'c'),             # b x  x  x<=
+/span>
+ ('c', 'a'), ('c', 'b'), ('c', 'c')]             # c x  x  x<=
+/span>
+
+
=
+>>> it.combinations('abc', 2)                    #   a  b  c
+[('a', 'b'), ('a', 'c'),                         # a .  =
+x  x
+ ('b', 'c')]                                     # =
+b .  .  x
+
+
=
+>>> it.combinations_with_replacement('abc', 2)   #   a  b  c
+[('a', 'a'), ('a', 'b'), ('a', 'c'),             # a x  x  x<=
+/span>
+ ('b', 'b'), ('b', 'c'),                         # b .  =
+x  x
+ ('c', 'c')]                                     # =
+c .  .  x
+
+
=
+>>> it.permutations('abc', 2)                    #   a  b  c
+[('a', 'b'), ('a', 'c'),                         # a .  =
+x  x
+ ('b', 'a'), ('b', 'c'),                         # b x  =
+.  x
+ ('c', 'a'), ('c', 'b')]                         # c x  =
+x  .
+
+

#Datetime

    +
  • Module 'datetime' provides 'date' <= +span class=3D"hljs-section"><D>, 'time' <T>, 'datetim= +e' <DT> and 'timedelta' <TD> classes. All are immutable and hashable.
  • +
  • Time and datetime objects can be 'aware' <a>, meaning they ha= +ve defined timezone, or 'naive' <n>, meaning they don't.
  • +
  • If object is naive, it is presumed to be in the system's timezo= +ne.
  • +
from datetime import dat=
+e, time, datetime, timedelta
+from dateutil.tz import UTC, tzlocal, gettz, datetime_exists, resolve_imaginar=
+y
+
+ + +

Constructors

<D>  =3D date(year, month, day)           =
+    # Only accepts valid dates from 1 to 9999 =
+AD.
+<T>  =3D time(hour=3D0, minute=3D<=
+span class=3D"hljs-number">0, second=3D0=
+)     # Also: `microsecond=3D0, tzinfo=
+=3DNone, fold=3D0`.
+<DT> =3D datetime(year, month, day, hour=3D0)   # Also: `minute=3D0, second=3D0,=
+ microsecond=3D0, =E2=80=A6`.
+<TD> =3D timedelta(weeks=3D0, days=
+=3D0, hours=3D0)  # Also: `minutes=3D0, seconds=3D0=
+, microseconds=3D0`.
+
+ +
    +
  • Use '&l= +t;D/DT>.weekday()' to get the day of the week as an int, w= +ith Monday being 0.
  • +
  • 'fold= +=3D1' means the second pass in case of time jumping back for = +one hour.
  • +
  • Timedelta normalizes arguments to =C2=B1days, seconds (< 86= +=E2=80=AF400) and microseconds (< 1M).
  • +
  • '<DT= +a> =3D resolve_imaginary(<DTa>)' fixes DTs that fall= + into the missing hour.
  • +
+

Now

<D/DTn>  =3D D/DT.today()                     # Current local date or naive datetime.
+<DTn>    =3D DT.utcnow()                      # Naive datetime from current UTC time.
+<DTa>    =3D DT.now(<tzinfo>)                 # Aware datetime from current tz time.
+
+ +
    +
  • To extract time use '<DTn>.time()', '<DTa>.time()' or '<DTa>.timetz()'.
  • +
+

Timezone

<tzinfo> =3D UTC                              # UTC timezone. London without DST.
+<tzinfo> =3D tzlocal()                        # Local timezone. Also gettz().
+<tzinfo> =3D gettz('<Continent>/<=
+;City>')      # 'Continent/City_Name=
+' timezone or None.
+<DTa>    =3D <DT>.astimezone(<tzinfo>)        # Datetime, converted to the passed timezone.
+<Ta/DTa> =3D <T/DT>.replace(tzinfo=3D<tzinfo>)  # Unconverted object with a new timezone.
+
+ +

Encode

<D/T/DT> =3D D/T/DT.fromisoformat('<iso>')    # Object from=
+ ISO string. Raises ValueError.
+<DT>     =3D DT.strptime(<str>, '&l=
+t;format>')   # Datetime from str, a=
+ccording to format.
+<D/DTn>  =3D D/DT.fromordinal(<int>)          # D/DTn from days since the Gregorian NYE 1.
+<DTn>    =3D DT.fromtimestamp(<real>)         # Local time DTn from seconds since the Epoch.
+<DTa>    =3D DT.fromtimestamp(<real>, <tz.>)  # Aware datetime from seconds since the Epoch.
+
+ +
    +
  • ISO strings come in following forms: 'YYYY-MM-DD', 'HH:MM:SS.mmmuuu[=C2=B1HH:MM]', or both separated by an arbitrary character. All parts following = +the hours are optional.
  • +
  • Python uses the Unix Epoch: '1970-01-01 00:00 UTC', '1970-01-01 01:00 CET', =E2=80=A6
  • +
+

Decode

<str>    =3D <D/T/DT>.isoformat(sep=3D'T')      # Also `timespec=
+=3D'auto/hours/minutes/seconds/=E2=80=A6'`.
+<str>    =3D <D/T/DT>.strftime('<=
+;format>')    # Custom string repres=
+entation.
+<int>    =3D <D/DT>.toordinal()               # Days since Gregorian NYE 1, ignoring time and tz.
+<float>  =3D <DTn>.timestamp()                # Seconds since the Epoch, from DTn in local tz.
+<float>  =3D <DTa>.timestamp()                # Seconds since the Epoch, from aware datetime.
+
+ +

Format

>>> dt =3D datetime.str=
+ptime('2015-05-14 23:39:00.00 +0200', '%Y-%m-%d %H:%M:%S.%f %z')
+>>> dt.strftime("%A, %dth of %B '%y, %I:%M%p %Z")
+"Thursday, 14th of May '15, 11:39PM UTC+02:00"<=
+/span>
+
+ +
    +
  • Format code '%z' accepts '=C2=B1HH[:]MM' and returns '=C2=B1HHMM' (or '' if datetim= +e is naive).
  • +
  • For abbreviated weekday and month use '%a' and '%b'.
  • +
+

Arithmetics

<D/DT>   =3D <D/DT>  =C2=B1 <TD>=
+                   # Returned datetime can fal=
+l into missing hour.
+<TD>     =3D <D/DTn> - <D/DTn>                # Returns the difference. Ignores time jumps.
+<TD>     =3D <DTa>   - <DTa>                  # Ignores time jumps if they share tzinfo object.
+<TD>     =3D <TD>    * <real>                 # Also: <TD> =3D abs(<TD>) and <TD> =3D=
+ <TD> =C2=B1% <TD>.
+<float>  =3D <TD>    / <TD>                   # How many weeks/years there are in TD. Also //.
+
+ +

#Arguments

Inside Function Call

func(<positional_args>)                           # func(0, 0)
+func(<keyword_args>)                              # func(x=3D0, y=3D0)
+func(<positional_args>, <keyword_args>)           # func(0, y=3D0)
+
+ + +

Inside Function Definition

def func(<nondefault_args>): ..= +. # def func(x, y): ... +def func(<default_a= +rgs>): ... # def func(x=3D0, y=3D0): ... +def func(<nondefaul= +t_args>, <default_args>): ... # def func(x, y=3D0): ... +
+ +
    +
  • Default values are evaluated when function is first encountered= + in the scope.
  • +
  • Any mutation of a mutable default value will persist between in= +vocations!
  • +
+

#Splat Operator

Inside Function Call

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

args   =3D (1, <=
+span class=3D"hljs-number">2)
+kwargs =3D {'x': 3, 'y': 4, 'z': 5}
+func(*args, **kwargs)
+
+ + + +

Is the same as:

func(1, 2, x=3D3, y=3D<=
+span class=3D"hljs-number">4, z=3D5)
+
+ +

Inside Function Definition

<= +p>Splat combines zero or more positional arguments into a tuple, wh= +ile splatty-splat combines zero or more keyword arguments into a dictionary= +.

def add(*a):
+    return sum(a)
+
+ + +
=
+>>> add(1, 2, 3)
+6
+
+

Legal argument combinations:

= +
def f(*args): ...               # f(1, 2, 3)
+def f(x, *args)=
+: ...            # f(1, 2, 3)
+def f(*args, z)=
+: ...            # f(1, 2, z=3D3)
+
+ +
def f(**kwargs): ...            # f(x=3D1, y=3D2, z=3D3)
+def f(x, **kwargs): ...         # f(x=3D1, y=3D2, z=3D=
+3) | f(1, y=3D2, z=3D3)
+
+
def f(*args, **kwargs): ...     # f(x=3D1, y=3D2, z=3D3) | f(1, y=3D2, z=3D3) | =
+f(1, 2, z=3D3) | f(1, 2, 3)
+def f(x, *args, **kwar=
+gs): ...  # f(x=3D1, y=3D2, z=3D=
+3) | f(1, y=3D2, z=3D3) | f(1, 2, z=3D3) | f(1, 2, 3)
+def f(*args, y, **kwar=
+gs): ...  # f(x=3D1, y=3D2, z=3D=
+3) | f(1, y=3D2, z=3D3)
+
+
def f(*, x, y, z): ...          # f(x=3D1, y=3D2, z=3D3)
+def f(x, *, y, z): ...          # f(x=3D1, y=3D2, z=3D=
+3) | f(1, y=3D2, z=3D3)
+def f(x, y, *, z): ...          # f(x=3D1, y=3D2, z=3D=
+3) | f(1, y=3D2, z=3D3) | f(1, 2, z=3D3)
+
+

Other Uses

<list>  =3D [*<coll.> [, ...]]    # Or: list(<collection>) [+ ...]
+<tuple> =3D (*<coll.>, [...])     =
+# Or: tuple(<collection>) [+ ...]
+<set>   =3D {*<coll.> [, ...]}    =
+# Or: set(<collection>) [| ...]
+<dict>  =3D {**<dict> [, ...]}    =
+# Or: dict(**<dict> [, ...])
+
+ +
head, *body, tail =3D <=
+coll.>     # Head or tail can be omitted.
+
+

#Inline

Lambda
<func> =3D lambda: <return_value>                   =
+  # A single statement function.
+<func> =3D lambda <arg_1>, =
+<arg_2>: <return_value>    # Also =
+accepts default arguments.
+

+ + +

Comprehensions

<list> =3D [i+1 for i in range(10)]                  =
+ # Or: [1, 2, ..., 10]
+<iter> =3D (i for i in range(10) if i > 5)            # Or: iter([6, 7, 8, 9])
+<set>  =3D {i+5 for i in range(10)}                   # Or: {5, 6, ..., 14}
+<dict> =3D {i: i*2 for i in range(10)}                # Or: {0: 0, 1: 2, ..., 9: 18}
+
+ +
=
+>>> [l+r for l in 'abc' for r in 'abc']
+['aa', 'ab'<=
+/span>, 'ac', ..., 'cc']
+
+

Map, Filter, Reduce

from func=
+tools import reduce
+
+ +
<iter> =3D map(lambda x: x + 1<=
+/span>, range(10))            # Or: iter([1, 2, ..., 10])
+<iter> =3D filter(lambda x: x >=
+; 5, range(1=
+0))         # Or: iter([6, 7, 8, 9])
+<obj>  =3D reduce(lambda out, x: =
+out + x, range(10))  # Or: 45
+
+

Any, All

<bool> =3D any(<collection>)                         =
+ # Is `bool(<el>)` True for any element.=
+
+<bool> =3D all(<collection>)                          # Is True for all elements or empty.
+
+ +

Conditional Expression

<obj> =3D <exp> if <condition> else <exp>             # Only =
+one expression gets evaluated.
+
+ +
=
+>>> [a if a else 'zero' for a in (0, 1, 2, 3)]      # `any([0, '', [], None]) =3D=3D F=
+alse`
+['zero', 1, 2, 3<=
+/span>]
+
+

Named Tuple, Enum, Dataclass

from collections import namedtu= +ple +Point =3D namedtuple('Point', 'x y') # Creates a tuple's subclass. +point =3D Point(0, 0) # Returns its instance. +
+ +
from enum import Enum
+Direction =3D Enum('Direction', 'N E S W')            # Creates an enum.
+direction =3D Direction.N                             # Returns its member.
+
+
from dataclasses import make_=
+dataclass
+Player =3D make_dataclass('Player', ['loc', 'dir'])   # Creates a class.
+player =3D Player(point, direction)                   # Returns its instance.
+
+

#Imports

import <module&g=
+t;            # Imports a built-in or '<mod=
+ule>.py'.
+import <package>           # Imports a built-in or '<package>/__init__.py=
+'.
+import <package>.<module>  =
+# Imports a built-in or '<package>/<m=
+odule>.py'.
+
+ +
    +
  • Package is a collection of modules, but it can also define its = +own objects.
  • +
  • On a filesystem this corresponds to a directory of Python files= + with an optional init script.
  • +
  • Running 'import <package>' does not automatically provide acce= +ss to the package's modules unless they are explicitly imported in its init= + script.
  • +
+

#Closure

We have/get a clos= +ure in Python when:

    +
  • A nested function references a value of its enclosing function = +and then
  • +
  • the enclosing function returns the nested function. +
def get_multiplier(a):
+    def <=
+span class=3D"hljs-title">out(b):=
+
+        return a * b
+    return out
+
+ + + +
=
+>>> multiply_by_3 =3D get_multiplier(3)
+>>> multiply_by_3(10)
+30
+
+
    +
  • If multiple nested functions within enclosing function referenc= +e the same value, that value gets shared.
  • +
  • To dynamically access function's first free variable use '<function>.__closu= +re__[0].cell_contents'.
  • +
+

Partial

from functools import partial
+<function> =3D partial(<function> [, <arg_1>, <arg_2&g=
+t;, ...])
+
+ +
=
+>>> def multiply(a, b):
+...     retur=
+n a * b
+>>> multiply_by_3 =3D partial(mul=
+tiply, 3)
+>>> multiply_by_3(10)
+30
+
+
    +
  • Partial is also useful in cases when function needs to be passe= +d as an argument because it enables us to set its arguments beforehand.
  • +
  • A few examples being: 'defaultdict(<function>)', 'iter(<function>, to_exc= +lusive)' and dataclass's 'field(default_factory=3D<function>)'.
  • +
+

Non-Local

If variable is being assi= +gned to anywhere in the scope, it is regarded as a local variable, unless i= +t is declared as a 'global' or a 'nonlocal'.

def get_counter<=
+span class=3D"hljs-params">():
+    i =3D 0
+    def <=
+span class=3D"hljs-title">out():<=
+/span>
+        nonlocal i
+        i +=3D 1
+        return i
+    return out
+
+ + +
=
+>>> counter =3D get_counter()
+>>> counter(), counter(), counter=
+()
+(1, 2=
+, 3)
+
+

#Deco= +rator

    +
  • A decorator takes a function, adds some functionality and retur= +ns it.
  • +
  • It can be any callable, but is usually implemented as a function that = +returns a cl= +osure.
  • +
@decorator_name
+def function_that_gets_passed_to_decorator():
+    ...
+
+ + +

Debugger Example

Decorator t= +hat prints function's name every time the function is called.

<= +pre>from functools import wraps + +def debug(func)= +: + @wraps(func) + def <= +span class=3D"hljs-title">out(*args, **k= +wargs): + print(func.__name__) + return func(*args, **kwargs) + return out + +@debug +def add(x, y):<= +/span> + return x + y +
+ + +
    +
  • Wraps is a helper decorator that copies the metadata of the pas= +sed function (func) to the function it is wrapping (out).
  • +
  • Without it 'add.__name__' would return <= +span class=3D"hljs-string">'out'.
  • +
+

LRU Cache

Decorator that caches fun= +ction's return values. All function's arguments must be hashable.<= +/p>

from functools import lru_=
+cache
+
+@lru_cache(maxsize=3DNone)
+def fib(n):
+    return n if n < 2 else fib(n-2) + fib(n-=
+1)
+
+ + +
    +
  • Default size of the cache is 128 values. Passing 'maxsize=3DNone' ma= +kes it unbounded.
  • +
  • CPython interpreter limits recursion depth to 1000 by default. = +To increase it use = +'sys.setrecursionlimit(<depth>)'.
  • +
+

Parametrized Decorator

A decorator that accepts arguments and returns a normal decorator that acc= +epts a function.

from functools import wraps
+
+def debug(print_result=
+=3DFalse):
+    def <=
+span class=3D"hljs-title">decorator(func=
+):
+        @wraps(func)
+        def out(*args,=
+ **kwargs):
+            result =3D func(*args, **kwargs)
+            print(func.__name__, result if print_result else '')
+            return result
+        return out
+    return decorator
+
+@debug(print_result=3DTrue)
+def add(x, y):<=
+/span>
+    return x + y
+
+ + +
    +
  • Using only '@debug' to decorate the add() function would not work he= +re, because debug would then receive the add() function as a 'print_result'= + argument. Decorators can however manually check if the argument they recei= +ved is a function and act accordingly.
  • +
+

#Class

class <name>:
+    def <=
+span class=3D"hljs-title">__init__(self,=
+ a):
+        self.a =3D a
+    def <=
+span class=3D"hljs-title">__repr__(self)=
+:
+        class_name =3D self.__class__.__name__
+        return f'{class_name}({self.a!r})'
+    def <=
+span class=3D"hljs-title">__str__(self)<=
+/span>:
+        return str(self.a)
+
+    @classmethod
+    def <=
+span class=3D"hljs-title">get_class_name=
+(cls):
+        return cls.__name__
+
+ +
    +
  • Return value of repr() should be unambiguous and of str() reada= +ble.
  • +
  • If only repr() is defined, it will also be used for str().
  • +
  • Methods decorated with '@staticmethod' do not receive 'self' nor 'c= +ls' as their first arg.
  • +
+

Expressions that call the s= +tr() method:

print(<=
+;el>)
+f'{<el>}'
+logging.warning(<el>)
+csv.writer(<file>).writerow([<el>])
+raise Exception(<el>)
+
+ +

Expressions that call the = +repr() method:

print/s=
+tr/repr([<el>])
+print/str/repr({<el>: <el>})
+f'{<el>!r}'
+Z =3D dataclasses.make_dataclass('Z', [<=
+span class=3D"hljs-string">'a']); print/str/repr(Z(<el>))
+>>> <el>
+
+ +

Constructor Overloading

class <name>:
+    def <=
+span class=3D"hljs-title">__init__(self,=
+ a=3DNone):
+        self.a =3D a
+
+ +

Inheritance

c=
+lass Person:
+    def <=
+span class=3D"hljs-title">__init__(self,=
+ name, age):
+        self.name =3D name
+        self.age  =3D age
+
+class Employee(Person):
+    def <=
+span class=3D"hljs-title">__init__(self,=
+ name, age, staff_num):
+        super().__init__(name, age)
+        self.staff_num =3D staff_num
+
+ +

Multiple Inheritance

class A: =
+pass
+class B: pass
+class C(A, B): pass
+
+ +

MRO determines the order in which parent classes are traversed w= +hen searching for a method or an attribute:

+
=
+>>> C.mro()
+[<class 'C'>, <clas=
+s 'A'>, <class 'B'>, <class 'object'=
+>]
+
+

Property

Pythonic way of implementi= +ng getters and setters.

class Person:
+    @property
+    def <=
+span class=3D"hljs-title">name(self):
+        return ' '.join(self._name)
+
+    @name.setter
+    def <=
+span class=3D"hljs-title">name(self, val=
+ue):
+        self._name =3D value.split()
+
+ + +
=
+>>> person =3D Person()
+>>> person.name =3D '\t Guido  van Rossum \n'
+>>> person.name
+'Guido van Rossum'
+
+

Dataclass

Decorator that automatic= +ally generates init(), repr() and eq() special methods.

from=
+ dataclasses import dataclass, f=
+ield
+
+@dataclass(order=3DFalse, frozen=3DFalse)
+class <class_name>:
+    <attr_name>: <type>
+    <attr_name>: <type> =3D <default_value>
+    <attr_name>: list/dict/set =3D field(default_factory=3Dlist/dict/=
+set)
+
+ + +
    +
  • Objects can be made sortable with 'order=3DTrue' and immutable with 'frozen=3DTrue'.
  • +
  • For object to be hashable, all attributes must be hashable and 'frozen= +' must be True.
  • +
  • Function field() is needed because = +'<attr_name>: list =3D []' = +would make a list that is shared among all instances. Its 'default_factory'= + argument can be any callable.
  • +
  • For attributes of arbitrary type use 'typing.Any'.
  • +
+

Inline:

from dataclasses import make_dataclass
+<class> =3D make_dataclass('<class_nam=
+e>', <coll_of_attribute_names>)
+<class> =3D make_dataclass('<class_nam=
+e>', <coll_of_tuples>)
+<tuple> =3D ('<attr_name>', =
+<type> [, <default_value>])
+ +

Rest = +of type annotations (CPython interpreter ignores them all):

import typing as tp, collections.abc as abc
+<var_name>: list/set/abc.Iterable/abc.Sequence/tp.Optional[<type&g=
+t;] [=3D <obj>]
+<var_name>: dict/tuple/tp.Union[<type>, ...] [=3D <obj>]
+def func(<arg_name&=
+gt;: <type> [=3D <obj>]) -> <type>: ...
+
+ +

Slots

Mechanism that restricts objects= + to attributes listed in 'slots' and significantly reduces their memory foo= +tprint.

class MyClassWithSlots:
+    __slots__ =3D ['a']
+    def <=
+span class=3D"hljs-title">__init__(self)=
+:
+        self.a =3D 1
+
+ + +

Copy

from copy import copy, deepcopy
+<object> =3D copy(<object>)
+<object> =3D deepcopy(<object>)
+
+ +

#Duck Types

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

Comparable

    +
  • If eq() method is not overridden, it returns 'id(self) =3D=3D id(other)', which is the same as 'self is other'.
  • +
  • That means all objects compare not equal by default. +
  • Only the left side object has eq() method called, unless it ret= +urns NotImplemented, in which case the right object is consulted. False is = +returned if both return NotImplemented.
  • +
  • Ne() automatically works on any object that has eq() defined.
  • +
class =
+MyComparable:
+    def <=
+span class=3D"hljs-title">__init__(self,=
+ a):
+        self.a =3D a
+    def <=
+span class=3D"hljs-title">__eq__(self, o=
+ther):
+        if isinstance(other, type(self)=
+):
+            return self.a =3D=3D other.=
+a
+        return NotImplemented
+
+ + + + +

Hashable

    +
  • Hashable object needs both hash() and eq() methods and its hash= + value should never change.
  • +
  • Hashable objects that compare equal must have the same hash val= +ue, meaning default hash() that returns 'id(self)' will not do.
  • +
  • That is why Python automatically makes classes unhashable if yo= +u only implement eq().
  • +
class =
+MyHashable:
+    def <=
+span class=3D"hljs-title">__init__(self,=
+ a):
+        self._a =3D a
+    @property
+    def <=
+span class=3D"hljs-title">a(self)=
+:
+        return self._a
+    def <=
+span class=3D"hljs-title">__eq__(self, o=
+ther):
+        if isinstance(other, type(self)=
+):
+            return self.a =3D=3D other.=
+a
+        return NotImplemented
+    def <=
+span class=3D"hljs-title">__hash__(self)=
+:
+        return hash(self.a)
+
+ + +

Sortable

    +
  • With 'total_ordering' decorator, you only need to provide eq() = +and one of lt(), gt(), le() or ge() special methods and the rest will be au= +tomatically generated.
  • +
  • Functions sorted() and min() only require lt() method, while ma= +x() only requires gt(). However, it is best to define them all so that conf= +usion doesn't arise in other contexts.
  • +
  • When two lists, strings or dataclasses are compared, their valu= +es get compared in order until a pair of unequal values is found. The compa= +rison of this two values is then returned. The shorter sequence is consider= +ed smaller in case of all values being equal.
  • +
  • Characters are compared by their Unicode IDs. Use module 'local= +e' for proper alphabetical order.
  • +
from functools import to=
+tal_ordering
+
+@total_ordering
+class MySortable:
+    def <=
+span class=3D"hljs-title">__init__(self,=
+ a):
+        self.a =3D a
+    def <=
+span class=3D"hljs-title">__eq__(self, o=
+ther):
+        if isinstance(other, type(self)=
+):
+            return self.a =3D=3D other.=
+a
+        return NotImplemented
+    def <=
+span class=3D"hljs-title">__lt__(self, o=
+ther):
+        if isinstance(other, type(self)=
+):
+            return self.a < other.a
+        return NotImplemented
+
+ + +

Iterator

    +
  • Any object that has methods next() and iter() is an iterator.
  • +
  • Next() should return next item or raise StopIteration.= +
  • +
  • Iter() should return 'self'.
  • +
class =
+Counter:
+    def <=
+span class=3D"hljs-title">__init__(self)=
+:
+        self.i =3D 0
+    def <=
+span class=3D"hljs-title">__next__(self)=
+:
+        self.i +=3D 1
+        return self.i
+    def <=
+span class=3D"hljs-title">__iter__(self)=
+:
+        return self
+
+ + +
=
+>>> counter =3D Counter()
+>>> next(counter), next(counter),=
+ next(counter)
+(1, 2=
+, 3)
+
+

Python has many diffe= +rent iterator objects:

Callable

    +
  • All functions and classes have a call() method, hence are calla= +ble.
  • +
  • When this cheatsheet uses '<function>' as an argument, it actu= +ally means '<cal= +lable>'.
  • +
class =
+Counter:
+    def <=
+span class=3D"hljs-title">__init__(self)=
+:
+        self.i =3D 0
+    def <=
+span class=3D"hljs-title">__call__(self)=
+:
+        self.i +=3D 1
+        return self.i
+
+ + + + +
=
+>>> counter =3D Counter()
+>>> counter(), counter(), counter=
+()
+(1, 2=
+, 3)
+
+

Context Manager

    +
  • With statements only work with objects that have enter() and ex= +it() special methods.
  • +
  • Enter() should lock the resources and optionally return an obje= +ct.
  • +
  • Exit() should release the resources.
  • +
  • Any exception that happens inside the with block is passed to t= +he exit() method.
  • +
  • The exit() method can suppress the exception by returning a tru= +e value.
  • +
class =
+MyOpen:
+    def <=
+span class=3D"hljs-title">__init__(self,=
+ filename):
+        self.filename =3D filename
+    def <=
+span class=3D"hljs-title">__enter__(self=
+):
+        self.file =3D open(self.filename)
+        return self.file
+    def <=
+span class=3D"hljs-title">__exit__(self,=
+ exc_type, exception, traceback):
+        self.file.close()
+
+ + +
=
+>>> with open('test.txt', 'w') as file:
+...     file.write('Hello World!')
+>>> =
+with MyOpen('test.txt') as file:
+...     print(file.read())
+Hello World!
+
+

#Iterable Du= +ck Types

Iterable

    +
  • Only required method is iter(). It should return an iterator of= + object's items.
  • +
  • Contains() automatically works on any object that has iter() de= +fined.
  • +
class =
+MyIterable:
+    def <=
+span class=3D"hljs-title">__init__(self,=
+ a):
+        self.a =3D a
+    def <=
+span class=3D"hljs-title">__iter__(self)=
+:
+        return iter(self.a)
+    def <=
+span class=3D"hljs-title">__contains__(s=
+elf, el):
+        return el in self.a
+
+ + + +
=
+>>> obj =3D MyIterable([1, 2, 3])
+>>> [el for el in obj]
+[1, 2=
+, 3]
+>>> 1=
+ in obj
+True
+
+

Collection

    +
  • Only required methods are iter() and len(). Len() should return= + the number of items.
  • +
  • This cheatsheet actually means '<iterable>' when it uses '<collection>'.
  • +
  • I chose not to use the name 'iterable' because it sounds scarie= +r and more vague than 'collection'. The only drawback of this decision is t= +hat a reader could think a certain function doesn't accept iterators when i= +t does, since iterators are the only built-in objects that are iterable but= + are not collections.
  • +
class =
+MyCollection:
+    def <=
+span class=3D"hljs-title">__init__(self,=
+ a):
+        self.a =3D a
+    def <=
+span class=3D"hljs-title">__iter__(self)=
+:
+        return iter(self.a)
+    def <=
+span class=3D"hljs-title">__contains__(s=
+elf, el):
+        return el in self.a
+    def <=
+span class=3D"hljs-title">__len__(self)<=
+/span>:
+        return len(self.a)
+
+ + +

Sequence

    +
  • Only required methods are getitem() and len().
  • +
  • Getitem() should return an item at the passed index or raise In= +dexError.
  • +
  • Iter() and contains() automatically work on any object that has= + getitem() defined.
  • +
  • Reversed() automatically works on any object that has getitem()= + and len() defined.
  • +
class =
+MySequence:
+    def <=
+span class=3D"hljs-title">__init__(self,=
+ a):
+        self.a =3D a
+    def <=
+span class=3D"hljs-title">__iter__(self)=
+:
+        return iter(self.a)
+    def <=
+span class=3D"hljs-title">__contains__(s=
+elf, el):
+        return el in self.a
+    def <=
+span class=3D"hljs-title">__len__(self)<=
+/span>:
+        return len(self.a)
+    def <=
+span class=3D"hljs-title">__getitem__(se=
+lf, i):
+        return self.a[i]
+    def <=
+span class=3D"hljs-title">__reversed__(s=
+elf):
+        return reversed(self.a)
+
+ + +

Discrepancies between glossary definitions and abstract base classes:
    +
  • Glossary defines iterable as any object with iter() or getitem(= +) and sequence as any object with getitem() and len(). It does not define c= +ollection.
  • +
  • Passing ABC Iterable to isinstance() or issubclass() checks whe= +ther object/class has method iter(), while ABC Collection checks for iter()= +, contains() and len().
  • +

+ + + + +

ABC Sequence

    +
  • It's a richer interface than the basic sequence.
  • +
  • Extending it generates iter(), contains(), reversed(), index() = +and count().
  • +
  • Unlike = +'abc.Iterable' and 'abc.Collection', it is not a duck type. That i= +s why 'issubclass(M= +ySequence, abc.Sequence)' would return False even if MySequen= +ce had all the methods defined. It however recognizes list, tuple, range, s= +tr, bytes, bytearray, array, memoryview and deque, because they are registe= +red as its virtual subclasses.
  • +
from collections import =
+abc
+
+class MyAbcSequence(abc.S=
+equence):
+    def <=
+span class=3D"hljs-title">__init__(self,=
+ a):
+        self.a =3D a
+    def <=
+span class=3D"hljs-title">__len__(self)<=
+/span>:
+        return len(self.a)
+    def <=
+span class=3D"hljs-title">__getitem__(se=
+lf, i):
+        return self.a[i]
+

Table of required and automatically available special method= +s:

=E2=94=8F=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=93
+=E2=94=83            =E2=94=82  Iterable  =E2=94=82 Collection =E2=94=82  S=
+equence  =E2=94=82 abc.Sequence =E2=94=83
+=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
+=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
+=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
+=80=E2=94=A8
+=E2=94=83 iter()     =E2=94=82     !      =E2=94=82     !      =E2=94=82   =
+  =E2=9C=93      =E2=94=82      =E2=9C=93       =E2=94=83
+=E2=94=83 contains() =E2=94=82     =E2=9C=93      =E2=94=82     =E2=9C=93  =
+    =E2=94=82     =E2=9C=93      =E2=94=82      =E2=9C=93       =E2=94=83
+=E2=94=83 len()      =E2=94=82            =E2=94=82     !      =E2=94=82   =
+  !      =E2=94=82      !       =E2=94=83
+=E2=94=83 getitem()  =E2=94=82            =E2=94=82            =E2=94=82   =
+  !      =E2=94=82      !       =E2=94=83
+=E2=94=83 reversed() =E2=94=82            =E2=94=82            =E2=94=82   =
+  =E2=9C=93      =E2=94=82      =E2=9C=93       =E2=94=83
+=E2=94=83 index()    =E2=94=82            =E2=94=82            =E2=94=82   =
+         =E2=94=82      =E2=9C=93       =E2=94=83
+=E2=94=83 count()    =E2=94=82            =E2=94=82            =E2=94=82   =
+         =E2=94=82      =E2=9C=93       =E2=94=83
+=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=9B
+
+ +
    +
  • Other ABCs that generate missing methods are: MutableSequence, = +Set, MutableSet, Mapping and MutableMapping.
  • +
  • Names of their required methods are stored in '<abc>.__abstractmethods__'.
  • +
+

#Enum

from enum import Enum, auto
+
+ +
class <e=
+num_name>(Enum):
+    <member_name> =3D auto()
+    <member_name> =3D <value>
+    <member_name> =3D <value>, <value>
+
+
    +
  • Function auto() returns an increment of the last numeric value = +or 1.
  • +
  • Accessing a member named after a reserved keyword causes Syntax= +Error.
  • +
  • Methods receive the member they were called on as the 'self' ar= +gument.
  • +
+
<member> =3D <enu=
+m>.<member_name>           # Returns =
+a member.
+<member> =3D <enum>['<member_nam=
+e>']        # Returns a member. Rais=
+es KeyError.
+<member> =3D <enum>(<value>)                # Returns a member. Raises ValueError.
+<str>    =3D <member>.name                  # Returns member's name.
+<obj>    =3D <member>.value                 # Returns member's value.
+
+
<list>   =3D list(&l=
+t;enum>)                   # Returns enum's=
+ members.
+<list>   =3D [a.name for a in <enum>]       # Returns enum's member names.
+<list>   =3D [a.value for a in <enum>]      # Returns enum's member values.
+<member> =3D random.choice(list(<enum>))    # Returns a random member.
+
+
def get_=
+next_member(member):
+    members =3D list(type(member))
+    index =3D members.index(member) + 1
+    return members[index % len(members)=
+]
+
+

Inline

Cutlery =3D Enum('Cutlery', 'FORK KNIFE SPOON')
+Cutlery =3D Enum('Cutlery', ['FORK', 'KNIFE',=
+ 'SPOON'])
+Cutlery =3D Enum('Cutlery', {'FORK': 1, 'KNIFE': 2=
+, 'SPOON': 3=
+})
+
+ +

User-= +defined functions cannot be values, so they must be wrapped:

from functools import partial
+LogicOp =3D Enum('LogicOp', {'AND': partial(lambda<=
+/span> l, r: l and r),
+                           'OR':  partia=
+l(lambda l, r: l or r)})
+
+ +

#Exceptions

try:
+    <code>
+except <exception>:
+    <code>
+
+ +

Complex Example

try:
+    <code_1>
+except <exception_a>:
+    <code_2_a>
+except <exception_b>:
+    <code_2_b>
+else:
+    <code_2_c>
+finally:
+    <code_3>
+
+ +
    +
  • Code inside the 'else' block will only be executed if 'try' block had no = +exceptions.
  • +
  • Code inside the 'finally' block will always be executed (unless a si= +gnal is received).
  • +
  • All variables that are initialized in executed blocks are also = +visible in all subsequent blocks, as well as outside the try/except clause = +(only function blocks delimit scope).
  • +
  • To catch signals use 'signal.signal(signal_number, <func>)'.
  • +
+

Catching Exceptions

except=
+ <exception>: ...
+except <exception> as <name>: ...
+except (<exception>, [...]): ...
+except (<exception>, [...]) as <name>: ...
+
+ +
    +
  • Also catches subclasses of the exception.
  • +
  • Use 'tr= +aceback.print_exc()' to print the error message to stderr.
  • +
  • Use 'pr= +int(<name>)' to print just the cause of the exception (= +its arguments).
  • +
  • Use 'lo= +gging.exception(<message>)' to log the passed message, = +followed by the full error message of the caught exception.
  • +
+

Raising Exceptions

raise =
+<exception>
+raise <exception>()
+raise <exception>(<el> [, .=
+..])
+
+ +

Re-raising caught exception:

<= +pre>except <exception> [as &= +lt;name>]: + ... + raise +
+ +

Exception Object

arguments =3D <name>.args
+exc_type  =3D <name>.__class__
+filename  =3D <name>.__traceback__.tb_frame.f_code.co_filename
+func_name =3D <name>.__traceback__.tb_frame.f_code.co_name
+line      =3D linecache.getline(filename, <name>.__traceback__.tb_lin=
+eno)
+trace_str =3D ''.join(traceback.format_t=
+b(<name>.__traceback__))
+error_msg =3D ''.join(traceback.format_e=
+xception(exc_type, <name>, <name>.__traceback__))
+
+ +

Built-in Exceptions

BaseException
+ =E2=94=9C=E2=94=80=E2=94=80 SystemExit                   # Raised by the sys.exit() function.
+ =E2=94=9C=E2=94=80=E2=94=80 KeyboardInterrupt            # Raised when the user hits the interrupt key (ctrl-c).
+ =E2=94=94=E2=94=80=E2=94=80 Exception                    # User-defined exceptions should be derived from this class.
+      =E2=94=9C=E2=94=80=E2=94=80 ArithmeticError         # Base class for arithmetic errors such as ZeroDivisionError.
+      =E2=94=9C=E2=94=80=E2=94=80 AssertionError          # Raised by `assert <exp>` if expression returns false va=
+lue.
+      =E2=94=9C=E2=94=80=E2=94=80 AttributeError          # Raised when object doesn't have requested attribute/method.
+      =E2=94=9C=E2=94=80=E2=94=80 EOFError                # Raised by input() when it hits an end-of-file condition.
+      =E2=94=9C=E2=94=80=E2=94=80 LookupError             # Base class for errors when a collection can't find an item.
+      =E2=94=82    =E2=94=9C=E2=94=80=E2=94=80 IndexError         # Raised when a sequence index is out of range.
+      =E2=94=82    =E2=94=94=E2=94=80=E2=94=80 KeyError           # Raised when a dictionary key or set element is missin=
+g.
+      =E2=94=9C=E2=94=80=E2=94=80 MemoryError             # Out of memory. Could be too late to start deleting vars.
+      =E2=94=9C=E2=94=80=E2=94=80 NameError               # Raised when nonexistent name (variable/func/class) is used.
+      =E2=94=82    =E2=94=94=E2=94=80=E2=94=80 UnboundLocalError  # Raised when local name is used before it's being defi=
+ned.
+      =E2=94=9C=E2=94=80=E2=94=80 OSError                 # Errors such as FileExistsError/PermissionError (see #Open).
+      =E2=94=82    =E2=94=94=E2=94=80=E2=94=80 ConnectionError    # Errors such as BrokenPipeError/ConnectionAbortedError=
+.
+      =E2=94=9C=E2=94=80=E2=94=80 RuntimeError            # Raised by errors that don't fall into other categories.
+      =E2=94=82    =E2=94=9C=E2=94=80=E2=94=80 NotImplementedErr  # Can be raised by abstract methods or by unfinished co=
+de.
+      =E2=94=82    =E2=94=94=E2=94=80=E2=94=80 RecursionError     # Raised when the maximum recursion depth is exceeded.<=
+/span>
+      =E2=94=9C=E2=94=80=E2=94=80 StopIteration           # Raised by next() when run on an empty iterator.
+      =E2=94=9C=E2=94=80=E2=94=80 TypeError               # Raised when an argument is of the wrong type.
+      =E2=94=94=E2=94=80=E2=94=80 ValueError              # When argument has the right type but inappropriate value.
+
+ +

Collections and their excepti= +ons:

=E2=94=8F=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=93
+=E2=94=83           =E2=94=82    List    =E2=94=82    Set     =E2=94=82    =
+Dict    =E2=94=83
+=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
+=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
+=E2=94=80=E2=94=A8
+=E2=94=83 getitem() =E2=94=82 IndexError =E2=94=82            =E2=94=82  Ke=
+yError  =E2=94=83
+=E2=94=83 pop()     =E2=94=82 IndexError =E2=94=82  KeyError  =E2=94=82  Ke=
+yError  =E2=94=83
+=E2=94=83 remove()  =E2=94=82 ValueError =E2=94=82  KeyError  =E2=94=82    =
+        =E2=94=83
+=E2=94=83 index()   =E2=94=82 ValueError =E2=94=82            =E2=94=82    =
+        =E2=94=83
+=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=9B
+
+ +

Useful built-in exceptions:

= +raise TypeError('Argument is of the wron= +g type!') +raise ValueError('Argument has the right type but an inappropriate value!') +raise RuntimeError('None of above!') +
+ +

User-defined Exceptions

class MyError=
+(Exception): pass
+class MyInputError(MyErro=
+r): pass
+
+ +

#Exit

Exits the interpreter by raisi= +ng SystemExit exception.

import sys
+sys.exit()                        # Exits with=
+ exit code 0 (success).
+sys.exit(<el>)                    # Prin=
+ts to stderr and exits with 1.
+sys.exit(<int>)                   # Exit=
+s with passed exit code.
+
+ + +

#Print

print(<el_1>, ..., sep=3D' '<=
+/span>, end=3D'\n', file=3Dsys.stdout, f=
+lush=3DFalse)
+
+ +
    +
  • Use 'fi= +le=3Dsys.stderr' for messages about errors.
  • +
  • Use 'fl= +ush=3DTrue' to forcibly flush the stream.
  • +
+

Pretty Print

from pprint import pprint
+pprint(<collection>, width=3D80, d=
+epth=3DNone, compact=3DFalse, sort_dicts=3DTrue)
+
+ +
    +
  • Levels deeper than 'depth' get replaced by '=E2=80=A6'.
  • +
+

#Input

Reads a line from the user= + input or pipe if present.

<str> =3D input(prompt=3DNo=
+ne)
+
+ + +
    +
  • Trailing newline gets stripped.
  • +
  • Prompt string is printed to the standard output before reading = +input.
  • +
  • Raises EOFError when user hits EOF (ctrl-d/ctrl-z=E2=8F=8E) or = +input stream gets exhausted.
  • +
+

#Co= +mmand Line Arguments

<=
+span class=3D"hljs-keyword">import sys
+scripts_path =3D sys.argv[0]
+arguments    =3D sys.argv[1:]
+
+ +

Argument Parser

from argparse =
+import ArgumentParser, FileType
+p =3D ArgumentParser(description=3D<str>)
+p.add_argument('-<short_name>', '--<name>', action=3D'store_true')  # Flag.
+p.add_argument('-<short_name>', '--<name>', type=3D<type>)    =
+      # Option.
+p.add_argument('<name>', type=3D&l=
+t;type>, nargs=3D1)                  =
+  # First argument.
+p.add_argument('<name>', type=3D&l=
+t;type>, nargs=3D'+')                =
+  # Remaining arguments.
+p.add_argument('<name>', type=3D&l=
+t;type>, nargs=3D'*')                =
+  # Optional arguments.
+args  =3D p.parse_args()                                            # Exits on error.
+value =3D args.<name>
+
+ +
    +
  • Use 'he= +lp=3D<str>' to set argument description that will be di= +splayed in help message.
  • +
  • Use 'de= +fault=3D<el>' to set the default value.
  • +
  • Use 'ty= +pe=3DFileType(<mode>)' for files. Accepts 'encoding', b= +ut 'newline' is None.
  • +
+

#Open

Opens the file and returns a c= +orresponding file object.

<file> =3D open(<path>, mode=3D'r', encoding=3DNone, ne=
+wline=3DNone)
+
+ + +
    +
  • 'encodi= +ng=3DNone' means that the default encoding is used, which is = +platform dependent. Best practice is to use 'encoding=3D"utf-8"' whenever possib= +le.
  • +
  • 'newlin= +e=3DNone' means all different end of line combinations are co= +nverted to '\n' on read, while on write all '\n' characters are converted t= +o system's default line separator.
  • +
  • 'newlin= +e=3D""' means no conversions take place, but input is still b= +roken into chunks by readline() and readlines() on every '\n', '\r' and '\r= +\n'.
  • +
+

Modes

    +
  • 'r' - Read (default).
  • +
  • 'w' - Write (truncate).
  • +
  • 'x' - Write or fail if the file already exists.
  • +
  • 'a' - Append.
  • +
  • 'w+' - Read and write (truncate).
  • +
  • 'r+' - Read and write from the start.
  • +
  • 'a+' - Read and write from the end.
  • +
  • 't' - Text mode (default).
  • +
  • 'b' - Binary mode ('br', 'bw', 'bx', =E2=80=A6).
  • +

Exceptions

    +
  • 'FileNo= +tFoundError' can be raised when reading with 'r' or 'r+'.
  • +
  • 'FileEx= +istsError' can be raised when writing with 'x'.
  • +
  • 'IsADir= +ectoryError' and 'PermissionError' can be raised by any.<= +/li> +
  • 'OSErro= +r' is the parent class of all listed exceptions. +

File Object

<file>.seek(0)                      # Moves to the start o=
+f the file.
+<file>.seek(offset)                 # Mo=
+ves 'offset' chars/bytes from the start.
+<file>.seek(0, 2)                   # Moves t=
+o the end of the file.
+<bin_file>.seek(=C2=B1offset, <anchor>)  # Anchor: 0 start, 1 current position, 2 end.
+
+ + + + + +
<str/bytes> =3D <=
+file>.read(size=3D-1)  # Reads 'size' chars/bytes or until EOF.
+<str/bytes> =3D <file>.readline()     # Returns a line or empty string/bytes on EOF.
+<list>      =3D <file>.readlines()    # Returns a list of remaining lines.
+<str/bytes> =3D next(<file>)          # Returns a line using buffer. Do not mix.
+
+
<file>.write(<str=
+/bytes>)           # Writes a string or byt=
+es object.
+<file>.writelines(<collection>)     # Writes a coll. of strings or bytes objects.
+<file>.flush()                      # Fl=
+ushes write buffer. Runs every 4096/8192 B.
+
+
    +
  • Methods do not add or strip trailing newlines, even writelines(= +).
  • +
+

Read Text from File

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

Write Text to File

def write_to_file(filename, text):
+    with open(filename, 'w', encoding=3D'utf-8') as file:
+        file.write(text)
+
+ +

#Paths

import os, glob
+from pathlib import Path
+
+ +
<str>  =3D os.getcwd=
+()                # Returns the current workin=
+g directory.
+<str>  =3D os.path.join(<path>, ...)  # Joins two or more pathname components.
+<str>  =3D os.path.realpath(<path>)   # Resolves symlinks and calls path.abspath().
+
+
<str>  =3D os.path.b=
+asename(<path>)   # Returns final compon=
+ent of the path.
+<str>  =3D os.path.dirname(<path>)    # Returns path without the final component.
+<tup.> =3D os.path.splitext(<path>)   # Splits on last period of the final component.
+
+
<list> =3D os.listdi=
+r(path=3D'.')       # Returns filenames located at the path.
+<list> =3D glob.glob('<pattern>')     # Returns paths matching the wildcar=
+d pattern.
+
+
<bool> =3D os.path.e=
+xists(<path>)     # Or: <Path>.exi=
+sts()
+<bool> =3D os.path.isfile(<path>)     # Or: <DirEntry/Path>.is_file()
+<bool> =3D os.path.isdir(<path>)      # Or: <DirEntry/Path>.is_dir()
+
+
<stat> =3D os.stat(&=
+lt;path>)            # Or: <DirEntry/Pat=
+h>.stat()
+<real> =3D <stat>.st_mtime/st_size/=E2=80=A6  # Modification time, size in bytes, ...
+
+

DirEntry

Unlike listdir(), scandir(= +) returns DirEntry objects that cache isfile, isdir and on Windows also sta= +t information, thus significantly increasing the performance of code that r= +equires it.

&l=
+t;iter> =3D os.scandir(path=3D'.')   =
+    # Returns DirEntry objects located at the =
+path.
+<str>  =3D <DirEntry>.path            # Returns the whole path as a string.
+<str>  =3D <DirEntry>.name            # Returns final component as a string.
+<file> =3D open(<DirEntry>)           # Opens the file and returns a file object.
+
+ + +

Path Object

<Path> =3D Path(<path> [, ...])       # Accepts strings, Paths and DirEntry objects.
+<Path> =3D <path> / <path> [/ ...]    # First or second path must be a Path object.
+<Path> =3D <Path>.resolve()           # Resolves symlinks and calls <Path>.absolute().
+
+ +
<Path> =3D Path()   =
+                  # Returns relative cwd. Also=
+ Path('.').
+<Path> =3D Path.cwd()                 # =
+Returns absolute cwd. Also Path().resolve().
+<Path> =3D Path.home()                # =
+Returns user's home directory (absolute).
+<Path> =3D Path(__file__).resolve()   # =
+Returns script's path if cwd wasn't changed.
+
+
<Path> =3D <Path&=
+gt;.parent              # Returns Path without=
+ the final component.
+<str>  =3D <Path>.name                # Returns final component as a string.
+<str>  =3D <Path>.stem                # Returns final component without extension.
+<str>  =3D <Path>.suffix              # Returns final component's extension.
+<tup.> =3D <Path>.parts               # Returns all components as strings.
+
+
<iter> =3D <Path&=
+gt;.iterdir()           # Returns directory co=
+ntents as Path objects.
+<iter> =3D <Path>.glob('<pattern=
+>')   # Returns Paths matching the w=
+ildcard pattern.
+
+
<str>  =3D str(<P=
+ath>)                # Returns path as a st=
+ring.
+<file> =3D open(<Path>)               # Also <Path>.read/write_text/bytes().
+
+

#OS Commands

import=
+ os, shutil, subprocess
+
+ +
os.chdir(<path>)    =
+                # Changes the current working =
+directory.
+os.mkdir(<path>, mode=3D0o777)    =
+    # Creates a directory. Permissions are in =
+octal.
+os.makedirs(<path>, mode=3D0o777) =
+    # Creates all path's dirs. Also `exist_ok=
+=3DFalse`.
+
+
shutil.copy(from, to)     =
+          # Copies the file. 'to' can exist or=
+ be a dir.
+shutil.copy2(from, to)              # Also cop=
+ies creation and modification time.
+shutil.copytree(from, to)           # Copies t=
+he directory. 'to' must not exist.
+
+
os.rename(from, to)       =
+          # Renames/moves the file or director=
+y.
+os.replace(from, to)                # Same, bu=
+t overwrites file 'to' even on Windows.
+shutil.move(from, to)               # Rename()=
+ that moves into 'to' if it's a dir.
+
+
os.remove(<path>)   =
+                # Deletes the file.
+os.rmdir(<path>)                    # De=
+letes the empty directory.
+shutil.rmtree(<path>)               # De=
+letes the directory.
+
+
    +
  • Paths can be either strings, Paths or DirEntry objects.
  • +
  • Functions report OS related errors by raising either OSError or= + one of its subclasses.
  • +
+

Shell Commands

<pipe> =3D os.popen('<command>')      # Executes co=
+mmand in sh/cmd. Returns its stdout pipe.
+<str>  =3D <pipe>.read(size=3D-1)       # Reads 'size' chars or until EOF.=
+ Also readline/s().
+<int>  =3D <pipe>.close()             # Closes the pipe. Returns None on success (returncode 0).
+
+ +

Sends '1 + = +1' to the basic calculator and captures its output:

>>> subprocess.run('bc', input=3D'1 + 1\n', capture_output=3DTrue, text=3DTrue)
+CompletedProcess(args=3D'bc', returncode=
+=3D0, stdout=3D'2\n', stderr=3D'')
+
+ +

Sends test.in to the basic calculator running in standa= +rd mode and saves its output to test.out:

>>> from shlex import split
+>>> os.popen('echo 1 + 1 > test.in')
+>>> subprocess.run(split('bc -s'), stdin=3Dopen('test.in'), stdout=3Dopen('test.out'<=
+/span>, 'w'))
+CompletedProcess(args=3D['bc', '-s'], returncode=3D0=
+)
+>>> open('test.out').read()
+'2\n'
+
+ +

#JSON

Text file format for storing c= +ollections of strings and numbers.

import json
+<str>    =3D json.dumps(<object>)     # Converts object to JSON string.
+<object> =3D json.loads(<str>)        # Converts JSON string to object.
+
+ + +

Read Object from JSON File

=
+<=
+span class=3D"hljs-keyword">def read_json=
+_file(filename):
+    with open(filename, encoding=3D'utf-8') as file:
+        return json.load(file)
+
+ +

Write Object to JSON File

def write_to_js=
+on_file(filename, an_object):
+    with open(filename, 'w', encoding=3D'utf-8') as file:
+        json.dump(an_object, file, ensure_ascii=3DFalse, indent=3D2)
+
+ +

#Pickle

Binary file format for= + storing Python objects.

import pickle
+<bytes>  =3D pickle.dumps(<object>)   # Converts object to bytes object.
+<object> =3D pickle.loads(<bytes>)    # Converts bytes object to object.
+
+ + +

Read Object from File

def read_pickle_file(filename):
+    with open(filename, 'rb') as file:
+        return pickle.load(file)
+
+ +

Write Object to File

def write_to_pickle_fil=
+e(filename, an_object):
+    with open(filename, 'wb') as file:
+        pickle.dump(an_object, file)
+
+ +

#CSV

Text file format for storing sprea= +dsheets.

import csv
+
+ + +

Read

<reader> =3D csv.reader(<file>)       # Also: `dialect=3D'excel', delimiter=3D','`.
+<list>   =3D next(<reader>)           # Returns next row as a list of strings.
+<list>   =3D list(<reader>)           # Returns a list of remaining rows.
+
+ +
    +
  • File must be opened with a 'newline=3D""' argument, or newlines embe= +dded inside quoted fields will not be interpreted correctly!
  • +
  • To print the spreadsheet to the console use Tabulate library. +
  • For XML and binary Excel files (xlsx, xlsm and xlsb) use = +Pandas library.
  • +
  • Reader accepts any iterator of strings, not just files.
  • +
+

Write

<writer> =3D csv.writer(<file>)       # Also: `dialect=3D'excel', delimiter=3D','`.
+<writer>.writerow(<collection>)     # Encodes objects using `str(<el>)`.
+<writer>.writerows(<coll_of_coll>)  # Appends multiple rows.
+
+ +
    +
  • File must be opened with a 'newline=3D""' argument, or '\r' will be = +added in front of every '\n' on platforms that use '\r\n' line endings!
  • +
+

Parameters

    +
  • 'dialec= +t' - Master parameter that sets the default values. String or= + a 'csv.Dialect' object.
  • +
  • 'delimi= +ter' - A one-character string used to separate fields.
  • +
  • 'quotec= +har' - Character for quoting fields that contain special char= +acters.
  • +
  • 'double= +quote' - Whether quotechars inside fields are/get doubled or = +escaped.
  • +
  • 'skipin= +itialspace' - Is space character at the start of the field st= +ripped by the reader.
  • +
  • 'linete= +rminator' - How writer terminates rows. Reader is hardcoded t= +o '\n', '\r', '\r\n'.
  • +
  • 'quotin= +g' - 0: As necessary, 1: All, 2: All but numbers which are re= +ad as floats, 3: None.
  • +
  • 'escape= +char' - Character for escaping quotechars if doublequote is F= +alse.
  • +

Dialects

=E2=94=8F=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=93
+=E2=94=83                  =E2=94=82     excel    =E2=94=82   excel-tab  =
+=E2=94=82     unix     =E2=94=83
+=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
+=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=
+=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=A8
+=E2=94=83 delimiter        =E2=94=82       ','    =E2=94=82      '\t'    =
+=E2=94=82       ','    =E2=94=83
+=E2=94=83 quotechar        =E2=94=82       '"'    =E2=94=82       '"'    =
+=E2=94=82       '"'    =E2=94=83
+=E2=94=83 doublequote      =E2=94=82      True    =E2=94=82      True    =
+=E2=94=82      True    =E2=94=83
+=E2=94=83 skipinitialspace =E2=94=82     False    =E2=94=82     False    =
+=E2=94=82     False    =E2=94=83
+=E2=94=83 lineterminator   =E2=94=82    '\r\n'    =E2=94=82    '\r\n'    =
+=E2=94=82      '\n'    =E2=94=83
+=E2=94=83 quoting          =E2=94=82         0    =E2=94=82         0    =
+=E2=94=82         1    =E2=94=83
+=E2=94=83 escapechar       =E2=94=82      None    =E2=94=82      None    =
+=E2=94=82      None    =E2=94=83
+=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=9B
+
+ + + +

Read Rows from CSV File

def read_csv_file(filename, dialect=3D'excel'):
+    with open(filename, encoding=3D'utf-8', newline=3D'') as file:
+        return list(csv.reader(file, di=
+alect))
+
+ +

Write Rows to CSV File

def write_to_csv_file=
+(filename, rows, dialect=3D'excel'):
+    with open(filename, 'w', encoding=3D'utf-8', newline=3D'') as file:
+        writer =3D csv.writer(file, dialect)
+        writer.writerows(rows)
+
+ +

#SQLite

A server-less database= + engine that stores each database into a separate file.

impo=
+rt sqlite3
+<conn> =3D sqlite3.connect(<path>)                # Opens existing or new file. Also ':memory:'.
+<conn>.close()                                  # Closes the connection.
+
+ + +

Read

<cursor> =3D <conn>.execute('=
+<query>')            # Can raise =
+a subclass of sqlite3.Error.
+<tuple>  =3D <cursor>.fetchone()                  # Returns next row. Also next(<cursor>).
+<list>   =3D <cursor>.fetchall()                  # Returns remaining rows. Also list(<cursor>).
+
+ +

Write

<conn>.execute('<query>')                       # Can raise a subc=
+lass of sqlite3.Error.
+<conn>.commit()                                 # Saves all changes since the last commit.
+<conn>.rollback()                               # Discards all changes since the last commit.
+
+ +

Or:

with <conn>:                    =
+                # Exits the block with commit(=
+) or rollback(),
+    <conn>.execute('<query>'=
+)                   # depending on whether any=
+ exception occurred.
+
+ +

Placeholders

<conn>.execute('<q=
+uery>', <list/tuple>)         =
+# Replaces '?'s in query with values.
+<conn>.execute('<query>', &l=
+t;dict/namedtuple>)    # Replaces ':<key=
+>'s with values.
+<conn>.executemany('<query>'=
+, <coll_of_above>)  # Runs execute() mul=
+tiple times.
+
+ +
    +
  • Passed values can be of type str, int, float, bytes, None, bool= +, datetime.date or datetime.datetime.
  • +
  • Bools will be stored and returned as ints and dates as ISO formatted string= +s.
  • +
+

Example

Values are not actually sa= +ved in this example because 'conn.commit()' is omitted!

>>>=
+ conn =3D sqlite3.connect('test.db')
+>>> conn.execute('CREATE TABLE person (person_id INTEGER PRIMARY KEY, name, heig=
+ht)')
+>>> conn.execute('INSERT INTO person VALUES (NULL, ?, ?)', ('Jean-Luc', 187)=
+).lastrowid
+1
+>>> conn.execute('SELECT * FROM person').fetchall()
+[(1, 'Jean-L=
+uc', 187)]
+
+ + +

SqlAlchemy

# $ pip3 install sqlalchemy
+from sqlalchemy import create_engine, text
+<engine> =3D create_engine('<url>'<=
+/span>)               # Url: 'dialect://user:p=
+assword@host/dbname'.
+<conn>   =3D <engine>.connect()                   # Creates a connection. Also <conn>.close().
+<cursor> =3D <conn>.execute(text('&=
+lt;query>'), =E2=80=A6)   # Replaces=
+ ':<key>'s with keyword arguments.
+with <conn>.begin(): ...         =
+               # Exits the block with commit o=
+r rollback.
+
+ +
=E2=94=8F=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=93
+=E2=94=83 Dialect    =E2=94=82 pip3 install =E2=94=82 import   =E2=94=82   =
+        Dependencies           =E2=94=83
+=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
+=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
+=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
+=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
+=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=A8
+=E2=94=83 mysql      =E2=94=82 mysqlclient  =E2=94=82 MySQLdb  =E2=94=82 ww=
+w.pypi.org/project/mysqlclient =E2=94=83
+=E2=94=83 postgresql =E2=94=82 psycopg2     =E2=94=82 psycopg2 =E2=94=82 ww=
+w.pypi.org/project/psycopg2    =E2=94=83
+=E2=94=83 mssql      =E2=94=82 pyodbc       =E2=94=82 pyodbc   =E2=94=82 ww=
+w.pypi.org/project/pyodbc      =E2=94=83
+=E2=94=83 oracle     =E2=94=82 oracledb     =E2=94=82 oracledb =E2=94=82 ww=
+w.pypi.org/project/oracledb    =E2=94=83
+=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
+=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
+=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
+=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=9B
+
+

#Bytes

Bytes object is an immutab= +le sequence of single bytes. Mutable version is called bytearray.<= +/p>

<bytes> =3D b'<str>'                          # Only accepts ASCII characters and \x00-\xff.
+<int>   =3D <bytes>[<index>]                  # Returns an int in range from 0 to 255.
+<bytes> =3D <bytes>[<slice>]                  # Returns bytes even if it has only one element.
+<bytes> =3D <bytes>.join(<coll_of_bytes>)     # Joins elements using bytes as a separator.
+
+ + +

Encode

<bytes> =3D bytes(<coll_of_ints>)             # Ints must be in range from 0 to 255.
+<bytes> =3D bytes(<str>, 'utf-8')             # Or: <str>.encode('ut=
+f-8')
+<bytes> =3D <int>.to_bytes(n_bytes, =E2=80=A6)        # `byteorder=3D'big/little', signed=3DFalse`.
+<bytes> =3D bytes.fromhex('<hex>')            # Hex pairs can be separated=
+ by whitespaces.
+
+ +

Decode

<list>  =3D list(<bytes>)                     # Returns ints in range from 0 to 255.
+<str>   =3D str(<bytes>, 'utf-8')             # Or: <bytes>.decode('=
+utf-8')
+<int>   =3D int.from_bytes(<bytes>, =E2=80=A6)        # `byteorder=3D'big/little', signed=3DFalse`.
+'<hex>' =3D <bytes>.hex()   =
+                  # Returns hex pairs. Accepts=
+ `sep=3D<str>`.
+
+ +

Read Bytes from File

def read_bytes(filename):
+    with open(filename, 'rb') as file:
+        return file.read()
+
+ +

Write Bytes to File

def write_bytes<=
+span class=3D"hljs-params">(filename, bytes_obj):
+    with open(filename, 'wb') as file:
+        file.write(bytes_obj)
+
+ +

#Struct

    +
  • Module that performs conversions between a sequence of numbers = +and a bytes object.
  • +
  • System=E2=80=99s type sizes, byte order, and alignment rules ar= +e used by default.
  • +
from struct import pack,=
+ unpack
+<bytes> =3D pack('<format>',=
+ <el_1> [, ...])  # Packages arguments o=
+r raises struct.error.
+<tuple> =3D unpack('<format>', <bytes>)       # Use iter_unpack() fo=
+r iterator of tuples.
+
+ + +
=
+>>> pack('>hhl', 1, 2, 3)
+b'\x00\x01\x00\x02\x00\x00\x00\x03'
+>>> unpack('>hhl', b'\x00\x01\x00\x02\x00\=
+x00\x00\x03')
+(1, 2=
+, 3)
+
+

Format

For standard type sizes and manual a= +lignment (padding) start format string with:

    +
  • '=3D' - System's byte order (usually little-endian).
  • +
  • '<'<= +/span> - Little-endian.
  • +
  • '>'<= +/span> - Big-endian (also '!').
  • +

Besides numbers, pack() and unpack() also support bytes obj= +ects as part of the sequence:

    +
  • 'c' - A bytes object with a single element. For pad byte use 'x'.
  • +
  • '<n= +>s' - A bytes object= + with n elements.
  • +

Integer types. Use a capital le= +tter for unsigned type. Minimum and standard sizes are in brackets:

+
  • 'b' - char (1/1)
  • +
  • 'h' - short (2/2)
  • +
  • 'i' - int (2/4)
  • +
  • 'l' - long (4/4)
  • +
  • 'q' - long long (8/8)
  • +

    Floating point types:

    +
  • 'f' - float (4/4)
  • +
  • 'd' - double (8/8)
  • +
    + + + + + + + + +

    #Array

    List that can only hold nu= +mbers of a predefined type. Available types and their minimum sizes in byte= +s are listed above. Sizes and byte order are always determined by the syste= +m, however bytes of each element can be swapped with byteswap() method.

    from array import ar=
    +ray
    +<array> =3D array('<typecode>', <collection>)    # Array from collec=
    +tion of numbers.
    +<array> =3D array('<typecode>', <bytes>)         # Array from bytes =
    +object.
    +<array> =3D array('<typecode>', <array>)         # Treats array as a=
    + sequence of numbers.
    +<bytes> =3D bytes(<array>)                       # Or: <array>.tobytes()
    +<file>.write(<array>)                          # Writes array to the binary file.
    +
    + + +

    #Memory View

      +
    • A sequence object that points to the memory of another object.<= +/strong>
    • +
    • Each element can reference a single or multiple consecutive byt= +es, depending on format.
    • +
    • Order and number of elements can be changed with slicing.
    • +
    • Casting only works between char and other types and uses system= +'s sizes.
    • +
    • Byte order is always determined by the system.
    • +
    <mview> =3D mem=
    +oryview(<bytes/bytearray/array>)  # Immu=
    +table if bytes, else mutable.
    +<real>  =3D <mview>[<index>]                     # Returns an int or a float.
    +<mview> =3D <mview>[<slice>]                     # Mview with rearranged elements.
    +<mview> =3D <mview>.cast('<typec=
    +ode>')           # Casts memoryview =
    +to the new format.
    +<mview>.release()                              # Releases the object's memory buffer.
    +
    + + +
    <bytes> =3D bytes(&l=
    +t;mview>)                       # Returns a=
    + new bytes object.
    +<bytes> =3D <bytes>.join(<coll_of_mviews>)       # Joins mviews using bytes object as sep.
    +<array> =3D array('<typecode>', <mview>)         # Treats mview as a=
    + sequence of numbers.
    +<file>.write(<mview>)                          # Writes mview to the binary file.
    +
    +
    <list>  =3D list(<=
    +;mview>)                        # Returns a=
    + list of ints or floats.
    +<str>   =3D str(<mview>, 'utf-8')                # Treats mview as a bytes=
    + object.
    +<int>   =3D int.from_bytes(<mview>, =E2=80=A6)           # `byteorder=3D'big/little', signed=3DFalse`.
    +'<hex>' =3D <mview>.hex()   =
    +                     # Treats mview as a bytes=
    + object.
    +
    +

    #Deque

    A thread-safe list with ef= +ficient appends and pops from either side. Pronounced "deck".

    <= +pre>from collections import deque +<deque> =3D deque(<collection>, maxlen=3DNone) +
    + + +
    <deque>.appendleft(&=
    +lt;el>)                       # Opposite el=
    +ement is dropped if full.
    +<deque>.extendleft(<collection>)               # Collection gets reversed.
    +<el> =3D <deque>.popleft()                       # Raises IndexError if empty.
    +<deque>.rotate(n=3D1)             =
    +               # Rotates elements to the right=
    +.
    +
    +

    #Threading

      +
    • CPython interpreter can only run a single thread at a time.
    • +
    • That is why using multiple threads won't result in a faster exe= +cution, unless at least one of the threads contains an I/O operation.
    • +
    from threading import Th=
    +read, RLock, Semaphore, Event, Barrier
    +from concurrent.futures import ThreadPoolExecutor, as_completed
    +
    + + +

    Thread

    <Thread> =3D Thread(target=3D<function>)           # Use `args=3D<collection>` to set the argum=
    +ents.
    +<Thread>.start()                               # Starts the thread.
    +<bool> =3D <Thread>.is_alive()                   # Checks if the thread has finished executing.
    +<Thread>.join()                                # Waits for the thread to finish.
    +
    + +
      +
    • Use 'kw= +args=3D<dict>' to pass keyword arguments to the functio= +n.
    • +
    • Use 'da= +emon=3DTrue', or the program will not be able to exit while t= +he thread is alive.
    • +
    +

    Lock

    <lock> =3D RLock()                               # Lock that can only be released by acquirer.
    +<lock>.acquire()                               # Waits for the lock to be available.
    +<lock>.release()                               # Makes the lock available again.
    +
    + +

    Or:

    with <lock>:                  =
    +                 # Enters the block by calling=
    + acquire() and
    +    ...                                        # exits it with release(), even on error.
    +
    + +

    Semaphore, Event, Barrier

    <Semaphore> =3D Semaphore(v=
    +alue=3D1)               # Lock that can be acquired by 'value' threads.
    +<Event>     =3D Event()                          # Method wait() blocks until set() is called.
    +<Barrier>   =3D Barrier(n_times)                 # Wait() blocks until it's called n_times.
    +
    + +

    Queue

    <Queue> =3D queue.Queue(maxsize=3D0=
    +)               # A thread-safe FIFO qu=
    +eue. Also LifoQueue.
    +<Queue>.put(<el>)                              # Blocks until queue stops being full.
    +<Queue>.put_nowait(<el>)                       # Raises queue.Full exception if full.
    +<el> =3D <Queue>.get()                           # Blocks until queue stops being empty.
    +<el> =3D <Queue>.get_nowait()                    # Raises queue.Empty exception if empty.
    +
    + +

    Thread Pool Executor

    <Exec> =3D ThreadPoolExecutor(max_w=
    +orkers=3DNone)  # Or: `with ThreadPoolExecutor() as <name>: =E2=80=A6`
    +<iter> =3D <Exec>.map(<func>, <args_1>, ...)     # Multithreaded and non-lazy map(). Keeps order.=
    +
    +<Futr> =3D <Exec>.submit(<func>, <arg_1>, ...)   # Creates a thread and returns its Future obj.
    +<Exec>.shutdown(wait=3DTrue)     =
    +                # Blocks until all threads fin=
    +ish executing.
    +
    + +
    <bool> =3D <Futur=
    +e>.done()                       # Checks if=
    + the thread has finished executing.
    +<obj>  =3D <Future>.result(timeout=3DNone)         # Waits for thread to =
    +finish and returns result.
    +<bool> =3D <Future>.cancel()                     # Returns False if thread is already running.
    +<iter> =3D as_completed(<coll_of_Futures>)       # Each Future is yielded as it completes.
    +
    +
      +
    • Map() and as_completed() also accept 'timeout' argument that ca= +uses TimeoutError if result isn't available in 'timeout' seconds after next= +() is called.
    • +
    • Exceptions that happen inside threads are raised when next() is= + called on map's iterator or when result() is called on a Future. Its excep= +tion() method returns exception or None.
    • +
    • An object with the same interface called ProcessPoolExecutor pr= +ovides true parallelism by running a separate interpreter in each process. = +Arguments/results must be pickable.
    • +
    +

    #Operator

    Module of func= +tions that provide the functionality of operators.

    import operator as op
    +<obj>     =3D op.add/sub/mul/truediv/floordiv/mod(<obj>, <ob=
    +j>)     # +, -, *, /, //, %
    +<int/set> =3D op.and_/or_/xor(<int/set>, <int/set>)      =
    +           # &, |, ^
    +<bool>    =3D op.eq/ne/lt/le/gt/ge(<sortable>, <sortable>=
    +)          # =3D=3D, !=3D, <, <=3D, >=
    +, >=3D
    +<func>    =3D op.itemgetter/attrgetter/methodcaller(<obj> [, ..=
    +.])  # [index/key], .name, .name()
    +
    + + +
    elementwise_sum  =3D map(o=
    +p.add, list_a, list_b)
    +sorted_by_second =3D sorted(<collection>, key=3Dop.itemgetter(1))
    +sorted_by_both   =3D sorted(<collection>, key=3Dop.itemgetter(1, 0))
    +product_of_elems =3D functools.reduce(op.mul, <collection>)
    +union_of_sets    =3D functools.reduce(op.or_, <coll_of_sets>)
    +first_element    =3D op.methodcaller('pop', 0)(<list>)
    +
    +
      +
    • Binary operators require objects to have and(), or(), xor() and= + invert() special methods, unlike logical operators that work on all types = +of objects.
    • +
    • Also: '= +<bool> =3D <bool> &|^ <bool>' and '<int> =3D <boo= +l> &|^ <int>'.
    • +
    +

    #Introspection

    Inspecting code at runtime.

    Var= +iables

    <list> =
    +=3D dir()                             # Names =
    +of local variables (incl. functions).
    +<dict> =3D vars()                            # Dict of local variables. Also locals().
    +<dict> =3D globals()                         # Dict of global variables.
    +
    + + + +

    Attributes

    <list> =3D dir(<object>)                     # Names of object's attributes (incl. methods).<=
    +/span>
    +<dict> =3D vars(<object>)                    # Dict of writable attributes. Also <obj>.__dict__.
    +<bool> =3D hasattr(<object>, '<a=
    +ttr_name>')  # Checks if getattr() r=
    +aises an AttributeError.
    +value  =3D getattr(<object>, '<attr_na=
    +me>')  # Raises AttributeError if at=
    +tribute is missing.
    +setattr(<object>, '<attr_name>', value)    # Only works on objects with '_=
    +_dict__' attribute.
    +delattr(<object>, '<attr_name>')           # Same. Also `del <object>=
    +;.<attr_name>`.
    +
    + +

    Parameters

    <Sig>  =3D inspect.signature(<function>)     =
    +# Function's Signature object.
    +<dict> =3D <Sig>.parameters                  # Dict of Parameter objects.
    +<memb> =3D <Param>.kind                      # Member of ParameterKind enum.
    +<obj>  =3D <Param>.default                   # Default value or Parameter.empty.
    +<type> =3D <Param>.annotation                # Type or Parameter.empty.
    +
    + +

    #Metaprogramming

    Code that generates code.

    = +Type

    Type is the root class. If only passed an object it ret= +urns its type (class). Otherwise it creates a new class.

    <=
    +code class=3D"python language-python hljs"><class> =3D type('<class_name>', <tuple_of_parents>, &=
    +lt;dict_of_class_attributes>)

    + + + + +
    =
    +>>> Z =3D type('Z', (), =
    +{'a': 'abcde=
    +', 'b': 12345})
    +>>> z =3D Z()
    +
    +

    Meta Class

    A class that creates cl= +asses.

    def my_meta_class(name, pare=
    +nts, attrs):
    +    attrs['a'] =3D 'abcde'
    +    return type(name, parents, attrs)
    +
    + + +

    Or:

    class MyMetaClass(type=
    +):
    +    def <=
    +span class=3D"hljs-title">__new__(cls, n=
    +ame, parents, attrs):
    +        attrs['a'] =3D 'abcde'
    +        return type.__new__(cls, name, =
    +parents, attrs)
    +
    + +
      +
    • New() is a class method that gets called before init(). If it r= +eturns an instance of its class, then that instance gets passed to init() a= +s a 'self' argument.
    • +
    • It receives the same arguments as init(), except for the first = +one that specifies the desired type of the returned instance (MyMetaClass i= +n our case).
    • +
    • Like in our case, new() can also be called directly, usually fr= +om a new() method of a child class (def __new__(cls):= + return super().__new__(cls)).
    • +
    • The only difference between the examples above is that my_meta_= +class() returns a class of type type, while MyMetaClass() returns a class o= +f type MyMetaClass.
    • +
    +

    Metaclass Attribute

    Right= + before a class is created it checks if it has the 'metaclass' attribute de= +fined. If not, it recursively checks if any of his parents has it defined a= +nd eventually comes to type().

    cl=
    +ass MyClass(metaclass=3DMyMetaClass):
    +    b =3D 12345
    +
    + + +
    =
    +>>> MyClass.a, MyClass.b
    +('abcde', 12=
    +345)
    +
    +

    Type Diagram

    type(MyClass) =3D=3D MyMetaClass         # MyClass is an instance of MyMetaClass.
    +type(MyMetaClass) =3D=3D type            # MyM=
    +etaClass is an instance of type.
    +
    + +
    =E2=94=8F=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=93
    +=E2=94=83   Classes   =E2=94=82 Metaclasses =E2=94=83
    +=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=A8
    +=E2=94=83   MyClass =E2=86=90=E2=94=80=E2=94=80=E2=95=B4MyMetaClass =E2=94=
    +=83
    +=E2=94=83             =E2=94=82     =E2=86=91       =E2=94=83
    +=E2=94=83    object =E2=86=90=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=95=B4type =E2=86=90=E2=95=AE  =E2=94=83
    +=E2=94=83             =E2=94=82     =E2=94=82 =E2=95=B0=E2=94=80=E2=94=80=
    +=E2=95=AF  =E2=94=83
    +=E2=94=83     str =E2=86=90=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=95=AF       =E2=94=83
    +=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=9B
    +
    +

    Inheritance Diagram

    MyClass.__base__ =3D=3D object           <=
    +span class=3D"hljs-comment"># MyClass is a subclass of object.
    +MyMetaClass.__base__ =3D=3D type         # MyM=
    +etaClass is a subclass of type.
    +
    + +
    =E2=94=8F=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=93
    +=E2=94=83   Classes   =E2=94=82 Metaclasses =E2=94=83
    +=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=A8
    +=E2=94=83   MyClass   =E2=94=82 MyMetaClass =E2=94=83
    +=E2=94=83      =E2=86=91      =E2=94=82     =E2=86=91       =E2=94=83
    +=E2=94=83    object=E2=95=B6=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=86=92 type     =E2=94=83
    +=E2=94=83      =E2=86=93      =E2=94=82             =E2=94=83
    +=E2=94=83     str     =E2=94=82             =E2=94=83
    +=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=9B
    +
    +

    #Eval

    >>> from ast import literal_=
    +eval
    +>>> literal_eval('[1, 2, 3]')
    +[1, 2=
    +, 3]
    +>>> literal_eval('1 + 2')
    +ValueError: malformed node or string
    +
    + +

    #Coroutines

      +
    • Coroutines have a lot in common with threads, but unlike thread= +s, they only give up control when they call another coroutine and they don= +=E2=80=99t use as much memory.
    • +
    • Coroutine definition starts with 'async' and its call with 'await'.
    • +
    • 'asynci= +o.run(<coroutine>)' is the main entry point for asynchr= +onous programs.
    • +
    • Functions wait(), gather() and as_completed() start multiple co= +routines at the same time.
    • +
    • Asyncio module also provides its own Queue, Event, Lock and Semaphore cl= +asses.
    • +

    Runs a terminal game where you control an asterisk that must avoid= + numbers:

    import asyncio, collections, curses, curses.textpa=
    +d, enum, random
    +
    +P =3D collections.namedtuple('P', 'x y')         # =
    +Position
    +D =3D enum.Enum('D', 'n e s w')                  # =
    +Direction
    +W, H =3D 15, 7                                   # =
    +Width, Height
    +
    +def main(screen):
    +    curses.curs_set(0)                  =
    +       # Makes cursor invisible.
    +    screen.nodelay(True)               =
    +        # Makes getch() non-blocking.
    +    asyncio.run(main_coroutine(screen))        # Starts running asyncio code.
    +
    +async def main_corout=
    +ine(screen):
    +    moves =3D asyncio.Queue()
    +    state =3D {'*': P(0, 0), **{id_: P(W//2, H//2)=
    + for id_ i=
    +n range(10)}}
    +    ai    =3D [random_controller(id_, moves) f=
    +or id_ in range(10)]
    +    mvc   =3D [human_controller(screen, moves), model(moves, state), view(s=
    +tate, screen)]
    +    tasks =3D [asyncio.create_task(cor) for cor in ai + mvc]
    +    await asyncio.wait(tasks, return_wh=
    +en=3Dasyncio.FIRST_COMPLETED)
    +
    +async def random_cont=
    +roller(id_, moves):
    +    while =
    +True:
    +        d =3D random.choice(list(D))
    +        moves.put_nowait((id_, d))
    +        await asyncio.sleep(random.tria=
    +ngular(0.01, 0.65))
    +
    +async def human_contr=
    +oller(screen, moves):
    +    while =
    +True:
    +        key_mappings =3D {258: D.s, 259: D.n, 260: D.w, 261: D.e}
    +        if d :=3D key_mappings.get(scre=
    +en.getch()):
    +            moves.put_nowait(('*', d))
    +        await asyncio.sleep(0.005)
    +
    +async def model(moves, state):
    +    while state['*'] not in (state[id_] for id=
    +_ in range(=
    +10)):
    +        id_, d =3D await moves.get()
    +        x, y   =3D state[id_]
    +        deltas =3D {D.n: P(0, -1), D.e: P(1, =
    +0), D.s: P(0=
    +, 1), D.w: P(-1, 0)}
    +        state[id_] =3D P((x + deltas[d].x) % W, (y + deltas[d].y) % H)
    +
    +async def view=
    +(state, screen):
    +    offset =3D P(curses.COLS//2 - W//2, curses.LINES//2 - H//2)
    +    while =
    +True:
    +        screen.erase()
    +        curses.textpad.rectangle(screen, offset.y-1, offset.x-1, offset.y+H, off=
    +set.x+W)
    +        for id_, p in state.items():
    +            screen.addstr(offset.y + (p.y - state['*'].y + H//2) % H,
    +                          offset.x + (p.x - state['*'].x + W//2) % W, str(id_))
    +        screen.refresh()
    +        await asyncio.sleep(0.005)
    +
    +if __name__ =3D=3D '__main__':
    +    curses.wrapper(main)
    +
    + + + +


    +

    Libraries

    #Progress Bar

    # $ pip3 install tqdm
    +>>> =
    +from tqdm import tqdm
    +>>> =
    +from time import sleep
    +>>> =
    +for el in tqdm([1, 2, 3], desc=3D'Processing'):
    +...     sleep(=
    +1)
    +Processing: 100%|=E2=96=88=E2=96=88=E2=96=88=E2=96=88=E2=96=88=E2=96=88=E2=
    +=96=88=E2=96=88=E2=96=88=E2=96=88=E2=96=88=E2=96=88=E2=96=88=E2=96=88=E2=96=
    +=88=E2=96=88=E2=96=88=E2=96=88=E2=96=88=E2=96=88| 3/3 [00:03<00:00,  1.0=
    +0s/it]
    +
    + + +

    #Plot

    # $ pip3 install matplotlib
    +import matplotlib.pyplot as plt
    +plt.plot/bar/scatter(x_data, y_data [, label=3D<str>])  # Or: plt.plot(y_data)
    +plt.legend()                                          # Adds a legend.
    +plt.savefig(<path>)                                   # Saves the figure.
    +plt.show()                                            # Displays the figure.
    +plt.clf()                                             # Clears the figure.
    +
    + +

    #Table

    Prints a CSV file as an ASCII table:

    # $ pip3 install tabula=
    +te
    +import csv, tabulate
    +with open('=
    +test.csv', encoding=3D'utf-8', ne=
    +wline=3D'') as file:
    +    rows   =3D csv.reader(file)
    +    header =3D next(rows)
    +    table  =3D tabulate.tabulate(rows, header)
    +print(table)
    +
    + + +

    #Curses

    Runs a basic file explorer in the terminal:

    impor=
    +t curses, curses.ascii, os
    +from curses import A_REVERSE, KEY_DOWN, KEY_UP, KEY_LEFT, KEY_RIGHT, KEY_ENTER
    +
    +def main(screen):
    +    ch, first, selected, paths =3D 0, 0, 0, o=
    +s.listdir()
    +    while ch !=3D curses.ascii.ESC:
    +        height, width =3D screen.getmaxyx()
    +        screen.erase()
    +        for y, filename in enumerate(paths[first : first+height]):
    +            color =3D A_REVERSE if file=
    +name =3D=3D paths[selected] else 0
    +            screen.addstr(y, 0, filename=
    +[:width-1], color)
    +        ch =3D screen.getch()
    +        selected +=3D (ch =3D=3D KEY_DOWN) - (ch =3D=3D KEY_UP)
    +        selected =3D max(0, min(len(path=
    +s)-1, selected))
    +        first +=3D (selected >=3D first + height) - (selected < first=
    +)
    +        if ch in [KEY_LEFT, KEY_RIGHT, KEY_ENTER, ord('\n'), ord('\r')]:
    +            new_dir =3D '..' if ch =3D=3D KEY_LEFT else paths[selected]
    +            if os.path.isdir(new_dir):
    +                os.chdir(new_dir)
    +                first, selected, paths =3D 0, 0, os.listdir()
    +
    +if __name__ =3D=3D '__main__':
    +    curses.wrapper(main)
    +
    + + +

    #Logging

    import logging
    +
    + +
    logging.basicConfig(filena=
    +me=3D<path>)              # Configures t=
    +he root logger.
    +logging.debug/info/warning/error/critical(<str>)  # Logs to the root logger.
    +<Logger> =3D logging.getLogger(__name__)            # Logger named after the module.
    +<Logger>.<level>(<str>)                           # Messages propagate to the root logger.
    +<Logger>.exception(<str>)                         # Calls error() with caught exception.
    +
    +

    Setup

    logging.basicConfig(
    +    filename=3DNone,                   =
    +             # Logs to console by default.
    +    format=3D'%(levelname)s:%(name)s:%(message)=
    +s',  # Add `%(asctime)s` for datetime.<=
    +/span>
    +    level=3Dlogging.WARNING,                        # Drops messages with lower priority.
    +    handlers=3D[logging.StreamHandler()]            # Uses FileHandler if filename is set.
    +)
    +
    + +
    <Formatter> =3D logg=
    +ing.Formatter('<format>')       # Creates a Formatter.
    +<Handler> =3D logging.FileHandler(<path>)           # Creates a Handler.
    +<Handler>.setFormatter(<Formatter>)               # Adds Formatter to the Handler.
    +<Handler>.setLevel(<int/str>)                     # Processes all messages by default.
    +<Logger>.addHandler(<Handler>)                    # Adds Handler to the Logger.
    +<Logger>.setLevel(<int/str>)                      # What is sent to handlers and parent.
    +
    +
      +
    • Parent logger can be specified by naming the child logger '<parent>.<name= +>'.
    • +
    • Formatter also supports: pathname, filename, funcName, lineno, = +thread and process.
    • +
    • A 'hand= +lers.RotatingFileHandler' creates and deletes log files based= + on 'maxBytes' and 'backupCount' arguments.
    • +
    +

    Creates a logger that writes all messages to a= + file and sends them to the root logger that prints to stdout:

    >>=
    +> logging.basicConfig(level=3D'WARNIN=
    +G')
    +>>> logger =3D logging.getLogger(=
    +'my_module')
    +>>> handler =3D logging.FileHandl=
    +er('test.log')
    +>>> formatter =3D logging.Formatt=
    +er('%(asctime)s %(levelname)s:%(name)s:%(messag=
    +e)s')
    +>>> handler.setFormatter(formatte=
    +r)
    +>>> logger.addHandler(handler)
    +>>> logger.critical('Running out of disk space.')
    +CRITICAL:my_module:Running out of disk space.
    +>>> print(open('test.log').read())
    +2023-02-07 23:21:01,430 CRITICAL:my_module:Running out of disk space.
    +
    + +

    #Scraping

    Scrapes Python's URL, vers= +ion number and logo from its Wikipedia page:

    # $ pip3 install reques=
    +ts beautifulsoup4
    +import requests, bs4, os, sys
    +
    +WIKI_URL =3D 'https://en.wikipedia.org/wiki/Pyt=
    +hon_(programming_language)'
    +try:
    +    html       =3D requests.get(WIKI_URL).text
    +    document   =3D bs4.BeautifulSoup(html, 'htm=
    +l.parser')
    +    table      =3D document.find('table'=
    +, class_=3D'infobox vevent')
    +    python_url =3D table.find('th', text=
    +=3D'Website').next_sibling.a['href']
    +    version    =3D table.find('th', text=
    +=3D'Stable release').next_sibling.string=
    +s.__next__()
    +    logo_url   =3D table.find('img')['src']
    +    logo       =3D requests.get(f'https:{logo_url}').content
    +    filename   =3D os.path.basename(logo_url)
    +    with open(filename, 'wb') as file:
    +        file.write(logo)
    +    print(f'{python_=
    +url}, {version}, file://{os.path.abspath(filename)}')
    +except requests.exceptions.ConnectionEr=
    +ror:
    +    print("You've got problems with connection.=
    +", file=3Dsys.stderr)
    +
    + + +

    #Web

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

    # $ pip3 install flask
    +from flask import Flask, send_from_directory, render_template_string, request
    +
    + + +
    app =3D Flask(__name__)
    +app.run(host=3DNone, debug=3DNone)
    +
    +
      +
    • Starts the app at 'http://localhost:5000'. Use 'host=3D"0.0.0.0"' to run = +externally.
    • +
    • Install a WSGI server like Waitress and a HTTP server such= + as Nginx for better security.
    • +
    • Debug mode restarts the app whenever script changes and display= +s errors in the browser.
    • +
    +

    Static Request

    @app.route('/img/<path:=
    +filename>')
    +def serve_file(filenam=
    +e):
    +    return send_from_directory('dirname/', filename)
    +
    + +

    Dynamic Request

    @app.route('/<sport&g=
    +t;')
    +def serve_html(sport)<=
    +/span>:
    +    return render_template_string('<h1>{{title}}</h1>', title=3Dspo=
    +rt)
    +
    + +
      +
    • To return an error code use 'abort(<int>)' and to redirect use= + 'redirect(<url&= +gt;)'.
    • +
    • 'reques= +t.args[<str>]' returns parameter from the query string = +(URL part after '?').
    • +
    • Use 'se= +ssion[key] =3D value' to store session data like username, et= +c.
    • +
    +

    REST Request

    @app.post('/<sport>/odds=
    +')
    +def serve_json(sport)<=
    +/span>:
    +    team =3D request.form['team']
    +    return {'team': team, 'odds': [2.09, 3.74, 3.68]}
    +
    + +

    Star= +ts the app in its own thread and queries it with a post request:

    <=
    +code class=3D"python language-python hljs"># $=
    + pip3 install requests
    +>>> =
    +import threading, requests
    +>>> threading.Thread(target=3Dapp=
    +.run, daemon=3DTrue).start()
    +>>> url =3D 'http://localhost:5000/football/odds'
    +>>> request_data =3D {'team': 'arsenal f.c.'<=
    +/span>}
    +>>> response =3D requests.post(ur=
    +l, data=3Drequest_data)
    +>>> response.json()
    +{'team': 'ar=
    +senal f.c.', 'odds': [2.09, 3.74, 3.68]}
    +
    + +

    #Profiling

    from time <=
    +span class=3D"hljs-keyword">import perf_counter
    +start_time =3D perf_counter()
    +...
    +duration_in_seconds =3D perf_counter() - start_time
    +
    + +

    Timing a Snippet

    >>> from timeit i=
    +mport timeit
    +>>> timeit('list(range(10000))', number=3D100=
    +0, globals=3Dglobals(), setup=3D'pass')
    +0.19373
    +
    + +

    Profiling by Line

    $ pip3 install line_profiler
    +$ echo "@profile
    +def main():
    +    a =3D list(range(10000))
    +    b =3D set(range(10000))
    +main()" > test.py
    +$ kernprof -lv test.py
    +Line #   Hits     Time  Per Hit   % Time  Line Contents
    +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
    +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
    +=3D=3D=3D=3D=3D
    +     1                                    @profile
    +     2                                    def main():
    +     3      1    219.0    219.0     31.1      a =3D list(range(10000))
    +     4      1    487.0    487.0     68.9      b =3D set(range(10000))
    +
    + +

    Call and Flame Graphs

    $ pip3 install gprof2dot snakeviz; apt/brew insta=
    +ll graphviz
    +$ tail -n 4 test.py > test.py
    +$ python3 -m cProfile -o test.prof test.py
    +$ gprof2dot -f pstats test.prof | dot -Tpng -o test.png; xdg-open/open test=
    +.png
    +$ snakeviz test.prof
    +
    + +

    Sampling and Memory Profilers
    =E2=94=8F=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=93
    +=E2=94=83 pip3 install =E2=94=82          How to run           =E2=94=82   =
    +Target   =E2=94=82   Type   =E2=94=82 Live =E2=94=83
    +=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=A8
    +=E2=94=83 py-spy       =E2=94=82 py-spy top -- python3 test.py =E2=94=82   =
    + CPU     =E2=94=82 Sampling =E2=94=82 Yes  =E2=94=83
    +=E2=94=83 pyinstrument =E2=94=82 pyinstrument test.py          =E2=94=82   =
    + CPU     =E2=94=82 Sampling =E2=94=82 No   =E2=94=83
    +=E2=94=83 scalene      =E2=94=82 scalene test.py               =E2=94=82 CP=
    +U+Memory =E2=94=82 Sampling =E2=94=82 No   =E2=94=83
    +=E2=94=83 memray       =E2=94=82 memray run --live test.py     =E2=94=82   =
    +Memory   =E2=94=82 Tracing  =E2=94=82 Yes  =E2=94=83
    +=E2=94=83 filprofiler  =E2=94=82 fil-profile run test.py       =E2=94=82   =
    +Memory   =E2=94=82 Tracing  =E2=94=82 No   =E2=94=83
    +=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=9B
    +

    + +

    #NumPy

    Array manipulation mini-la= +nguage. It can run up to one hundred times faster than the equivalent Pytho= +n code. An even faster alternative that runs on a GPU is called CuPy.

    # $ pip3 install numpy
    +import numpy as np
    +
    + + +
    <array> =3D np.array=
    +(<list/list_of_lists>)                # =
    +Returns a 1d/2d NumPy array.
    +<array> =3D np.zeros/ones(<shape>)                        # Also np.full(<shape>, <el>).
    +<array> =3D np.arange(from_inc, to_exc, =C2=B1step)            # Also np.linspace(start, stop, len).
    +<array> =3D np.random.randint(from_inc, to_exc, <shape>)  # Also np.random.random(<shape>).
    +
    +
    <view>  =3D <arra=
    +y>.reshape(<shape>)                      # Also `<array>.shape =3D <shape>`.
    +<array> =3D <array>.flatten()                             # Also `<view> =3D <array>.ravel()`.
    +<view>  =3D <array>.transpose()                           # Or: <array>.T
    +
    +
    <array> =3D np.copy/=
    +abs/sqrt/log/int64(<array>)           # =
    +Returns new array of the same shape.
    +<array> =3D <array>.sum/max/mean/argmax/all(axis)         # Passed dimension gets aggregated.
    +<array> =3D np.apply_along_axis(<func>, axis, <array>)   =
    + # Func can return a scalar or array.
    +
    +
    <array> =3D np.conca=
    +tenate(<list_of_arrays>, axis=3D0)=
    +      # Links arrays along first axis (rows).<=
    +/span>
    +<array> =3D np.row_stack/column_stack(<list_of_arrays>)   # Treats 1d arrays as rows or columns.
    +<array> =3D np.tile/repeat(<array>, <int/list>)          =
    + # Tiles array or repeats its elements.
    +
    +
      +
    • Shape is a tuple of dimension sizes. A 100x50 RGB image has sha= +pe (50, 100, 3).
    • +
    • Axis is an index of the dimension that gets aggregated. Leftmos= +t dimension has index 0. Summing the RGB image along axis 2 will return a g= +reyscale image with shape (50, 100).
    • +
    +

    Indexing

    <el=
    +>       =3D <2d_array>[row_index, column_index]        # <3d_a>[table_i, row_i, column_i]
    +<1d_view>  =3D <2d_array>[row_index]                      # <3d_a>[table_i, row_i]
    +<1d_view>  =3D <2d_array>[:, column_index]                # <3d_a>[table_i, :, column_i]
    +<2d_view>  =3D <2d_array>[rows_slice, columns_slice]      # <3d_a>[table_i, rows_s, columns_s]
    +
    + +
    <2d_array> =3D <2d_array>[row_in=
    +dexes]                    # <3d_a>[table=
    +_i/is, row_is]
    +<2d_array> =3D <2d_array>[:, column_indexes]              # <3d_a>[table_i/is, :, column_is]
    +<1d_array> =3D <2d_array>[row_indexes, column_indexes]    # <3d_a>[table_i/is, row_is, column_is]
    +<1d_array> =3D <2d_array>[row_indexes, column_index]      # <3d_a>[table_i/is, row_is, column_i]
    +
    +
    <2d_bools> =3D <2d_array> >&l=
    +t;=3D=3D <el/1d/2d_array>           # 1d=
    +_array must have size of a row.
    +<1d/2d_a>  =3D <2d_array>[<2d/1d_bools>]                 =
    + # 1d_bools must have size of a column.
    +
    +
      +
    • Indexes should not be tuples because Python converts 'obj[i, j]' to= + 'obj[(i, j)]'!
    • +
    • Any value that is broadcastable to the indexed shape can be ass= +igned to the selection.
    • +
    +

    Broadcasting

    Set of rules by wh= +ich NumPy functions operate on arrays of different sizes and/or dimensions.= +

    left  =3D [[<=
    +span class=3D"hljs-number">0.1], [0.6], [0.8]]                           =
    +# Shape: (3, 1)
    +right =3D [ 0.1 ,  0.6 ,  0.8 ]              =
    +             # Shape: (3,)
    +
    + + +

    = +1. If array shapes differ in length, left-pad the shorter shape with ones:<= +/h4>
    left  =3D [[0.1], [0.6], [<=
    +span class=3D"hljs-number">0.8]]                           # Shape: (3, 1)
    +right =3D [[0.1 ,  0.6 ,  0.8]]              =
    +             # Shape: (1, 3) <- !
    +

    + +

    2. If any dimensions differ in size, expand the ones = +that have size 1 by duplicating their elements:

    left  =3D [[0.1,  0.1,  0.=
    +1],                             # Shape=
    +: (3, 3) <- !
    +         [0.6,  0.6,  0.6],
    +         [0.8,  0.8,  0.8]]
    +
    +right =3D [[0.1,  0.6,  0.8],                =
    +             # Shape: (3, 3) <- !
    +         [0.1,  0.6,  0.8],
    +         [0.1,  0.6,  0.8]]
    +
    + +

    Example

    For each point returns index of its nearest p= +oint ([0.1, = +0.6, 0.8] =3D> [1, 2, 1]):

    >>&=
    +gt; points =3D np.array([0.1, 0.6, 0.8=
    +])
    + [ 0.1,  0.6=
    +,  0.8]
    +>>> wrapped_points =3D points.res=
    +hape(3, 1)
    +[[ 0.1],
    + [ 0.6],
    + [ 0.8]]
    +>>> distances =3D wrapped_points =
    +- points
    +[[ 0. , -0.5=
    +, -0.7],
    + [ 0.5,  0.<=
    +/span> , -0.2],
    + [ 0.7,  0.2=
    +,  0. ]]
    +>>> distances =3D np.abs(distance=
    +s)
    +[[ 0. ,  0.5=
    +,  0.7],
    + [ 0.5,  0.<=
    +/span> ,  0.2],
    + [ 0.7,  0.2=
    +,  0. ]]
    +>>> i =3D np.arange(3)
    +[0, 1=
    +, 2]
    +>>> distances[i, i] =3D np.inf
    +[[ inf,  0.5,  0.7],
    + [ 0.5,  inf,  0.2],
    + [ 0.7,  0.2=
    +,  inf]]
    +>>> distances.argmin(1)
    +[1, 2=
    +, 1]
    +
    + + +

    #Image

    # $ pip3 install pillow
    +from PIL i=
    +mport Image, ImageDraw
    +
    + +
    <Image> =3D Image.ne=
    +w('<mode>', (width, height))  # Also `color=3D<int/tuple/str>`.
    +<Image> =3D Image.open(<path>)                    # Identifies format based on file contents.
    +<Image> =3D <Image>.convert('<mo=
    +de>')             # Converts image t=
    +o the new mode.
    +<Image>.save(<path>)                            # Selects format based on the path extension.
    +<Image>.show()                                  # Opens image in the default preview app.
    +
    +
    <int/tuple> =3D <=
    +Image>.getpixel((x, y))          # Returns =
    +a pixel.
    +<Image>.putpixel((x, y), <int/tuple>)           # Writes a pixel to the image.
    +<ImagingCore> =3D <Image>.getdata()               # Returns a flattened view of the pixels.
    +<Image>.putdata(<list/ImagingCore>)             # Writes a flattened sequence of pixels.
    +<Image>.paste(<Image>, (x, y))                  # Writes passed image to the image.
    +
    +
    <Image> =3D <Imag=
    +e>.filter(<Filter>)              # `&=
    +lt;Filter> =3D ImageFilter.<name>([<args>])`
    +<Image> =3D <Enhance>.enhance(<float>)            # `<Enhance> =3D ImageEnhance.<name>(<=
    +Image>)`
    +
    +
    <array> =3D np.array=
    +(<Image>)                     # Creates =
    +NumPy array from the image.
    +<Image> =3D Image.fromarray(np.uint8(<array>))    # Use <array>.clip(0, 255) to clip the values.
    +
    +

    Modes

      +
    • '1' - 1-bit pixels, black and white, stored with one pixel per byte.= +
    • +
    • 'L' - 8-bit pixels, greyscale.
    • +
    • 'RGB' - 3x8-bit pixels, true color.
    • +
    • 'RGBA'<= +/span> - 4x8-bit pixels, true color with transparency mask.= +
    • +
    • 'HSV' - 3x8-bit pixels, Hue, Saturation, Value color space.= +
    • +

    Examples

    Creates a PNG image of a rainbow gradient:

    WIDTH, HEIGHT =3D 100, 100
    +n_pixels =3D WIDTH * HEIGHT
    +hues =3D (255 * i/n_pixels for i in range=
    +(n_pixels))
    +img =3D Image.new('HSV', (WIDTH, HEIGHT)=
    +)
    +img.putdata([(int(h), 255, 255) for h in hues])
    +img.convert('RGB').save('test.png')
    +
    + + + + +

    Adds noise to a PNG image:

    from=
    + random import randint
    +add_noise =3D lambda value: max(0, min(255, =
    +value + randint(-20, 20)))
    +img =3D Image.open('test.png').convert(<=
    +span class=3D"hljs-string">'HSV')
    +img.putdata([(add_noise(h), s, v) for h=
    +, s, v in img.getdata()])
    +img.show()
    +
    + +

    Image Draw

    <ImageDraw> =3D ImageDraw.Draw(<Image>)         =
    +  # Object for adding 2D graphics to the image=
    +.
    +<ImageDraw>.point((x, y))                       # Draws a point. Truncates floats into ints.
    +<ImageDraw>.line((x1, y1, x2, y2 [, ...]))      # To get anti-aliasing use Image's resize().
    +<ImageDraw>.arc((x1, y1, x2, y2), deg1, deg2)   # Always draws in clockwise direction.
    +<ImageDraw>.rectangle((x1, y1, x2, y2))         # To rotate use Image's rotate() and paste().
    +<ImageDraw>.polygon((x1, y1, x2, y2, ...))      # Last point gets connected to the first.
    +<ImageDraw>.ellipse((x1, y1, x2, y2))           # To rotate use Image's rotate() and paste().
    +<ImageDraw>.text((x, y), text, font=3D<Font>)     # `<Font> =3D ImageFont.truetype(<path>, size=
    +)`
    +
    + +
      +
    • Use 'fi= +ll=3D<color>' to set the primary color.
    • +
    • Use 'wi= +dth=3D<int>' to set the width of lines or contours.
    • +
    • Use 'ou= +tline=3D<color>' to set the color of the contours.
    • +
    • Color can be an int, tuple, '#rrggbb[aa]' string or a color name.
    • +
    +

    #Animation

    Creates a GIF of a bouncing ball:

    # $ pip3 ins=
    +tall imageio
    +from PIL i=
    +mport Image, ImageDraw
    +import imageio
    +
    +WIDTH, HEIGHT, R =3D 126, 126, 10
    +frames =3D []
    +for velocity in range(1, 16):
    +    y =3D sum(range(velocity))
    +    frame =3D Image.new('L', (WIDTH, HEI=
    +GHT))
    +    draw  =3D ImageDraw.Draw(frame)
    +    draw.ellipse((WIDTH/2-R, y, WIDTH/2+R, y+R*2), fill=3D'white')
    +    frames.append(frame)
    +frames +=3D reversed(frames[1:-1])
    +imageio.mimsave('test.gif', frames, dura=
    +tion=3D0.03)
    +
    + + +

    #Audio

    import wave
    +
    + +
    <Wave_read>  =3D wav=
    +e.open('<path>', 'rb')        # Opens the WAV=
    + file.
    +framerate    =3D <Wave_read>.getframerate()       # Number of frames per second.
    +nchannels    =3D <Wave_read>.getnchannels()       # Number of samples per frame.
    +sampwidth    =3D <Wave_read>.getsampwidth()       # Sample size in bytes.
    +nframes      =3D <Wave_read>.getnframes()         # Number of frames.
    +<params>     =3D <Wave_read>.getparams()          # Immutable collection of above.
    +<bytes>      =3D <Wave_read>.readframes(nframes)  # Returns next 'nframes' frames.
    +
    +
    <Wave_write> =3D wav=
    +e.open('<path>', 'wb')        # Truncates exi=
    +sting file.
    +<Wave_write>.setframerate(<int>)                # 44100 for CD, 48000 for video.
    +<Wave_write>.setnchannels(<int>)                # 1 for mono, 2 for stereo.
    +<Wave_write>.setsampwidth(<int>)                # 2 for CD quality sound.
    +<Wave_write>.setparams(<params>)                # Sets all parameters.
    +<Wave_write>.writeframes(<bytes>)               # Appends frames to the file.
    +
    +
      +
    • Bytes object contains a sequence of frames, each consisting of = +one or more samples.
    • +
    • In a stereo signal, the first sample of a frame belongs to the = +left channel.
    • +
    • Each sample consists of one or more bytes that, when converted = +to an integer, indicate the displacement of a speaker membrane at a given m= +oment.
    • +
    • If sample width is one byte, then the integer should be encoded= + unsigned.
    • +
    • For all other sizes, the integer should be encoded signed with = +little-endian byte order.
    • +
    +

    Sample Values

    =E2=94=8F=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=93
    +=E2=94=83 sampwidth =E2=94=82    min    =E2=94=82 zero =E2=94=82    max    =
    +=E2=94=83
    +=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=A8
    +=E2=94=83     1     =E2=94=82         0 =E2=94=82  1=
    +28 =E2=94=82       255 =E2=94=83
    +=E2=94=83     2     =E2=94=82    -32768 =E2=94=82    0 =E2=94=82     32767 =E2=94=83
    +=E2=94=83     3     =E2=94=82  -8388608 =E2=94=82    0 =E2=94=82   8388607 =E2=94=83
    +=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=9B
    +
    + +

    Read Float Samples from WAV Fil= +e

    def read_wav_file(filename):
    +    def <=
    +span class=3D"hljs-title">get_int(bytes_=
    +obj):
    +        an_int =3D int.from_bytes(bytes_obj, 'l=
    +ittle', signed=3D(sampwidth !=3D 1))
    +        return an_int - 128 * (sampwidth =3D=3D 1)
    +    with wave.open(filename, 'rb') as file:
    +        sampwidth =3D file.getsampwidth()
    +        frames =3D file.readframes(-1)
    +    bytes_samples =3D (frames[i : i+sampwidth] for i in range(0, len(frames), sampwidth))
    +    return [get_int(b) / pow(2, sampwidth * 8 - 1) for<=
    +/span> b in bytes_samples]
    +
    + +

    Write Float Samples to WAV File<= +/h3>
    def =
    +write_to_wav_file(filename, float_sample=
    +s, nchannels=3D1, sampwidth=3D2, framerate=3D44100):
    +    def <=
    +span class=3D"hljs-title">get_bytes(a_fl=
    +oat):
    +        a_float =3D max(-1, min(1 - 2e-16, a_=
    +float))
    +        a_float +=3D sampwidth =3D=3D 1
    +        a_float *=3D pow(2, sampwidth * =
    +8 - 1=
    +)
    +        return int(a_float).to_bytes(sa=
    +mpwidth, 'little', signed=3D(sampwidth !=
    +=3D 1))
    +    with wave.open(filename, 'wb') as file:
    +        file.setnchannels(nchannels)
    +        file.setsampwidth(sampwidth)
    +        file.setframerate(framerate)
    +        file.writeframes(b''.join(get_by=
    +tes(f) for f in float_samples))
    +

    + +

    Examples

    Saves a 440 Hz sine wave to a mono WAV file:

    from math import pi, sin
    +samples_f =3D (sin(i * 2 * pi * 440 / 44100) =
    +for i in range(100_000))
    +write_to_wav_file('test.wav', samples_f)
    +
    + + +

    Adds noise to a mono WAV file:

    = +
    from random import random
    +add_noise =3D lambda value: value + (ra=
    +ndom() - 0.5) * 0.03
    +samples_f =3D (add_noise(f) for f in read_wav_file('test.wav'))
    +write_to_wav_file('test.wav', samples_f)
    +
    + +

    Plays a WAV file:

    # $ pip3 install sim=
    +pleaudio
    +from simpleaudio import play_buffer
    +with wave.open('test.wav', 'rb') as file:
    +    p =3D file.getparams()
    +    frames =3D file.readframes(-1)
    +    play_buffer(frames, p.nchannels, p.sampwidth, p.framerate)
    +
    + +

    Text to Speech

    # $ pip3 install pyttsx3=
    +
    +import pyttsx3
    +engine =3D pyttsx3.init()
    +engine.say('Sally sells seashells by the seasho=
    +re.')
    +engine.runAndWait()
    +
    + +

    #Synthesizer

    Plays Popcorn by Gershon Kingsley:

    <= +pre># $ pip3 install simpleaudio +import array, itertools as it, math, simpleaudio + +F =3D 44100 +P1 =3D '71=E2=99=A9,69=E2=99=AA,,71=E2=99=A9,66= +=E2=99=AA,,62=E2=99=A9,66=E2=99=AA,,59=E2=99=A9,,' +P2 =3D '71=E2=99=A9,73=E2=99=AA,,74=E2=99=A9,73= +=E2=99=AA,,74=E2=99=AA,,71=E2=99=AA,,73=E2=99=A9,71=E2=99=AA,,73=E2=99=AA,,= +69=E2=99=AA,,71=E2=99=A9,69=E2=99=AA,,71=E2=99=AA,,67=E2=99=AA,,71=E2=99=A9= +,,' +get_pause =3D lambda seconds: it.repe= +at(0, int(seconds * F)) +sin_f =3D lambda i, hz: math.sin(= +i * 2 * math.pi * hz / F) +get_wave =3D lambda hz, seconds: (si= +n_f(i, hz) for i in range(int(seconds * F))) +get_hz =3D lambda key: 8.176 * 2 ** (in= +t(key) / 12) +parse_note =3D lambda note: (get_hz(no= +te[:2]), 1/4 if<= +/span> '=E2=99=A9' in note else 1/8) +get_samples =3D lambda note: get_wave(*= +parse_note(note)) if note else get_pause(1/8) +samples_f =3D it.chain.from_iterable(get_samples(n) for n in f'{P1},{P1},{P2}'.split(',')) +samples_i =3D array.array('h', (int(f = +* 30000) fo= +r f in samples_f)) +simpleaudio.play_buffer(samples_i, 1, 2, F) +
    + + +

    #Pygame

    # $ pip3 install pygame
    +import pygame as pg
    +
    +pg.init()
    +screen =3D pg.display.set_mode((500, 500))
    +rect =3D pg.Rect(240, 240, 20, 20)
    +while not<=
    +/span> pg.event.get(pg.QUIT):
    +    deltas =3D {pg.K_UP: (0, -20), pg.K_RIGHT: (20, 0), pg.K_DOWN: (0, 20), pg.K_LEFT: (-20, 0)=
    +}
    +    for event in pg.event.get(pg.KEYDOWN):
    +        dx, dy =3D deltas.get(event.key, (0, 0))
    +        rect =3D rect.move((dx, dy))
    +    screen.fill((0, 0, 0))
    +    pg.draw.rect(screen, (255, 255, 255), rec=
    +t)
    +    pg.display.flip()
    +
    + +

    Rectangle

    Object for storing recta= +ngular coordinates.

    <Rect> =3D pg.Rect(x, y, width, height)           # Floats get truncated into ints.
    +<int>  =3D <Rect>.x/y/centerx/centery/=E2=80=A6           # Top, right, bottom, left. Allows assignments.
    +<tup.> =3D <Rect>.topleft/center/=E2=80=A6                # Topright, bottomright, bottomleft. Same.
    +<Rect> =3D <Rect>.move((delta_x, delta_y))        # Use move_ip() to move in-place.
    +
    + + +
    <bool> =3D <Rect&=
    +gt;.collidepoint((x, y))            # Checks i=
    +f rectangle contains the point.
    +<bool> =3D <Rect>.colliderect(<Rect>)             # Checks if two rectangles overlap.
    +<int>  =3D <Rect>.collidelist(<list_of_Rect>)     # Returns index of first colliding Rect or -1.
    +<list> =3D <Rect>.collidelistall(<list_of_Rect>)  # Returns indexes of all colliding rectangles.
    +
    +

    Surface

    Object for representing imag= +es.

    <Surf&g=
    +t; =3D pg.display.set_mode((width, height))   =
    +# Opens new window and returns its surface.
    +<Surf> =3D pg.Surface((width, height))            # New RGB surface. RGBA if `flags=3Dpg.SRCALPHA`.
    +<Surf> =3D pg.image.load(<path/file>)             # Loads the image. Format depends on source.
    +<Surf> =3D pg.surfarray.make_surface(<np_array>)  # Also `<np_arr> =3D surfarray.pixels3d(<Surf>=
    +;)`.
    +<Surf> =3D <Surf>.subsurface(<Rect>)              # Creates a new surface from the cutout.
    +
    + + +
    <Surf>.fill(color)  =
    +                            # Tuple, Color('#r=
    +rggbb[aa]') or Color(<name>).
    +<Surf>.set_at((x, y), color)                    # Updates pixel. Also <Surf>.get_at((x, y)).
    +<Surf>.blit(<Surf>, (x, y))                     # Draws passed surface to the surface.
    +
    +
    from pygame.transform import =
    +scale, ...
    +<Surf> =3D scale(<Surf>, (width, height))         # Returns scaled surface.
    +<Surf> =3D rotate(<Surf>, anticlock_degrees)      # Returns rotated and scaled surface.
    +<Surf> =3D flip(<Surf>, x_bool, y_bool)           # Returns flipped surface.
    +
    +
    from pygame.draw import line,=
    + ...
    +line(<Surf>, color, (x1, y1), (x2, y2), width)  # Draws a line to the surface.
    +arc(<Surf>, color, <Rect>, from_rad, to_rad)    # Also ellipse(<Surf>, color, <Rect>, width=3D0).=
    +
    +rect(<Surf>, color, <Rect>, width=3D0)            # Also polygon(<Surf&=
    +gt;, color, points, width=3D0).
    +
    +

    Font

    <Font> =3D pg.font.Font(<path/file>, size)        # Loads TTF file. Pass None for default font.
    +<Surf> =3D <Font>.render(text, antialias, color)  # Background color can be specified at the end.
    +
    + +

    Sound

    <Sound> =3D pg.mixer.Sound(<path/file/bytes>)     # Loads WAV file or array of signed shorts.
    +<Sound>.play/stop()                             # Also <Sound>.set_volume(<float>).
    +
    + +

    Basic Mario Brothers Example

    = +
    import collections, dataclasses, enum, io, itertools as it, pygame as pg, urllib.request
    +from random import randint
    +
    +P =3D collections.namedtuple('P', 'x y')          #=
    + Position
    +D =3D enum.Enum('D', 'n e s w')                   #=
    + Direction
    +W, H, MAX_S =3D 50, 50, P(5, 10)                  # Widt=
    +h, Height, Max speed
    +
    +def main():
    +    def <=
    +span class=3D"hljs-title">get_screen():
    +        pg.init()
    +        return pg.display.set_mode((W*<=
    +span class=3D"hljs-number">16, H*16))
    +    def <=
    +span class=3D"hljs-title">get_images():
    +        url =3D 'https://gto76.github.io/python=
    +-cheatsheet/web/mario_bros.png'
    +        img =3D pg.image.load(io.BytesIO(urllib.request.urlopen(url).read()=
    +))
    +        return [img.subsurface(get_rect=
    +(x, 0)) for=
    + x in range(img.get_width() // <=
    +span class=3D"hljs-number">16)]
    +    def <=
    +span class=3D"hljs-title">get_mario():
    +        Mario =3D dataclasses.make_dataclass('M=
    +ario', 'rect spd facing_left frame_cycle=
    +'.split())
    +        return Mario(get_rect(1, 1), P(0, 0), False, it.cycle(range(3)))
    +    def <=
    +span class=3D"hljs-title">get_tiles():
    +        border =3D [(x, y) for x in range(W) for<=
    +/span> y in range(H) if x in [0, W-1] or y in [0, H-1]=
    +]
    +        platforms =3D [(randint(1, W-2), randint(2, H-2)) for _ in range(W*H // 10)]
    +        return [get_rect(x, y) for x, y in=
    + border + platforms]
    +    def <=
    +span class=3D"hljs-title">get_rect(x, y)=
    +:
    +        return pg.Rect(x*16, y*16, 16, 16)
    +    run(get_screen(), get_images(), get_mario(), get_tiles())
    +
    +def run(screen, images=
    +, mario, tiles):
    +    clock =3D pg.time.Clock()
    +    pressed =3D set()
    +    while =
    +not pg.event.get(pg.QUIT) and cl=
    +ock.tick(28):
    +        keys =3D {pg.K_UP: D.n, pg.K_RIGHT: D.e, pg.K_DOWN: D.s, pg.K_LEFT:=
    + D.w}
    +        pressed |=3D {keys.get(e.key) for e in pg.event.get(pg.KEYDOWN)}
    +        pressed -=3D {keys.get(e.key) for e in pg.event.get(pg.KEYUP)}
    +        update_speed(mario, tiles, pressed)
    +        update_position(mario, tiles)
    +        draw(screen, images, mario, tiles, pressed)
    +
    +def update_speed(mario=
    +, tiles, pressed):
    +    x, y =3D mario.spd
    +    x +=3D 2 * ((D.e in pressed) - (D.w in =
    +pressed))
    +    x +=3D (x < 0) - (x > 0)
    +    y +=3D 1 if D.s not in get_boundaries(mario.rect, tiles) else (D.n in pressed) * =
    +-10
    +    mario.spd =3D P(x=3Dmax(-MAX_S.x, min(MAX_S.x, x)), y=3Dmax(-MAX_S.y, m=
    +in(MAX_S.y, y)))
    +
    +def update_position(ma=
    +rio, tiles):
    +    x, y =3D mario.rect.topleft
    +    n_steps =3D max(abs(s) for s in mario.spd)
    +    for _ =
    +in range(n_steps):
    +        mario.spd =3D stop_on_collision(mario.spd, get_boundaries(mario.rec=
    +t, tiles))
    +        mario.rect.topleft =3D x, y =3D x + (mario.spd.x / n_steps), y + (m=
    +ario.spd.y / n_steps)
    +
    +def get_boundaries(rec=
    +t, tiles):
    +    deltas =3D {D.n: P(0, -1), D.e: P(1, 0), D.s: P(0, 1), D.w: P(-1, 0)}
    +    return {d for d, delta in deltas.items=
    +() if rect.move(delta).collidelist(tile=
    +s) !=3D -1}
    +
    +def stop_on_collision(=
    +spd, bounds):
    +    return P(x=3D0 if (D.w in bounds and spd.x=
    + < 0) or=
    + (D.e in bounds and spd.x > 0) else spd.x,
    +             y=3D0 if (D.n in bounds and spd.y < 0<=
    +/span>) or (D.s in bounds and spd.y > <=
    +span class=3D"hljs-number">0) else spd.y)
    +
    +def draw(screen, image=
    +s, mario, tiles, pressed):
    +    def <=
    +span class=3D"hljs-title">get_marios_image_index():
    +        if D.s not in get_boundaries(mario=
    +.rect, tiles):
    +            return 4
    +        return next(mario.frame_cycle) =
    +if {D.w, D.e} & pressed else 6
    +    screen.fill((85, 168, 255))
    +    mario.facing_left =3D (D.w in press=
    +ed) if {D.w, D.e} & pressed else mario.facing_left
    +    screen.blit(images[get_marios_image_index() + mario.facing_left * 9], mario.rect)
    +    for t =
    +in tiles:
    +        screen.blit(images[18 if t.x in [0, (W-1=
    +)*16] or t.y in [0, (H-1)*16] else 19], t)
    +    pg.display.flip()
    +
    +if __name__ =3D=3D '__main__':
    +    main()
    +
    + +

    #Pandas

    # $ pip3 install pandas matplo=
    +tlib
    +import pandas as pd, matplotlib.pyplot as =
    +plt
    +
    + +

    Series

    Ordered dictionary with a name= +.

    >>> pd.Series([1=
    +, 2], index=3D['x', 'y'], name=3D'a')
    +x    1
    +y    2
    +Name: a, dtype: int64
    +
    + + +
    <Sr> =3D pd.Series(&=
    +lt;list>)                       # Assigns R=
    +angeIndex starting at 0.
    +<Sr> =3D pd.Series(<dict>)                       # Takes dictionary's keys for index.
    +<Sr> =3D pd.Series(<dict/Series>, index=3D<list>)  # Only keeps items with keys specified in index.
    +
    +
    <el> =3D <Sr>.=
    +loc[key]                           # Or: <S=
    +r>.iloc[index]
    +<Sr> =3D <Sr>.loc[keys]                          # Or: <Sr>.iloc[indexes]
    +<Sr> =3D <Sr>.loc[from_key : to_key_inclusive]   # Or: <Sr>.iloc[from_i : to_i_exclusive]
    +
    +
    <el> =3D <Sr>[=
    +key/index]                         # Or: <S=
    +r>.key
    +<Sr> =3D <Sr>[keys/indexes]                      # Or: <Sr>[<keys_slice/slice>]
    +<Sr> =3D <Sr>[bools]                             # Or: <Sr>.loc/iloc[bools]
    +
    +
    <Sr> =3D <Sr> =
    +><=3D=3D <el/Sr>                       # Returns a Series of bools.
    +<Sr> =3D <Sr> +-*/ <el/Sr>                       # Items with non-matching keys get value NaN.
    +
    +
    <Sr> =3D pd.concat(&=
    +lt;coll_of_Sr>)                 # Concats m=
    +ultiple Series into one long Series.
    +<Sr> =3D <Sr>.combine_first(<Sr>)                # Adds items that are not yet present.
    +<Sr>.update(<Sr>)                              # Updates items that are already present.
    +
    +
    <Sr>.plot.line/area/=
    +bar/pie/hist()             # Generates a Matpl=
    +otlib plot.
    +plt.show()                                     # Displays the plot. Also plt.savefig(<path>).
    +
    +

    Series =E2=80=94 Aggregate, Tra= +nsform, Map:

    <el>=
    +; =3D <Sr>.sum/max/mean/idxmax/all()          # Or: <Sr>.agg(lambda <Sr>: <el>)
    +<Sr> =3D <Sr>.rank/diff/cumsum/ffill/interpl()   # Or: <Sr>.agg/transform(lambda <Sr>: <Sr>=
    +)
    +<Sr> =3D <Sr>.fillna(<el>)                       # Or: <Sr>.agg/transform/map(lambda <el>: =
    +<el>)
    +
    + +
    =
    +>>> sr =3D pd.Series([1,=
    + 2], index=3D['x', 'y'])
    +x    1
    +y    2
    +
    +
    =E2=94=8F=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=93
    +=E2=94=83               =E2=94=82    'sum'    =E2=94=82   ['sum']   =E2=94=82 {<=
    +span class=3D"hljs-string">'s': 'sum'}  =E2=94=83
    +=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=A8
    +=E2=94=83 sr.apply(=E2=80=A6)   =E2=94=82      =
    +3      =E2=94=82    sum  3   =E2=
    +=94=82     s  3      =E2=94=83
    +=E2=94=83 sr.agg(=E2=80=A6)     =E2=94=82             =E2=94=82            =
    + =E2=94=82               =E2=94=83
    +=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=9B
    +
    +=E2=94=8F=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=93
    +=E2=94=83               =E2=94=82    'rank'   =E2=94=82   ['rank']  =E2=94=82 {<=
    +span class=3D"hljs-string">'r': 'rank'} =E2=94=83
    +=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=A8
    +=E2=94=83 sr.apply(=E2=80=A6)   =E2=94=82             =E2=94=82      rank  =
    + =E2=94=82               =E2=94=83
    +=E2=94=83 sr.agg(=E2=80=A6)     =E2=94=82     x  1    =E2=94=82   x     1   =E2=
    +=94=82    r  x  1    =E2=94=83
    +=E2=94=83               =E2=94=82     y  2    =E2=94=82   y     2   =E2=94=82   =
    +    y  2    =E2=94=83
    +=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=9B
    +
    + +
      +
    • Keys/indexes/bools can't be tuples because 'obj[x, y]' is converted = +to 'obj[(x, y)]'!
    • +
    • Methods ffill(), interpolate(), fillna() and dropna() accept 'inplace=3DTrue'.
    • +
    • Last result has a hierarchical index. Use '<Sr>[key_1, key_2]'= + to get its values.
    • +
    +

    DataFrame

    Table with labeled rows = +and columns.

    <=
    +span class=3D"hljs-meta">>>> pd.DataFrame([[1, 2], [3, 4]], index=3D=
    +['a', 'b'], columns=3D['x', 'y'])
    +   x  y
    +a  1  2
    +b  3  4
    +
    + + +
    <DF>    =3D pd.DataF=
    +rame(<list_of_rows>)         # Rows can =
    +be either lists, dicts or series.
    +<DF>    =3D pd.DataFrame(<dict_of_columns>)      # Columns can be either lists, dicts or series.
    +
    +
    <el>    =3D <DF&g=
    +t;.loc[row_key, column_key]        # Or: <D=
    +F>.iloc[row_index, column_index]
    +<Sr/DF> =3D <DF>.loc[row_key/s]                  # Or: <DF>.iloc[row_index/es]
    +<Sr/DF> =3D <DF>.loc[:, column_key/s]            # Or: <DF>.iloc[:, column_index/es]
    +<DF>    =3D <DF>.loc[row_bools, column_bools]    # Or: <DF>.iloc[row_bools, column_bools]
    +
    +
    <Sr/DF> =3D <DF&g=
    +t;[column_key/s]                   # Or: <D=
    +F>.column_key
    +<DF>    =3D <DF>[row_bools]                      # Keeps rows as specified by bools.
    +<DF>    =3D <DF>[<DF_of_bools>]                  # Assigns NaN to False values.
    +
    +
    <DF>    =3D <DF&g=
    +t; ><=3D=3D <el/Sr/DF>                 # Returns DF of bools. Sr is treated as a row.
    +<DF>    =3D <DF> +-*/ <el/Sr/DF>                 # Items with non-matching keys get value NaN.
    +
    +
    <DF>    =3D <DF&g=
    +t;.set_index(column_key)           # Replaces =
    +row keys with values from a column.
    +<DF>    =3D <DF>.reset_index(drop=3DFalse)         # Drops or moves row k=
    +eys to column named index.
    +<DF>    =3D <DF>.sort_index(ascending=3DTrue)      # Sorts rows by row ke=
    +ys. Use `axis=3D1` for cols.
    +<DF>    =3D <DF>.sort_values(column_key/s)       # Sorts rows by the passed column/s. Same.
    +
    +

    DataFrame =E2=80=94 Merge, Join, C= +oncat:

    >>> l =3D pd.DataFrame([[1, 2], [3, 4]], index=3D['a', 'b'], co=
    +lumns=3D['x', 'y'])
    +   x  y
    +a  1  2
    +b  3  4
    +>>> r =3D pd.DataFrame([[4, 5], [6, 7]], in=
    +dex=3D['b', =
    +'c'], columns=3D['y', 'z'])
    +   y  z
    +b  4  5
    +c  6  7
    +
    + +
    =E2=94=8F=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=93
    +=E2=94=83                        =E2=94=82    '=
    +outer'    =E2=94=82   'inner'  =
    +=E2=94=82   'left'   =E2=94=82       Des=
    +cription        =E2=94=83
    +=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=A8
    +=E2=94=83 l.merge(r, on=3D'y',     =E2=
    +=94=82    x   y   z  =E2=94=82 x   y   z  =E2=94=82 x   y   z  =E2=94=82 Me=
    +rges on column if 'on' =E2=94=83
    +=E2=94=83            how=3D=E2=80=A6)      =E2=94=82 0  1   2   .  =E2=94=82 3   4   5  =
    +=E2=94=82 1   2   .  =E2=94=82 or 'left/right_on' are   =E2=94=83
    +=E2=94=83                        =E2=94=82 1  3   4<=
    +/span>   5  =E2=94=82            =E2=94=
    +=82 3   4   5  =E2=94=82 set, else on shared =
    +cols.=E2=94=83
    +=E2=94=83                        =E2=94=82 2  .   6   7  =E2=94=82            =E2=94=82            =E2=94=82 Uses 'inner' by default. =E2=94=83
    +=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=A8
    +=E2=94=83 l.join(r, lsuffix=3D'l', =E2=
    +=94=82    x yl yr  z =E2=94=82            =E2=94=82 x yl yr  z =E2=94=82 Me=
    +rges on row keys.      =E2=94=83
    +=E2=94=83           rsuffix=3D'r', =E2=
    +=94=82 a  1  2  .  . =E2=94=82 x yl yr  z =E2=94=82 =
    +1  2  .  . =E2=94=82 Uses 'left' by default.  =E2=94=83
    +=E2=94=83           how=3D=E2=80=A6)       =E2=94=82 b  3  4  4  5 =E2=94=82 3  4  4  5 =E2=94=
    +=82 3  4  4  5 =E2=94=82 If r is a Series, it is  =E2=94=83
    +=E2=94=83                        =E2=94=82 c  .  .  6  7 =E2=94=82            =
    +=E2=94=82            =E2=94=82 treated as a column.     =E2=94=83
    +=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=A8
    +=E2=94=83 pd.concat([l, r],      =E2=94=82    x   y   z  =E2=94=82     y   =
    +   =E2=94=82            =E2=94=82 Adds rows at the bottom. =E2=94=83
    +=E2=94=83           axis=3D0,      =E2=
    +=94=82 a  1   2   .  =E2=94=82     2      =E2=
    +=94=82            =E2=94=82 Uses 'outer'=
    + by default. =E2=94=83
    +=E2=94=83           join=3D=E2=80=A6)      =E2=94=82 b  3   4   .  =E2=94=82    =
    + 4      =E2=94=82            =E2=94=82 A=
    + Series is treated as a =E2=94=83
    +=E2=94=83                        =E2=94=82 b  .   4   5  =E2=94=82     4      =E2=94=82            =E2=94=82 column. To =
    +add a row use =E2=94=83
    +=E2=94=83                        =E2=94=82 c  .   6   7  =E2=94=82     6      =E2=94=82            =E2=94=82 pd.concat([=
    +l, DF([sr])]).=E2=94=83
    +=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=A8
    +=E2=94=83 pd.concat([l, r],      =E2=94=82    x  y  y  z =E2=94=82         =
    +   =E2=94=82            =E2=94=82 Adds columns at the      =E2=94=83
    +=E2=94=83           axis=3D1,      =E2=
    +=94=82 a  1  2  .  . =E2=94=82 x  y  y  z =E2=94=82            =E2=94=82 right e=
    +nd. Uses 'outer'  =E2=94=83
    +=E2=94=83           join=3D=E2=80=A6)      =E2=94=82 b  3  4  4  5 =E2=94=82 3  4  4  5 =E2=94=
    +=82            =E2=94=82 by default. A Series is  =E2=94=83
    +=E2=94=83                        =E2=94=82 c  .  .  6  7 =E2=94=82            =
    +=E2=94=82            =E2=94=82 treated as a column.     =E2=94=83
    +=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=A8
    +=E2=94=83 l.combine_first(r)     =E2=94=82    x   y   z  =E2=94=82         =
    +   =E2=94=82            =E2=94=82 Adds missing rows and    =E2=94=83
    +=E2=94=83                        =E2=94=82 a  1=
    +   2   .  =E2=94=82            =
    +=E2=94=82            =E2=94=82 columns. Also updates    =E2=94=83
    +=E2=94=83                        =E2=94=82 b  3=
    +   4   5  =E2=94=82            =E2=94=82            =E2=94=82 items that =
    +contain NaN.  =E2=94=83
    +=E2=94=83                        =E2=94=82 c  .   6   7  =E2=94=82            =
    +=E2=94=82            =E2=94=82 R must be a DataFrame.   =E2=94=83
    +=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=9B
    +
    +

    DataFrame =E2=80=94 Aggregat= +e, Transform, Map:

    <=
    +;Sr> =3D <DF>.sum/max/mean/idxmax/all()          # Or: <DF>.apply/agg(lambda <Sr>: <el>)
    +<DF> =3D <DF>.rank/diff/cumsum/ffill/interpl()   # Or: <DF>.apply/agg/transfrm(lambda <Sr>: <S=
    +r>)
    +<DF> =3D <DF>.fillna(<el>)                       # Or: <DF>.applymap(lambda <el>: <el>=
    +;)
    +
    + +
      +
    • All operations operate on columns by default. Pass 'axis=3D1' to pr= +ocess the rows instead.
    • +
    +
    =
    +>>> df =3D pd.DataFrame([[1, 2], [3<=
    +/span>, 4]], index=3D['a', 'b'], columns=3D[<=
    +span class=3D"hljs-string">'x', 'y'])
    +   x  y
    +a  1  2
    +b  3  4
    +
    +
    =E2=94=8F=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=93
    +=E2=94=83                 =E2=94=82    'sum'    =E2=94=82   ['sum']   =E2=94=82 =
    +{'x': 'sum'<=
    +/span>}  =E2=94=83
    +=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=A8
    +=E2=94=83 df.apply(=E2=80=A6)     =E2=94=82             =E2=94=82       x  =
    +y  =E2=94=82               =E2=94=83
    +=E2=94=83 df.agg(=E2=80=A6)       =E2=94=82     x  4    =E2=94=82  sum  4  6  =E2=94=82     x  4      =E2=94=83
    +=E2=94=83                 =E2=94=82     y  6    =E2=94=82             =E2=94=82               =E2=94=83
    +=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=9B
    +
    +=E2=94=8F=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=93
    +=E2=94=83                 =E2=94=82    'rank'   =E2=94=82   ['rank']  =E2=94=82 =
    +{'x': 'rank'=
    +} =E2=94=83
    +=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=A8
    +=E2=94=83 df.apply(=E2=80=A6)     =E2=94=82      x  y   =E2=94=82      x   =
    + y =E2=94=82        x      =E2=94=83
    +=E2=94=83 df.agg(=E2=80=A6)       =E2=94=82   a  1  1   =E2=94=82   rank rank =
    +=E2=94=82     a  1      =E2=94=83
    +=E2=94=83 df.transform(=E2=80=A6) =E2=94=82   b  2  2   =E2=94=82 a    1    1 =E2=94=
    +=82     b  2      =E2=94=83
    +=E2=94=83                 =E2=94=82             =E2=94=82 b    2    2 =E2=94=82=
    +               =E2=94=83
    +=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=9B
    +
    + +
      +
    • Use '&l= +t;DF>[col_key_1, col_key_2][row_key]' to get the fifth res= +ult's values.
    • +
    +

    DataFrame =E2=80=94 Plot, Encode,= + Decode:

    <DF>.pl=
    +ot.line/area/bar/hist/scatter/box()     # Also=
    +: `x=3Dcolumn_key, y=3Dcolumn_key/s`.
    +plt.show()                                     # Displays the plot. Also plt.savefig(<path>).
    +
    + +
    <DF> =3D pd.read_jso=
    +n/html('<str/path/url>')     # Run `$ pip3 install beautifulsoup4 lxml`.
    +<DF> =3D pd.read_csv/pickle/excel('<pa=
    +th/url>')  # Use `sheet_name=3DNone`=
    + to get all Excel sheets.
    +<DF> =3D pd.read_sql('<table/query>=
    +', <conn.>)   # Accepts SQLite3 o=
    +r SQLAlchemy connection.
    +<DF> =3D pd.read_clipboard()                     # Reads a copied table from the clipboard.
    +
    +
    <dict> =3D <DF>=
    +;.to_dict(['d/l/s/=E2=80=A6'])          =
    +   # Returns columns as dicts, lists or series=
    +.
    +<str>  =3D <DF>.to_json/html/csv([<path>])       # Also to_markdown/latex([<path>]).
    +<DF>.to_pickle/excel(<path>)                   # Run `$ pip3 install "pandas[excel]" odfpy`.
    +<DF>.to_sql('<table_name>', =
    +<connection>)      # Accepts SQLite3 or =
    +SQLAlchemy connection.
    +
    +

    GroupBy

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

    &g= +t;>> df =3D pd.DataFrame([[1, 2, 3], [4, 5, 6], [= +7, 8, 6]], list('abc'), list('xyz')) +>>> df.groupby('z').get_group(6) + x y z +b 4 5 6 +c 7 8 6 +
    + + +
    <GB> =3D <DF>.=
    +groupby(column_key/s)              # Splits DF=
    + into groups based on passed column.
    +<DF> =3D <GB>.apply(<func>)                      # Maps each group. Func can return DF, Sr or el.
    +<GB> =3D <GB>[column_key]                        # Single column GB. All operations return a Sr.
    +
    +

    GroupBy =E2=80=94 Aggregate, T= +ransform, Map:

    <DF&=
    +gt; =3D <GB>.sum/max/mean/idxmax/all()          # Or: <GB>.agg(lambda <Sr>: <el>)
    +<DF> =3D <GB>.rank/diff/cumsum/ffill()           # Or: <GB>.transform(lambda <Sr>: <Sr>)
    +<DF> =3D <GB>.fillna(<el>)                       # Or: <GB>.transform(lambda <Sr>: <Sr&g=
    +t;)
    +
    + +
    =
    +>>> gb =3D df.groupby('z')
    +      x  y  z
    +3: a  1  2  3
    +6: b  4  5  6
    +   c  7  8  6
    +
    +
    =E2=94=8F=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=AF=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=AF=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=93
    +=E2=94=83                 =E2=94=82    'sum'    =E2=94=82    'rank'   =E2=94=82 =
    +  ['rank']  =E2=94=82 {'x': 'rank'} =E2=94=83
    +=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=A8
    +=E2=94=83 gb.agg(=E2=80=A6)       =E2=94=82      x   y  =E2=94=82      x  y=
    +   =E2=94=82      x    y =E2=94=82        x      =E2=94=83
    +=E2=94=83                 =E2=94=82  z          =E2=94=82   a  1  1   =E2=94=82=
    +   rank rank =E2=94=82     a  1      =E2=
    +=94=83
    +=E2=94=83                 =E2=94=82  3  =
    + 1   2  =E2=94=82   b  1  1   =E2=94=82 a    1    =
    +1 =E2=94=82     b  1      =E2=94=83
    +=E2=94=83                 =E2=94=82  6  =
    +11  13  =E2=94=82   c  2  2   =E2=94=82 b    1    =
    +1 =E2=94=82     c  2      =E2=94=83
    +=E2=94=83                 =E2=94=82             =E2=94=82             =E2=
    +=94=82 c    2    2 =E2=94=82               =E2=94=83
    +=E2=94=A0=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=
    +=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
    +=94=80=E2=94=80=E2=94=BC=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
    +=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
    +=E2=94=80=E2=94=A8
    +=E2=94=83 gb.transform(=E2=80=A6) =E2=94=82      x   y  =E2=94=82      x  y=
    +   =E2=94=82             =E2=94=82               =E2=94=83
    +=E2=94=83                 =E2=94=82  a   1   2  =E2=94=82   a  1  1   =E2=94=82      =
    +       =E2=94=82               =E2=94=83
    +=E2=94=83                 =E2=94=82  b  11  13  =E2=94=82   b  1  1   =E2=94=82      =
    +       =E2=94=82               =E2=94=83
    +=E2=94=83                 =E2=94=82  c  11  13  =E2=94=82   c  2  2   =E2=94=82      =
    +       =E2=94=82               =E2=94=83
    +=E2=94=97=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=
    +=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=
    +=94=81=E2=94=81=E2=94=B7=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=
    +=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=E2=94=81=
    +=E2=94=81=E2=94=9B
    +
    +

    Rolling

    Object for rolling window ca= +lculations.

    &l=
    +t;RSr/RDF/RGB> =3D <Sr/DF/GB>.rolling(win_size)   # Also: `min_periods=3DNone, center=3DFalse`.
    +<RSr/RDF/RGB> =3D <RDF/RGB>[column_key/s]        # Or: <RDF/RGB>.column_key
    +<Sr/DF>       =3D <R>.mean/sum/max()             # Or: <R>.apply/agg(<agg_func/str>)
    +
    + + +

    #Plotly

    # $ pip3 install plotly kaleid=
    +o
    +from plotly.express import line
    +<Figure> =3D line(<DF>, x=3D<col_name>, y=3D<col_name&=
    +gt;)           # Or: line(x=3D<list>, y=
    +=3D<list>)
    +<Figure>.update_layout(margin=3Ddict(t=3D=
    +0, r=3D0, b=3D0, l=3D0), =E2=80=A6)  <=
    +span class=3D"hljs-comment"># `paper_bgcolor=3D'rgb(0, 0, 0)'`.
    +<Figure>.write_html/json/image('<path&=
    +gt;')                    # Also <Fig=
    +ure>.show().
    +
    + +

    Displays a line chart of total coronavirus deaths per million g= +rouped by continent:

    = += += +Apr 2020Jul 2020= +Oct= + 2020Jan 2021Apr 2021Jul 2021O= +ct 20210500<= +/text>1000150020002500= +
    <= +/g>ContinentSouth America= +North AmericaEuropeAsia= +AfricaOceania<= +rect class=3D"legendtoggle" pointer-events=3D"all" x=3D"0" y=3D"-9.5" width= +=3D"128.52083587646484" height=3D"19" style=3D"cursor: pointer; fill: rgb(0= +, 0, 0); fill-opacity: 0;">DateTotal Deaths per Million
    covid =3D pd.read_csv('h=
    +ttps://covid.ourworldindata.org/data/owid-covid-data.csv',
    +                    usecols=3D['iso_code', 'date', '=
    +total_deaths', 'population'])
    +continents =3D pd.read_csv('https://gist.github=
    +usercontent.com/stevewithington/20a69c0b6d2ff'
    +                         '846ea5d35e5fc47f26c/r=
    +aw/country-and-continent-codes-list-csv.csv',
    +                         usecols=3D['Three_Lett=
    +er_Country_Code', 'Continent_Name'])
    +df =3D pd.merge(covid, continents, left_on=3D'i=
    +so_code', right_on=3D'Three_Letter_Count=
    +ry_Code')
    +df =3D df.groupby(['Continent_Name', 'date']).sum().reset_index()
    +df['Total Deaths per Million'] =3D df.to=
    +tal_deaths * 1e6 / df.population
    +df =3D df[df.date > '2020-03-14']
    +df =3D df.rename({'date': 'Date', 'Continent_Name': 'Continent'}, axis=3D'columns')
    +line(df, x=3D'Date', y=3D'Total Deaths per Million', color=3D'Continent').show()
    +
    + + + +

    Displays a multi-axis line chart of total= + coronavirus cases and changes in prices of Bitcoin, Dow Jones and gold:

    = +<= +rect class=3D"nwdrag drag cursor-nw-resize" data-subplot=3D"xy" x=3D"60" y= +=3D"4" width=3D"20" height=3D"20" style=3D"fill: transparent; stroke-width:= + 0; pointer-events: all;">= += += +<= +path class=3D"y2grid crisp" transform=3D"translate(0,258.90999999999997)" d= +=3D"M80,0h696" style=3D"stroke: rgb(255, 255, 255); stroke-opacity: 1; stro= +ke-width: 1px;">= += +Apr 2020J= +ul 2020Oct 2020Jan 2021Apr 2021Jul 2021Oct 2021050M= +100M150M200M2= +50M0100200<= +/text>300400<= +text text-anchor=3D"start" x=3D"779.4" y=3D"4.199999999999999" data-unforma= +tted=3D"500" data-math=3D"N" transform=3D"translate(0,106.53)" style=3D"fon= +t-family: "Open Sans", verdana, arial, sans-serif; font-size: 12p= +x; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;">500600700
    Total Cases<= +g class=3D"legendlines"><= +rect class=3D"legendtoggle" pointer-events=3D"all" x=3D"0" y=3D"-9.5" width= +=3D"108.75" height=3D"19" style=3D"cursor: pointer; fill: rgb(0, 0, 0); fil= +l-opacity: 0;">Bitcoin= +Dow JonesGold<= +/g>Total Cases%<= +g class=3D"zoomlayer">
    import pandas as pd, plotly.graph_objects as go
    +
    +def main():
    +    display_data(wrangle_data(*scrape_data()))
    +
    +def scrape_data():
    +    def <=
    +span class=3D"hljs-title">scrape_covid()=
    +:
    +        url =3D 'https://covid.ourworldindata.o=
    +rg/data/owid-covid-data.csv'
    +        df =3D pd.read_csv(url, usecols=3D['loc=
    +ation', 'date', 'total_cases'])
    +        return df[df.location =3D=3D 'World'].set_index('date').total_cases
    +    def <=
    +span class=3D"hljs-title">scrape_yahoo(s=
    +lug):
    +        url =3D (f'https://query1.finance.yahoo=
    +.com/v7/finance/download/{slug}?'
    +               'period1=3D1579651200&period=
    +2=3D9999999999&interval=3D1d&events=3Dhistory')
    +        df =3D pd.read_csv(url, usecols=3D['Dat=
    +e', 'Close'])
    +        return df.set_index('Date').Close
    +    out =3D scrape_covid(), scrape_yahoo('BTC-U=
    +SD'), scrape_yahoo('GC=3DF'), scr=
    +ape_yahoo('^DJI')
    +    return map(pd.Series.rename, out, [=
    +'Total Cases', 'Bitcoin', 'Gold', 'Dow Jones'])
    +
    +def wrangle_data(covid=
    +, bitcoin, gold, dow):
    +    df =3D pd.concat([bitcoin, gold, dow], axis=3D1)  # Joins columns on dates.
    +    df =3D df.sort_index().interpolate()            # Sorts by date and interpolates NaN-s.
    +    df =3D df.loc['2020-02-23':]        =
    +            # Discards rows before '2020-02-23=
    +'.
    +    df =3D (df / df.iloc[0]) * 100                  # Calculates percentages relative to day 1.
    +    df =3D df.join(covid)                           # Adds column with covid cases.
    +    return df.sort_values(df.index[-1], axis=3D1)   # Sorts columns by last day's value.
    +
    +def display_data(df):
    +    figure =3D go.Figure()
    +    for col_name in reversed(df.columns):
    +        yaxis =3D 'y1' if col_name =3D=3D 'Total Ca=
    +ses' else 'y2'
    +        trace =3D go.Scatter(x=3Ddf.index, y=3Ddf[col_name], name=3Dcol_nam=
    +e, yaxis=3Dyaxis)
    +        figure.add_trace(trace)
    +    figure.update_layout(
    +        yaxis1=3Ddict(title=3D'Total Cases', rangemode=3D'tozero'),
    +        yaxis2=3Ddict(title=3D'%', range=
    +mode=3D'tozero', overlaying=3D'y', side=3D'right'),
    +        legend=3Ddict(x=3D1.1),
    +        height=3D450
    +    )
    +    figure.show()
    +
    +if __name__ =3D=3D '__main__':
    +    main()
    +
    + + + +

    #PySimpleGUI

    # $ pip3 i=
    +nstall PySimpleGUI
    +import PySimpleGUI as sg
    +
    +layout =3D [[sg.Text("What's your name?"=
    +)], [sg.Input()], [sg.Button('Ok')]]
    +window =3D sg.Window('Window Title', lay=
    +out)
    +event, values =3D window.read()
    +print(f'Hello {value=
    +s[0]}!' if event =3D=3D 'Ok' <=
    +span class=3D"hljs-keyword">else '')
    +
    + +

    #Appendix

    Cy= +thon

    Library that compiles Python code into C.

    <= +pre># $ pip3 install cython +import pyximport; pyximport.install() +import <cython_script> +<cython_script>.main() +
    + + + +

    Definitions:

      +
    • All 'cd= +ef' definitions are optional, but they contribute to the spee= +d-up.
    • +
    • Script needs to be saved with a 'pyx' extension.
    • +
    cdef <ctype> &l=
    +t;var_name> =3D <el>
    +cdef <ctype>[n_elements] <var_name> =3D [<el>, <el>=
    +, ...]
    +cdef <ctype/void> <func_name>(<ctype> <arg_name>): =
    +...
    +
    + + +
    cdef class <class_name>:
    +    cdef public <ctype> <attr_name>
    +    def <=
    +span class=3D"hljs-title">__init__(self,=
    + <ctype> <arg_name>):
    +        self.<attr_name> =3D <arg_name>
    +
    +
    cdef enum <enum_name>=
    +;: <member_name>, <member_name>, ...
    +
    +

    PyInstaller

    $ pip3 install pyinstaller
    +$ pyinstaller script.py                        # Compiles into './dist/script' directory.
    +$ pyinstaller script.py --onefile              # Compiles into './dist/script' console app.
    +$ pyinstaller script.py --windowed             # Compiles into './dist/script' windowed app.
    +$ pyinstaller script.py --add-data '<path>:.'  # Adds file to the root of the executable.
    +
    + +
      +
    • File paths need to be updated to 'os.path.join(sys._MEIPASS, <path>)'= +.
    • +
    +

    Basic Script Template

    #!/usr/bin=
    +/env python3
    +#
    +# Usage: .py
    +#
    +
    +from sys i=
    +mport argv, exit
    +from collections import defaultdict, namedtuple
    +from dataclasses import make_dataclass
    +from enum =
    +import Enum
    +import functools as ft, itertools as it, o=
    +perator as op, re
    +
    +
    +def main():
    +    pass
    +
    +
    +###
    +##  UTIL
    +#
    +
    +def read_file(filename=
    +):
    +    with open(filename, encoding=3D'utf-8') as file:
    +        return file.readlines()
    +
    +
    +if __name__ =3D=3D '__main__':
    +    main()
    +
    + +

    #Index

    • Only available in the= + PDF.
    • +
    • Ctrl+F / =E2=8C=98F is usually sufficient.
    • +
    • Searching '#<title>' will limit the search to the titles.
    • +
    +=20 + + + + + + =20 + =20 + =20 + =20 + + =20 + + + + +------MultipartBoundary--woPjoy8Y4Af6z7kPeFw2jGCIU9O3A2jLmleyvZRmJk---- +Content-Type: text/css +Content-Transfer-Encoding: quoted-printable +Content-Location: cid:css-f5978238-c4d6-4d80-ab44-36d739b2a915@mhtml.blink + +@charset "utf-8"; + +.js-plotly-plot .plotly .mapboxgl-ctrl-logo { display: block; width: 21px; = +height: 21px; background-image: url("data:image/svg+xml;charset=3Dutf-8,%3C= +?xml version=3D\"1.0\" encoding=3D\"utf-8\"?%3E %3Csvg version=3D\"1.1\" id= +=3D\"Layer_1\" xmlns=3D\"http://www.w3.org/2000/svg\" xmlns:xlink=3D\"http:= +//www.w3.org/1999/xlink\" x=3D\"0px\" y=3D\"0px\" viewBox=3D\"0 0 21 21\" s= +tyle=3D\"enable-background:new 0 0 21 21;\" xml:space=3D\"preserve\"%3E%3Cg= + transform=3D\"translate(0,0.01)\"%3E%3Cpath d=3D\"m 10.5,1.24 c -5.11,0 -9= +.25,4.15 -9.25,9.25 0,5.1 4.15,9.25 9.25,9.25 5.1,0 9.25,-4.15 9.25,-9.25 0= +,-5.11 -4.14,-9.25 -9.25,-9.25 z m 4.39,11.53 c -1.93,1.93 -4.78,2.31 -6.7,= +2.31 -0.7,0 -1.41,-0.05 -2.1,-0.16 0,0 -1.02,-5.64 2.14,-8.81 0.83,-0.83 1.= +95,-1.28 3.13,-1.28 1.27,0 2.49,0.51 3.39,1.42 1.84,1.84 1.89,4.75 0.14,6.5= +2 z\" style=3D\"opacity:0.9;fill:%23ffffff;enable-background:new\" class=3D= +\"st0\"/%3E%3Cpath d=3D\"M 10.5,-0.01 C 4.7,-0.01 0,4.7 0,10.49 c 0,5.79 4.= +7,10.5 10.5,10.5 5.8,0 10.5,-4.7 10.5,-10.5 C 20.99,4.7 16.3,-0.01 10.5,-0.= +01 Z m 0,19.75 c -5.11,0 -9.25,-4.15 -9.25,-9.25 0,-5.1 4.14,-9.26 9.25,-9.= +26 5.11,0 9.25,4.15 9.25,9.25 0,5.13 -4.14,9.26 -9.25,9.26 z\" style=3D\"op= +acity:0.35;enable-background:new\" class=3D\"st1\"/%3E%3Cpath d=3D\"M 14.74= +,6.25 C 12.9,4.41 9.98,4.35 8.23,6.1 5.07,9.27 6.09,14.91 6.09,14.91 c 0,0 = +5.64,1.02 8.81,-2.14 C 16.64,11 16.59,8.09 14.74,6.25 Z m -2.27,4.09 -0.91,= +1.87 -0.9,-1.87 -1.86,-0.91 1.86,-0.9 0.9,-1.87 0.91,1.87 1.86,0.9 z\" styl= +e=3D\"opacity:0.35;enable-background:new\" class=3D\"st1\"/%3E%3Cpolygon po= +ints=3D\"11.56,12.21 10.66,10.34 8.8,9.43 10.66,8.53 11.56,6.66 12.47,8.53 = +14.33,9.43 12.47,10.34 \" style=3D\"opacity:0.9;fill:%23ffffff;enable-backg= +round:new\" class=3D\"st0\"/%3E%3C/g%3E%3C/svg%3E"); } + +.js-plotly-plot .plotly .mapboxgl-attrib-empty { display: none; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib .mapbox-improve-map { font-we= +ight: bold; margin-left: 2px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib a:hover { color: inherit; tex= +t-decoration: underline; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib a { color: rgba(0, 0, 0, 0.75= +); text-decoration: none; font-size: 12px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib { color: rgba(0, 0, 0, 0.75);= + text-decoration: none; font-size: 12px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-right .mapboxgl-ctrl { margin= +: 0px 10px 10px 0px; float: right; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-left .mapboxgl-ctrl { margin:= + 0px 0px 10px 10px; float: left; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-left > .mapboxgl-ctrl-attrib.= +mapboxgl-compact::after { bottom: 0px; left: 0px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-right > .mapboxgl-ctrl-attrib= +.mapboxgl-compact::after { bottom: 0px; right: 0px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib.mapboxgl-compact { min-height= +: 20px; padding: 0px; margin: 10px; position: relative; background-color: r= +gb(255, 255, 255); border-radius: 3px 12px 12px 3px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib.mapboxgl-compact::after { con= +tent: ""; cursor: pointer; position: absolute; background-image: url("data:= +image/svg+xml;charset=3Dutf-8,%3Csvg viewBox=3D\"0 0 20 20\" xmlns=3D\"http= +://www.w3.org/2000/svg\"%3E %3Cpath fill=3D\"%23333333\" fill-rule=3D\"even= +odd\" d=3D\"M4,10a6,6 0 1,0 12,0a6,6 0 1,0 -12,0 M9,7a1,1 0 1,0 2,0a1,1 0 1= +,0 -2,0 M9,10a1,1 0 1,1 2,0l0,3a1,1 0 1,1 -2,0\"/%3E %3C/svg%3E"); backgrou= +nd-color: rgba(255, 255, 255, 0.5); width: 24px; height: 24px; box-sizing: = +border-box; border-radius: 12px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib.mapboxgl-compact:hover { padd= +ing: 2px 24px 2px 4px; visibility: visible; margin-top: 6px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib.mapboxgl-compact:hover .mapbo= +xgl-ctrl-attrib-inner { display: block; margin-top: 2px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib.mapboxgl-compact .mapboxgl-ct= +rl-attrib-inner { display: none; } + +.js-plotly-plot .plotly .mapboxgl-ctrl { clear: both; pointer-events: auto;= + transform: translate(0px, 0px); } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-right { position: absolute; p= +ointer-events: none; z-index: 2; right: 0px; bottom: 0px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-left { position: absolute; po= +inter-events: none; z-index: 2; bottom: 0px; left: 0px; } + +.js-plotly-plot .plotly .mapboxgl-canary { background-color: salmon; } + +.js-plotly-plot .plotly .mapboxgl-missing-css { display: none; } + +.js-plotly-plot .plotly .mapboxgl-map { overflow: hidden; position: relativ= +e; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-logo { display: block; width: 21px; = +height: 21px; background-image: url("data:image/svg+xml;charset=3Dutf-8,%3C= +?xml version=3D\"1.0\" encoding=3D\"utf-8\"?%3E %3Csvg version=3D\"1.1\" id= +=3D\"Layer_1\" xmlns=3D\"http://www.w3.org/2000/svg\" xmlns:xlink=3D\"http:= +//www.w3.org/1999/xlink\" x=3D\"0px\" y=3D\"0px\" viewBox=3D\"0 0 21 21\" s= +tyle=3D\"enable-background:new 0 0 21 21;\" xml:space=3D\"preserve\"%3E%3Cg= + transform=3D\"translate(0,0.01)\"%3E%3Cpath d=3D\"m 10.5,1.24 c -5.11,0 -9= +.25,4.15 -9.25,9.25 0,5.1 4.15,9.25 9.25,9.25 5.1,0 9.25,-4.15 9.25,-9.25 0= +,-5.11 -4.14,-9.25 -9.25,-9.25 z m 4.39,11.53 c -1.93,1.93 -4.78,2.31 -6.7,= +2.31 -0.7,0 -1.41,-0.05 -2.1,-0.16 0,0 -1.02,-5.64 2.14,-8.81 0.83,-0.83 1.= +95,-1.28 3.13,-1.28 1.27,0 2.49,0.51 3.39,1.42 1.84,1.84 1.89,4.75 0.14,6.5= +2 z\" style=3D\"opacity:0.9;fill:%23ffffff;enable-background:new\" class=3D= +\"st0\"/%3E%3Cpath d=3D\"M 10.5,-0.01 C 4.7,-0.01 0,4.7 0,10.49 c 0,5.79 4.= +7,10.5 10.5,10.5 5.8,0 10.5,-4.7 10.5,-10.5 C 20.99,4.7 16.3,-0.01 10.5,-0.= +01 Z m 0,19.75 c -5.11,0 -9.25,-4.15 -9.25,-9.25 0,-5.1 4.14,-9.26 9.25,-9.= +26 5.11,0 9.25,4.15 9.25,9.25 0,5.13 -4.14,9.26 -9.25,9.26 z\" style=3D\"op= +acity:0.35;enable-background:new\" class=3D\"st1\"/%3E%3Cpath d=3D\"M 14.74= +,6.25 C 12.9,4.41 9.98,4.35 8.23,6.1 5.07,9.27 6.09,14.91 6.09,14.91 c 0,0 = +5.64,1.02 8.81,-2.14 C 16.64,11 16.59,8.09 14.74,6.25 Z m -2.27,4.09 -0.91,= +1.87 -0.9,-1.87 -1.86,-0.91 1.86,-0.9 0.9,-1.87 0.91,1.87 1.86,0.9 z\" styl= +e=3D\"opacity:0.35;enable-background:new\" class=3D\"st1\"/%3E%3Cpolygon po= +ints=3D\"11.56,12.21 10.66,10.34 8.8,9.43 10.66,8.53 11.56,6.66 12.47,8.53 = +14.33,9.43 12.47,10.34 \" style=3D\"opacity:0.9;fill:%23ffffff;enable-backg= +round:new\" class=3D\"st0\"/%3E%3C/g%3E%3C/svg%3E"); } + +.js-plotly-plot .plotly .mapboxgl-attrib-empty { display: none; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib .mapbox-improve-map { font-we= +ight: bold; margin-left: 2px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib a:hover { color: inherit; tex= +t-decoration: underline; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib a { color: rgba(0, 0, 0, 0.75= +); text-decoration: none; font-size: 12px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib { color: rgba(0, 0, 0, 0.75);= + text-decoration: none; font-size: 12px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-right .mapboxgl-ctrl { margin= +: 0px 10px 10px 0px; float: right; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-left .mapboxgl-ctrl { margin:= + 0px 0px 10px 10px; float: left; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-left > .mapboxgl-ctrl-attrib.= +mapboxgl-compact::after { bottom: 0px; left: 0px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-right > .mapboxgl-ctrl-attrib= +.mapboxgl-compact::after { bottom: 0px; right: 0px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib.mapboxgl-compact { min-height= +: 20px; padding: 0px; margin: 10px; position: relative; background-color: r= +gb(255, 255, 255); border-radius: 3px 12px 12px 3px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib.mapboxgl-compact::after { con= +tent: ""; cursor: pointer; position: absolute; background-image: url("data:= +image/svg+xml;charset=3Dutf-8,%3Csvg viewBox=3D\"0 0 20 20\" xmlns=3D\"http= +://www.w3.org/2000/svg\"%3E %3Cpath fill=3D\"%23333333\" fill-rule=3D\"even= +odd\" d=3D\"M4,10a6,6 0 1,0 12,0a6,6 0 1,0 -12,0 M9,7a1,1 0 1,0 2,0a1,1 0 1= +,0 -2,0 M9,10a1,1 0 1,1 2,0l0,3a1,1 0 1,1 -2,0\"/%3E %3C/svg%3E"); backgrou= +nd-color: rgba(255, 255, 255, 0.5); width: 24px; height: 24px; box-sizing: = +border-box; border-radius: 12px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib.mapboxgl-compact:hover { padd= +ing: 2px 24px 2px 4px; visibility: visible; margin-top: 6px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib.mapboxgl-compact:hover .mapbo= +xgl-ctrl-attrib-inner { display: block; margin-top: 2px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib.mapboxgl-compact .mapboxgl-ct= +rl-attrib-inner { display: none; } + +.js-plotly-plot .plotly .mapboxgl-ctrl { clear: both; pointer-events: auto;= + transform: translate(0px, 0px); } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-right { position: absolute; p= +ointer-events: none; z-index: 2; right: 0px; bottom: 0px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-left { position: absolute; po= +inter-events: none; z-index: 2; bottom: 0px; left: 0px; } + +.js-plotly-plot .plotly .mapboxgl-canary { background-color: salmon; } + +.js-plotly-plot .plotly .mapboxgl-missing-css { display: none; } + +.js-plotly-plot .plotly .mapboxgl-map { overflow: hidden; position: relativ= +e; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-logo { display: block; width: 21px; = +height: 21px; background-image: url("data:image/svg+xml;charset=3Dutf-8,%3C= +?xml version=3D\"1.0\" encoding=3D\"utf-8\"?%3E %3Csvg version=3D\"1.1\" id= +=3D\"Layer_1\" xmlns=3D\"http://www.w3.org/2000/svg\" xmlns:xlink=3D\"http:= +//www.w3.org/1999/xlink\" x=3D\"0px\" y=3D\"0px\" viewBox=3D\"0 0 21 21\" s= +tyle=3D\"enable-background:new 0 0 21 21;\" xml:space=3D\"preserve\"%3E%3Cg= + transform=3D\"translate(0,0.01)\"%3E%3Cpath d=3D\"m 10.5,1.24 c -5.11,0 -9= +.25,4.15 -9.25,9.25 0,5.1 4.15,9.25 9.25,9.25 5.1,0 9.25,-4.15 9.25,-9.25 0= +,-5.11 -4.14,-9.25 -9.25,-9.25 z m 4.39,11.53 c -1.93,1.93 -4.78,2.31 -6.7,= +2.31 -0.7,0 -1.41,-0.05 -2.1,-0.16 0,0 -1.02,-5.64 2.14,-8.81 0.83,-0.83 1.= +95,-1.28 3.13,-1.28 1.27,0 2.49,0.51 3.39,1.42 1.84,1.84 1.89,4.75 0.14,6.5= +2 z\" style=3D\"opacity:0.9;fill:%23ffffff;enable-background:new\" class=3D= +\"st0\"/%3E%3Cpath d=3D\"M 10.5,-0.01 C 4.7,-0.01 0,4.7 0,10.49 c 0,5.79 4.= +7,10.5 10.5,10.5 5.8,0 10.5,-4.7 10.5,-10.5 C 20.99,4.7 16.3,-0.01 10.5,-0.= +01 Z m 0,19.75 c -5.11,0 -9.25,-4.15 -9.25,-9.25 0,-5.1 4.14,-9.26 9.25,-9.= +26 5.11,0 9.25,4.15 9.25,9.25 0,5.13 -4.14,9.26 -9.25,9.26 z\" style=3D\"op= +acity:0.35;enable-background:new\" class=3D\"st1\"/%3E%3Cpath d=3D\"M 14.74= +,6.25 C 12.9,4.41 9.98,4.35 8.23,6.1 5.07,9.27 6.09,14.91 6.09,14.91 c 0,0 = +5.64,1.02 8.81,-2.14 C 16.64,11 16.59,8.09 14.74,6.25 Z m -2.27,4.09 -0.91,= +1.87 -0.9,-1.87 -1.86,-0.91 1.86,-0.9 0.9,-1.87 0.91,1.87 1.86,0.9 z\" styl= +e=3D\"opacity:0.35;enable-background:new\" class=3D\"st1\"/%3E%3Cpolygon po= +ints=3D\"11.56,12.21 10.66,10.34 8.8,9.43 10.66,8.53 11.56,6.66 12.47,8.53 = +14.33,9.43 12.47,10.34 \" style=3D\"opacity:0.9;fill:%23ffffff;enable-backg= +round:new\" class=3D\"st0\"/%3E%3C/g%3E%3C/svg%3E"); } + +.js-plotly-plot .plotly .mapboxgl-attrib-empty { display: none; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib .mapbox-improve-map { font-we= +ight: bold; margin-left: 2px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib a:hover { color: inherit; tex= +t-decoration: underline; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib a { color: rgba(0, 0, 0, 0.75= +); text-decoration: none; font-size: 12px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib { color: rgba(0, 0, 0, 0.75);= + text-decoration: none; font-size: 12px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-right .mapboxgl-ctrl { margin= +: 0px 10px 10px 0px; float: right; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-left .mapboxgl-ctrl { margin:= + 0px 0px 10px 10px; float: left; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-left > .mapboxgl-ctrl-attrib.= +mapboxgl-compact::after { bottom: 0px; left: 0px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-right > .mapboxgl-ctrl-attrib= +.mapboxgl-compact::after { bottom: 0px; right: 0px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib.mapboxgl-compact { min-height= +: 20px; padding: 0px; margin: 10px; position: relative; background-color: r= +gb(255, 255, 255); border-radius: 3px 12px 12px 3px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib.mapboxgl-compact::after { con= +tent: ""; cursor: pointer; position: absolute; background-image: url("data:= +image/svg+xml;charset=3Dutf-8,%3Csvg viewBox=3D\"0 0 20 20\" xmlns=3D\"http= +://www.w3.org/2000/svg\"%3E %3Cpath fill=3D\"%23333333\" fill-rule=3D\"even= +odd\" d=3D\"M4,10a6,6 0 1,0 12,0a6,6 0 1,0 -12,0 M9,7a1,1 0 1,0 2,0a1,1 0 1= +,0 -2,0 M9,10a1,1 0 1,1 2,0l0,3a1,1 0 1,1 -2,0\"/%3E %3C/svg%3E"); backgrou= +nd-color: rgba(255, 255, 255, 0.5); width: 24px; height: 24px; box-sizing: = +border-box; border-radius: 12px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib.mapboxgl-compact:hover { padd= +ing: 2px 24px 2px 4px; visibility: visible; margin-top: 6px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib.mapboxgl-compact:hover .mapbo= +xgl-ctrl-attrib-inner { display: block; margin-top: 2px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-attrib.mapboxgl-compact .mapboxgl-ct= +rl-attrib-inner { display: none; } + +.js-plotly-plot .plotly .mapboxgl-ctrl { clear: both; pointer-events: auto;= + transform: translate(0px, 0px); } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-right { position: absolute; p= +ointer-events: none; z-index: 2; right: 0px; bottom: 0px; } + +.js-plotly-plot .plotly .mapboxgl-ctrl-bottom-left { position: absolute; po= +inter-events: none; z-index: 2; bottom: 0px; left: 0px; } + +.js-plotly-plot .plotly .mapboxgl-canary { background-color: salmon; } + +.js-plotly-plot .plotly .mapboxgl-missing-css { display: none; } + +.js-plotly-plot .plotly .mapboxgl-map { overflow: hidden; position: relativ= +e; } + +.plotly-notifier .notifier-close:hover { color: rgb(68, 68, 68); text-decor= +ation: none; cursor: pointer; } + +.plotly-notifier .notifier-close { color: rgb(255, 255, 255); opacity: 0.8;= + float: right; padding: 0px 5px; background: none; border: none; font-size:= + 20px; font-weight: bold; line-height: 20px; } + +.plotly-notifier .notifier-note { min-width: 180px; max-width: 250px; borde= +r: 1px solid rgb(255, 255, 255); z-index: 3000; margin: 0px; background-col= +or: rgba(140, 151, 175, 0.9); color: rgb(255, 255, 255); padding: 10px; ove= +rflow-wrap: break-word; hyphens: auto; } + +.plotly-notifier p { margin: 0px; } + +.plotly-notifier { font-family: "Open Sans", verdana, arial, sans-serif; po= +sition: fixed; top: 50px; right: 20px; z-index: 10000; font-size: 10pt; max= +-width: 180px; } + +.js-plotly-plot .plotly .select-outline-2 { stroke: black; stroke-dasharray= +: 2px, 2px; } + +.js-plotly-plot .plotly .select-outline-1 { stroke: white; } + +.js-plotly-plot .plotly .select-outline { fill: none; stroke-width: 1; shap= +e-rendering: crispedges; } + +.js-plotly-plot .plotly .vertical [data-title]::before { border-width: 6px;= + border-style: solid; border-color: transparent transparent transparent rgb= +(105, 115, 138); border-image: initial; margin-top: 8px; margin-right: -30p= +x; } + +.js-plotly-plot .plotly .vertical [data-title]::before, .js-plotly-plot .pl= +otly .vertical [data-title]::after { top: 0%; right: 200%; } + +.js-plotly-plot .plotly [data-title]::after { content: attr(data-title); ba= +ckground: rgb(105, 115, 138); color: white; padding: 8px 10px; font-size: 1= +2px; line-height: 12px; white-space: nowrap; margin-right: -18px; border-ra= +dius: 2px; } + +.js-plotly-plot .plotly [data-title]::before { content: ""; position: absol= +ute; background: transparent; border-width: 6px; border-style: solid; borde= +r-color: transparent transparent rgb(105, 115, 138); border-image: initial;= + z-index: 1002; margin-top: -12px; margin-right: -6px; } + +.js-plotly-plot .plotly [data-title]:hover::before, .js-plotly-plot .plotly= + [data-title]:hover::after { display: block; opacity: 1; } + +.js-plotly-plot .plotly [data-title]::before, .js-plotly-plot .plotly [data= +-title]::after { position: absolute; transform: translate3d(0px, 0px, 0px);= + display: none; opacity: 0; z-index: 1001; pointer-events: none; top: 110%;= + right: 50%; } + +.js-plotly-plot .plotly .modebar.vertical .modebar-group .modebar-btn { dis= +play: block; text-align: center; } + +.js-plotly-plot .plotly .modebar.vertical .modebar-group { display: block; = +float: none; padding-left: 0px; padding-bottom: 8px; } + +.js-plotly-plot .plotly .modebar.vertical svg { top: -1px; } + +.js-plotly-plot .plotly .modebar.vertical { display: flex; flex-flow: colum= +n wrap; align-content: flex-end; max-height: 100%; } + +.js-plotly-plot .plotly .modebar-btn svg { position: relative; top: 2px; } + +.js-plotly-plot .plotly .modebar-btn { position: relative; font-size: 16px;= + padding: 3px 4px; height: 22px; cursor: pointer; line-height: normal; box-= +sizing: border-box; } + +.js-plotly-plot .plotly .modebar-group { float: left; display: inline-block= +; box-sizing: border-box; padding-left: 8px; position: relative; vertical-a= +lign: middle; white-space: nowrap; } + +.js-plotly-plot .plotly:hover .modebar--hover .modebar-group { opacity: 1; = +} + +.js-plotly-plot .plotly .modebar--hover > :not(.watermark) { opacity: 0; tr= +ansition: opacity 0.3s ease 0s; } + +.js-plotly-plot .plotly .ease-bg { transition: background-color 0.3s ease 0= +s; } + +.js-plotly-plot .plotly .modebar { position: absolute; top: 2px; right: 2px= +; } + +.js-plotly-plot .plotly .cursor-grab { cursor: grab; } + +.js-plotly-plot .plotly .cursor-ne-resize { cursor: ne-resize; } + +.js-plotly-plot .plotly .cursor-n-resize { cursor: n-resize; } + +.js-plotly-plot .plotly .cursor-nw-resize { cursor: nw-resize; } + +.js-plotly-plot .plotly .cursor-e-resize { cursor: e-resize; } + +.js-plotly-plot .plotly .cursor-w-resize { cursor: w-resize; } + +.js-plotly-plot .plotly .cursor-se-resize { cursor: se-resize; } + +.js-plotly-plot .plotly .cursor-s-resize { cursor: s-resize; } + +.js-plotly-plot .plotly .cursor-sw-resize { cursor: sw-resize; } + +.js-plotly-plot .plotly .cursor-ew-resize { cursor: ew-resize; } + +.js-plotly-plot .plotly .cursor-ns-resize { cursor: ns-resize; } + +.js-plotly-plot .plotly .cursor-row-resize { cursor: row-resize; } + +.js-plotly-plot .plotly .cursor-col-resize { cursor: col-resize; } + +.js-plotly-plot .plotly .cursor-move { cursor: move; } + +.js-plotly-plot .plotly .cursor-crosshair { cursor: crosshair; } + +.js-plotly-plot .plotly .cursor-pointer { cursor: pointer; } + +.js-plotly-plot .plotly .cursor-default { cursor: default; } + +.js-plotly-plot .plotly .main-svg .draglayer { pointer-events: all; } + +.js-plotly-plot .plotly .main-svg { position: absolute; top: 0px; left: 0px= +; pointer-events: none; } + +.js-plotly-plot .plotly svg a:hover { fill: rgb(60, 109, 197); } + +.js-plotly-plot .plotly svg a { fill: rgb(68, 122, 219); } + +.js-plotly-plot .plotly svg { overflow: hidden; } + +.js-plotly-plot .plotly .user-select-none { user-select: none; } + +.js-plotly-plot .plotly .crisp { shape-rendering: crispedges; } + +.js-plotly-plot .plotly a:hover { text-decoration: none; } + +.js-plotly-plot .plotly a { text-decoration: none; } + +.js-plotly-plot .plotly input:focus, .js-plotly-plot .plotly button:focus {= + outline: none; } + +.js-plotly-plot .plotly input, .js-plotly-plot .plotly button { font-family= +: "Open Sans", verdana, arial, sans-serif; } + +.js-plotly-plot .plotly, .js-plotly-plot .plotly div { direction: ltr; font= +-family: "Open Sans", verdana, arial, sans-serif; margin: 0px; padding: 0px= +; } +------MultipartBoundary--woPjoy8Y4Af6z7kPeFw2jGCIU9O3A2jLmleyvZRmJk---- +Content-Type: text/css +Content-Transfer-Encoding: quoted-printable +Content-Location: cid:css-d76930fc-2056-48b7-81c0-036899aab1ec@mhtml.blink + +@charset "utf-8"; + +#modebar-f5f9cb .modebar-btn.active .icon path { fill: rgba(255, 255, 255, = +0.7); } + +#modebar-f5f9cb .modebar-btn:hover .icon path { fill: rgba(255, 255, 255, 0= +.7); } + +#modebar-f5f9cb .modebar-btn .icon path { fill: rgba(255, 255, 255, 0.3); } + +.js-plotly-plot .plotly:hover #modebar-f5f9cb .modebar-group { background-c= +olor: rgba(0, 0, 0, 0.5); } +------MultipartBoundary--woPjoy8Y4Af6z7kPeFw2jGCIU9O3A2jLmleyvZRmJk---- +Content-Type: text/css +Content-Transfer-Encoding: quoted-printable +Content-Location: cid:css-db38e7ab-154c-4a46-9d37-33c065e85a2d@mhtml.blink + +@charset "utf-8"; + +#modebar-c1336a .modebar-btn.active .icon path { fill: rgba(255, 255, 255, = +0.7); } + +#modebar-c1336a .modebar-btn:hover .icon path { fill: rgba(255, 255, 255, 0= +.7); } + +#modebar-c1336a .modebar-btn .icon path { fill: rgba(255, 255, 255, 0.3); } + +.js-plotly-plot .plotly:hover #modebar-c1336a .modebar-group { background-c= +olor: rgba(0, 0, 0, 0.5); } +------MultipartBoundary--woPjoy8Y4Af6z7kPeFw2jGCIU9O3A2jLmleyvZRmJk---- +Content-Type: text/css +Content-Transfer-Encoding: quoted-printable +Content-Location: https://gto76.github.io/python-cheatsheet/web/default.min.css + +@charset "utf-8"; + +.hljs { overflow-x: auto; } + +.hljs, .hljs-subst { } + +.hljs-comment { color: rgb(136, 136, 136); } + +.hljs-keyword, .hljs-attribute, .hljs-selector-tag, .hljs-meta-keyword, .hl= +js-doctag, .hljs-name { font-weight: bold; color: rgb(49, 130, 189); } + +.hljs-type, .hljs-string, .hljs-number, .hljs-selector-id, .hljs-selector-c= +lass, .hljs-quote, .hljs-template-tag, .hljs-deletion { color: rgb(136, 0, = +0); } + +.hljs-title, .hljs-section { color: rgb(136, 0, 0); font-weight: bold; } + +.hljs-regexp, .hljs-symbol, .hljs-variable, .hljs-template-variable, .hljs-= +link, .hljs-selector-attr, .hljs-selector-pseudo { color: rgb(188, 96, 96);= + } + +.hljs-literal { color: rgb(120, 169, 96); } + +.hljs-meta { color: rgb(31, 113, 153); } + +.hljs-meta-string { color: rgb(77, 153, 191); } + +.hljs-emphasis { font-style: italic; } + +.hljs-strong { font-weight: bold; } +------MultipartBoundary--woPjoy8Y4Af6z7kPeFw2jGCIU9O3A2jLmleyvZRmJk---- +Content-Type: text/css +Content-Transfer-Encoding: quoted-printable +Content-Location: https://netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css + +@charset "utf-8"; + +@font-face { font-family: FontAwesome; src: url("../font/fontawesome-webfon= +t.woff?v=3D3.2.1") format("woff"), url("../font/fontawesome-webfont.ttf?v= +=3D3.2.1") format("truetype"); font-weight: normal; font-style: normal; } + +[class^=3D"icon-"], [class*=3D" icon-"] { font-family: FontAwesome; font-we= +ight: normal; font-style: normal; text-decoration: inherit; -webkit-font-sm= +oothing: antialiased; } + +[class^=3D"icon-"]::before, [class*=3D" icon-"]::before { text-decoration: = +inherit; display: inline-block; speak: none; } + +.icon-large::before { vertical-align: -10%; font-size: 1.33333em; } + +a [class^=3D"icon-"], a [class*=3D" icon-"] { display: inline; } + +[class^=3D"icon-"].icon-fixed-width, [class*=3D" icon-"].icon-fixed-width {= + display: inline-block; width: 1.14286em; text-align: right; padding-right:= + 0.285714em; } + +[class^=3D"icon-"].icon-fixed-width.icon-large, [class*=3D" icon-"].icon-fi= +xed-width.icon-large { width: 1.42857em; } + +.icons-ul { margin-left: 2.14286em; list-style-type: none; } + +.icons-ul > li { position: relative; } + +.icons-ul .icon-li { position: absolute; left: -2.14286em; width: 2.14286em= +; text-align: center; line-height: inherit; } + +[class^=3D"icon-"].hide, [class*=3D" icon-"].hide { display: none; } + +.icon-muted { color: rgb(238, 238, 238); } + +.icon-light { color: rgb(255, 255, 255); } + +.icon-dark { color: rgb(51, 51, 51); } + +.icon-border { border: 1px solid rgb(238, 238, 238); padding: 0.2em 0.25em = +0.15em; border-radius: 3px; } + +.icon-2x { font-size: 2em; } + +.icon-2x.icon-border { border-width: 2px; border-radius: 4px; } + +.icon-3x { font-size: 3em; } + +.icon-3x.icon-border { border-width: 3px; border-radius: 5px; } + +.icon-4x { font-size: 4em; } + +.icon-4x.icon-border { border-width: 4px; border-radius: 6px; } + +.icon-5x { font-size: 5em; } + +.icon-5x.icon-border { border-width: 5px; border-radius: 7px; } + +.pull-right { float: right; } + +.pull-left { float: left; } + +[class^=3D"icon-"].pull-left, [class*=3D" icon-"].pull-left { margin-right:= + 0.3em; } + +[class^=3D"icon-"].pull-right, [class*=3D" icon-"].pull-right { margin-left= +: 0.3em; } + +[class^=3D"icon-"], [class*=3D" icon-"] { display: inline; width: auto; hei= +ght: auto; line-height: normal; vertical-align: baseline; background-image:= + none; background-position: 0% 0%; background-repeat: repeat; margin-top: 0= +px; } + +.icon-white, .nav-pills > .active > a > [class^=3D"icon-"], .nav-pills > .a= +ctive > a > [class*=3D" icon-"], .nav-list > .active > a > [class^=3D"icon-= +"], .nav-list > .active > a > [class*=3D" icon-"], .navbar-inverse .nav > .= +active > a > [class^=3D"icon-"], .navbar-inverse .nav > .active > a > [clas= +s*=3D" icon-"], .dropdown-menu > li > a:hover > [class^=3D"icon-"], .dropdo= +wn-menu > li > a:hover > [class*=3D" icon-"], .dropdown-menu > .active > a = +> [class^=3D"icon-"], .dropdown-menu > .active > a > [class*=3D" icon-"], .= +dropdown-submenu:hover > a > [class^=3D"icon-"], .dropdown-submenu:hover > = +a > [class*=3D" icon-"] { background-image: none; } + +.btn [class^=3D"icon-"].icon-large, .nav [class^=3D"icon-"].icon-large, .bt= +n [class*=3D" icon-"].icon-large, .nav [class*=3D" icon-"].icon-large { lin= +e-height: 0.9em; } + +.btn [class^=3D"icon-"].icon-spin, .nav [class^=3D"icon-"].icon-spin, .btn = +[class*=3D" icon-"].icon-spin, .nav [class*=3D" icon-"].icon-spin { display= +: inline-block; } + +.nav-tabs [class^=3D"icon-"], .nav-pills [class^=3D"icon-"], .nav-tabs [cla= +ss*=3D" icon-"], .nav-pills [class*=3D" icon-"], .nav-tabs [class^=3D"icon-= +"].icon-large, .nav-pills [class^=3D"icon-"].icon-large, .nav-tabs [class*= +=3D" icon-"].icon-large, .nav-pills [class*=3D" icon-"].icon-large { line-h= +eight: 0.9em; } + +.btn [class^=3D"icon-"].pull-left.icon-2x, .btn [class*=3D" icon-"].pull-le= +ft.icon-2x, .btn [class^=3D"icon-"].pull-right.icon-2x, .btn [class*=3D" ic= +on-"].pull-right.icon-2x { margin-top: 0.18em; } + +.btn [class^=3D"icon-"].icon-spin.icon-large, .btn [class*=3D" icon-"].icon= +-spin.icon-large { line-height: 0.8em; } + +.btn.btn-small [class^=3D"icon-"].pull-left.icon-2x, .btn.btn-small [class*= +=3D" icon-"].pull-left.icon-2x, .btn.btn-small [class^=3D"icon-"].pull-righ= +t.icon-2x, .btn.btn-small [class*=3D" icon-"].pull-right.icon-2x { margin-t= +op: 0.25em; } + +.btn.btn-large [class^=3D"icon-"], .btn.btn-large [class*=3D" icon-"] { mar= +gin-top: 0px; } + +.btn.btn-large [class^=3D"icon-"].pull-left.icon-2x, .btn.btn-large [class*= +=3D" icon-"].pull-left.icon-2x, .btn.btn-large [class^=3D"icon-"].pull-righ= +t.icon-2x, .btn.btn-large [class*=3D" icon-"].pull-right.icon-2x { margin-t= +op: 0.05em; } + +.btn.btn-large [class^=3D"icon-"].pull-left.icon-2x, .btn.btn-large [class*= +=3D" icon-"].pull-left.icon-2x { margin-right: 0.2em; } + +.btn.btn-large [class^=3D"icon-"].pull-right.icon-2x, .btn.btn-large [class= +*=3D" icon-"].pull-right.icon-2x { margin-left: 0.2em; } + +.nav-list [class^=3D"icon-"], .nav-list [class*=3D" icon-"] { line-height: = +inherit; } + +.icon-stack { position: relative; display: inline-block; width: 2em; height= +: 2em; line-height: 2em; vertical-align: -35%; } + +.icon-stack [class^=3D"icon-"], .icon-stack [class*=3D" icon-"] { display: = +block; text-align: center; position: absolute; width: 100%; height: 100%; f= +ont-size: 1em; line-height: inherit; } + +.icon-stack .icon-stack-base { font-size: 2em; } + +.icon-spin { display: inline-block; animation: 2s linear 0s infinite normal= + none running spin; } + +a .icon-stack, a .icon-spin { display: inline-block; text-decoration: none;= + } + +@-webkit-keyframes spin {=20 + 0% { transform: rotate(0deg); } + 100% { transform: rotate(359deg); } +} + +@keyframes spin {=20 + 0% { transform: rotate(0deg); } + 100% { transform: rotate(359deg); } +} + +.icon-rotate-90::before { transform: rotate(90deg); } + +.icon-rotate-180::before { transform: rotate(180deg); } + +.icon-rotate-270::before { transform: rotate(270deg); } + +.icon-flip-horizontal::before { transform: scale(-1, 1); } + +.icon-flip-vertical::before { transform: scale(1, -1); } + +a .icon-rotate-90::before, a .icon-rotate-180::before, a .icon-rotate-270::= +before, a .icon-flip-horizontal::before, a .icon-flip-vertical::before { di= +splay: inline-block; } + +.icon-glass::before { content: "=EF=80=80"; } + +.icon-music::before { content: "=EF=80=81"; } + +.icon-search::before { content: "=EF=80=82"; } + +.icon-envelope-alt::before { content: "=EF=80=83"; } + +.icon-heart::before { content: "=EF=80=84"; } + +.icon-star::before { content: "=EF=80=85"; } + +.icon-star-empty::before { content: "=EF=80=86"; } + +.icon-user::before { content: "=EF=80=87"; } + +.icon-film::before { content: "=EF=80=88"; } + +.icon-th-large::before { content: "=EF=80=89"; } + +.icon-th::before { content: "=EF=80=8A"; } + +.icon-th-list::before { content: "=EF=80=8B"; } + +.icon-ok::before { content: "=EF=80=8C"; } + +.icon-remove::before { content: "=EF=80=8D"; } + +.icon-zoom-in::before { content: "=EF=80=8E"; } + +.icon-zoom-out::before { content: "=EF=80=90"; } + +.icon-power-off::before, .icon-off::before { content: "=EF=80=91"; } + +.icon-signal::before { content: "=EF=80=92"; } + +.icon-gear::before, .icon-cog::before { content: "=EF=80=93"; } + +.icon-trash::before { content: "=EF=80=94"; } + +.icon-home::before { content: "=EF=80=95"; } + +.icon-file-alt::before { content: "=EF=80=96"; } + +.icon-time::before { content: "=EF=80=97"; } + +.icon-road::before { content: "=EF=80=98"; } + +.icon-download-alt::before { content: "=EF=80=99"; } + +.icon-download::before { content: "=EF=80=9A"; } + +.icon-upload::before { content: "=EF=80=9B"; } + +.icon-inbox::before { content: "=EF=80=9C"; } + +.icon-play-circle::before { content: "=EF=80=9D"; } + +.icon-rotate-right::before, .icon-repeat::before { content: "=EF=80=9E"; } + +.icon-refresh::before { content: "=EF=80=A1"; } + +.icon-list-alt::before { content: "=EF=80=A2"; } + +.icon-lock::before { content: "=EF=80=A3"; } + +.icon-flag::before { content: "=EF=80=A4"; } + +.icon-headphones::before { content: "=EF=80=A5"; } + +.icon-volume-off::before { content: "=EF=80=A6"; } + +.icon-volume-down::before { content: "=EF=80=A7"; } + +.icon-volume-up::before { content: "=EF=80=A8"; } + +.icon-qrcode::before { content: "=EF=80=A9"; } + +.icon-barcode::before { content: "=EF=80=AA"; } + +.icon-tag::before { content: "=EF=80=AB"; } + +.icon-tags::before { content: "=EF=80=AC"; } + +.icon-book::before { content: "=EF=80=AD"; } + +.icon-bookmark::before { content: "=EF=80=AE"; } + +.icon-print::before { content: "=EF=80=AF"; } + +.icon-camera::before { content: "=EF=80=B0"; } + +.icon-font::before { content: "=EF=80=B1"; } + +.icon-bold::before { content: "=EF=80=B2"; } + +.icon-italic::before { content: "=EF=80=B3"; } + +.icon-text-height::before { content: "=EF=80=B4"; } + +.icon-text-width::before { content: "=EF=80=B5"; } + +.icon-align-left::before { content: "=EF=80=B6"; } + +.icon-align-center::before { content: "=EF=80=B7"; } + +.icon-align-right::before { content: "=EF=80=B8"; } + +.icon-align-justify::before { content: "=EF=80=B9"; } + +.icon-list::before { content: "=EF=80=BA"; } + +.icon-indent-left::before { content: "=EF=80=BB"; } + +.icon-indent-right::before { content: "=EF=80=BC"; } + +.icon-facetime-video::before { content: "=EF=80=BD"; } + +.icon-picture::before { content: "=EF=80=BE"; } + +.icon-pencil::before { content: "=EF=81=80"; } + +.icon-map-marker::before { content: "=EF=81=81"; } + +.icon-adjust::before { content: "=EF=81=82"; } + +.icon-tint::before { content: "=EF=81=83"; } + +.icon-edit::before { content: "=EF=81=84"; } + +.icon-share::before { content: "=EF=81=85"; } + +.icon-check::before { content: "=EF=81=86"; } + +.icon-move::before { content: "=EF=81=87"; } + +.icon-step-backward::before { content: "=EF=81=88"; } + +.icon-fast-backward::before { content: "=EF=81=89"; } + +.icon-backward::before { content: "=EF=81=8A"; } + +.icon-play::before { content: "=EF=81=8B"; } + +.icon-pause::before { content: "=EF=81=8C"; } + +.icon-stop::before { content: "=EF=81=8D"; } + +.icon-forward::before { content: "=EF=81=8E"; } + +.icon-fast-forward::before { content: "=EF=81=90"; } + +.icon-step-forward::before { content: "=EF=81=91"; } + +.icon-eject::before { content: "=EF=81=92"; } + +.icon-chevron-left::before { content: "=EF=81=93"; } + +.icon-chevron-right::before { content: "=EF=81=94"; } + +.icon-plus-sign::before { content: "=EF=81=95"; } + +.icon-minus-sign::before { content: "=EF=81=96"; } + +.icon-remove-sign::before { content: "=EF=81=97"; } + +.icon-ok-sign::before { content: "=EF=81=98"; } + +.icon-question-sign::before { content: "=EF=81=99"; } + +.icon-info-sign::before { content: "=EF=81=9A"; } + +.icon-screenshot::before { content: "=EF=81=9B"; } + +.icon-remove-circle::before { content: "=EF=81=9C"; } + +.icon-ok-circle::before { content: "=EF=81=9D"; } + +.icon-ban-circle::before { content: "=EF=81=9E"; } + +.icon-arrow-left::before { content: "=EF=81=A0"; } + +.icon-arrow-right::before { content: "=EF=81=A1"; } + +.icon-arrow-up::before { content: "=EF=81=A2"; } + +.icon-arrow-down::before { content: "=EF=81=A3"; } + +.icon-mail-forward::before, .icon-share-alt::before { content: "=EF=81=A4";= + } + +.icon-resize-full::before { content: "=EF=81=A5"; } + +.icon-resize-small::before { content: "=EF=81=A6"; } + +.icon-plus::before { content: "=EF=81=A7"; } + +.icon-minus::before { content: "=EF=81=A8"; } + +.icon-asterisk::before { content: "=EF=81=A9"; } + +.icon-exclamation-sign::before { content: "=EF=81=AA"; } + +.icon-gift::before { content: "=EF=81=AB"; } + +.icon-leaf::before { content: "=EF=81=AC"; } + +.icon-fire::before { content: "=EF=81=AD"; } + +.icon-eye-open::before { content: "=EF=81=AE"; } + +.icon-eye-close::before { content: "=EF=81=B0"; } + +.icon-warning-sign::before { content: "=EF=81=B1"; } + +.icon-plane::before { content: "=EF=81=B2"; } + +.icon-calendar::before { content: "=EF=81=B3"; } + +.icon-random::before { content: "=EF=81=B4"; } + +.icon-comment::before { content: "=EF=81=B5"; } + +.icon-magnet::before { content: "=EF=81=B6"; } + +.icon-chevron-up::before { content: "=EF=81=B7"; } + +.icon-chevron-down::before { content: "=EF=81=B8"; } + +.icon-retweet::before { content: "=EF=81=B9"; } + +.icon-shopping-cart::before { content: "=EF=81=BA"; } + +.icon-folder-close::before { content: "=EF=81=BB"; } + +.icon-folder-open::before { content: "=EF=81=BC"; } + +.icon-resize-vertical::before { content: "=EF=81=BD"; } + +.icon-resize-horizontal::before { content: "=EF=81=BE"; } + +.icon-bar-chart::before { content: "=EF=82=80"; } + +.icon-twitter-sign::before { content: "=EF=82=81"; } + +.icon-facebook-sign::before { content: "=EF=82=82"; } + +.icon-camera-retro::before { content: "=EF=82=83"; } + +.icon-key::before { content: "=EF=82=84"; } + +.icon-gears::before, .icon-cogs::before { content: "=EF=82=85"; } + +.icon-comments::before { content: "=EF=82=86"; } + +.icon-thumbs-up-alt::before { content: "=EF=82=87"; } + +.icon-thumbs-down-alt::before { content: "=EF=82=88"; } + +.icon-star-half::before { content: "=EF=82=89"; } + +.icon-heart-empty::before { content: "=EF=82=8A"; } + +.icon-signout::before { content: "=EF=82=8B"; } + +.icon-linkedin-sign::before { content: "=EF=82=8C"; } + +.icon-pushpin::before { content: "=EF=82=8D"; } + +.icon-external-link::before { content: "=EF=82=8E"; } + +.icon-signin::before { content: "=EF=82=90"; } + +.icon-trophy::before { content: "=EF=82=91"; } + +.icon-github-sign::before { content: "=EF=82=92"; } + +.icon-upload-alt::before { content: "=EF=82=93"; } + +.icon-lemon::before { content: "=EF=82=94"; } + +.icon-phone::before { content: "=EF=82=95"; } + +.icon-unchecked::before, .icon-check-empty::before { content: "=EF=82=96"; = +} + +.icon-bookmark-empty::before { content: "=EF=82=97"; } + +.icon-phone-sign::before { content: "=EF=82=98"; } + +.icon-twitter::before { content: "=EF=82=99"; } + +.icon-facebook::before { content: "=EF=82=9A"; } + +.icon-github::before { content: "=EF=82=9B"; } + +.icon-unlock::before { content: "=EF=82=9C"; } + +.icon-credit-card::before { content: "=EF=82=9D"; } + +.icon-rss::before { content: "=EF=82=9E"; } + +.icon-hdd::before { content: "=EF=82=A0"; } + +.icon-bullhorn::before { content: "=EF=82=A1"; } + +.icon-bell::before { content: "=EF=82=A2"; } + +.icon-certificate::before { content: "=EF=82=A3"; } + +.icon-hand-right::before { content: "=EF=82=A4"; } + +.icon-hand-left::before { content: "=EF=82=A5"; } + +.icon-hand-up::before { content: "=EF=82=A6"; } + +.icon-hand-down::before { content: "=EF=82=A7"; } + +.icon-circle-arrow-left::before { content: "=EF=82=A8"; } + +.icon-circle-arrow-right::before { content: "=EF=82=A9"; } + +.icon-circle-arrow-up::before { content: "=EF=82=AA"; } + +.icon-circle-arrow-down::before { content: "=EF=82=AB"; } + +.icon-globe::before { content: "=EF=82=AC"; } + +.icon-wrench::before { content: "=EF=82=AD"; } + +.icon-tasks::before { content: "=EF=82=AE"; } + +.icon-filter::before { content: "=EF=82=B0"; } + +.icon-briefcase::before { content: "=EF=82=B1"; } + +.icon-fullscreen::before { content: "=EF=82=B2"; } + +.icon-group::before { content: "=EF=83=80"; } + +.icon-link::before { content: "=EF=83=81"; } + +.icon-cloud::before { content: "=EF=83=82"; } + +.icon-beaker::before { content: "=EF=83=83"; } + +.icon-cut::before { content: "=EF=83=84"; } + +.icon-copy::before { content: "=EF=83=85"; } + +.icon-paperclip::before, .icon-paper-clip::before { content: "=EF=83=86"; } + +.icon-save::before { content: "=EF=83=87"; } + +.icon-sign-blank::before { content: "=EF=83=88"; } + +.icon-reorder::before { content: "=EF=83=89"; } + +.icon-list-ul::before { content: "=EF=83=8A"; } + +.icon-list-ol::before { content: "=EF=83=8B"; } + +.icon-strikethrough::before { content: "=EF=83=8C"; } + +.icon-underline::before { content: "=EF=83=8D"; } + +.icon-table::before { content: "=EF=83=8E"; } + +.icon-magic::before { content: "=EF=83=90"; } + +.icon-truck::before { content: "=EF=83=91"; } + +.icon-pinterest::before { content: "=EF=83=92"; } + +.icon-pinterest-sign::before { content: "=EF=83=93"; } + +.icon-google-plus-sign::before { content: "=EF=83=94"; } + +.icon-google-plus::before { content: "=EF=83=95"; } + +.icon-money::before { content: "=EF=83=96"; } + +.icon-caret-down::before { content: "=EF=83=97"; } + +.icon-caret-up::before { content: "=EF=83=98"; } + +.icon-caret-left::before { content: "=EF=83=99"; } + +.icon-caret-right::before { content: "=EF=83=9A"; } + +.icon-columns::before { content: "=EF=83=9B"; } + +.icon-sort::before { content: "=EF=83=9C"; } + +.icon-sort-down::before { content: "=EF=83=9D"; } + +.icon-sort-up::before { content: "=EF=83=9E"; } + +.icon-envelope::before { content: "=EF=83=A0"; } + +.icon-linkedin::before { content: "=EF=83=A1"; } + +.icon-rotate-left::before, .icon-undo::before { content: "=EF=83=A2"; } + +.icon-legal::before { content: "=EF=83=A3"; } + +.icon-dashboard::before { content: "=EF=83=A4"; } + +.icon-comment-alt::before { content: "=EF=83=A5"; } + +.icon-comments-alt::before { content: "=EF=83=A6"; } + +.icon-bolt::before { content: "=EF=83=A7"; } + +.icon-sitemap::before { content: "=EF=83=A8"; } + +.icon-umbrella::before { content: "=EF=83=A9"; } + +.icon-paste::before { content: "=EF=83=AA"; } + +.icon-lightbulb::before { content: "=EF=83=AB"; } + +.icon-exchange::before { content: "=EF=83=AC"; } + +.icon-cloud-download::before { content: "=EF=83=AD"; } + +.icon-cloud-upload::before { content: "=EF=83=AE"; } + +.icon-user-md::before { content: "=EF=83=B0"; } + +.icon-stethoscope::before { content: "=EF=83=B1"; } + +.icon-suitcase::before { content: "=EF=83=B2"; } + +.icon-bell-alt::before { content: "=EF=83=B3"; } + +.icon-coffee::before { content: "=EF=83=B4"; } + +.icon-food::before { content: "=EF=83=B5"; } + +.icon-file-text-alt::before { content: "=EF=83=B6"; } + +.icon-building::before { content: "=EF=83=B7"; } + +.icon-hospital::before { content: "=EF=83=B8"; } + +.icon-ambulance::before { content: "=EF=83=B9"; } + +.icon-medkit::before { content: "=EF=83=BA"; } + +.icon-fighter-jet::before { content: "=EF=83=BB"; } + +.icon-beer::before { content: "=EF=83=BC"; } + +.icon-h-sign::before { content: "=EF=83=BD"; } + +.icon-plus-sign-alt::before { content: "=EF=83=BE"; } + +.icon-double-angle-left::before { content: "=EF=84=80"; } + +.icon-double-angle-right::before { content: "=EF=84=81"; } + +.icon-double-angle-up::before { content: "=EF=84=82"; } + +.icon-double-angle-down::before { content: "=EF=84=83"; } + +.icon-angle-left::before { content: "=EF=84=84"; } + +.icon-angle-right::before { content: "=EF=84=85"; } + +.icon-angle-up::before { content: "=EF=84=86"; } + +.icon-angle-down::before { content: "=EF=84=87"; } + +.icon-desktop::before { content: "=EF=84=88"; } + +.icon-laptop::before { content: "=EF=84=89"; } + +.icon-tablet::before { content: "=EF=84=8A"; } + +.icon-mobile-phone::before { content: "=EF=84=8B"; } + +.icon-circle-blank::before { content: "=EF=84=8C"; } + +.icon-quote-left::before { content: "=EF=84=8D"; } + +.icon-quote-right::before { content: "=EF=84=8E"; } + +.icon-spinner::before { content: "=EF=84=90"; } + +.icon-circle::before { content: "=EF=84=91"; } + +.icon-mail-reply::before, .icon-reply::before { content: "=EF=84=92"; } + +.icon-github-alt::before { content: "=EF=84=93"; } + +.icon-folder-close-alt::before { content: "=EF=84=94"; } + +.icon-folder-open-alt::before { content: "=EF=84=95"; } + +.icon-expand-alt::before { content: "=EF=84=96"; } + +.icon-collapse-alt::before { content: "=EF=84=97"; } + +.icon-smile::before { content: "=EF=84=98"; } + +.icon-frown::before { content: "=EF=84=99"; } + +.icon-meh::before { content: "=EF=84=9A"; } + +.icon-gamepad::before { content: "=EF=84=9B"; } + +.icon-keyboard::before { content: "=EF=84=9C"; } + +.icon-flag-alt::before { content: "=EF=84=9D"; } + +.icon-flag-checkered::before { content: "=EF=84=9E"; } + +.icon-terminal::before { content: "=EF=84=A0"; } + +.icon-code::before { content: "=EF=84=A1"; } + +.icon-reply-all::before { content: "=EF=84=A2"; } + +.icon-mail-reply-all::before { content: "=EF=84=A2"; } + +.icon-star-half-full::before, .icon-star-half-empty::before { content: "=EF= +=84=A3"; } + +.icon-location-arrow::before { content: "=EF=84=A4"; } + +.icon-crop::before { content: "=EF=84=A5"; } + +.icon-code-fork::before { content: "=EF=84=A6"; } + +.icon-unlink::before { content: "=EF=84=A7"; } + +.icon-question::before { content: "=EF=84=A8"; } + +.icon-info::before { content: "=EF=84=A9"; } + +.icon-exclamation::before { content: "=EF=84=AA"; } + +.icon-superscript::before { content: "=EF=84=AB"; } + +.icon-subscript::before { content: "=EF=84=AC"; } + +.icon-eraser::before { content: "=EF=84=AD"; } + +.icon-puzzle-piece::before { content: "=EF=84=AE"; } + +.icon-microphone::before { content: "=EF=84=B0"; } + +.icon-microphone-off::before { content: "=EF=84=B1"; } + +.icon-shield::before { content: "=EF=84=B2"; } + +.icon-calendar-empty::before { content: "=EF=84=B3"; } + +.icon-fire-extinguisher::before { content: "=EF=84=B4"; } + +.icon-rocket::before { content: "=EF=84=B5"; } + +.icon-maxcdn::before { content: "=EF=84=B6"; } + +.icon-chevron-sign-left::before { content: "=EF=84=B7"; } + +.icon-chevron-sign-right::before { content: "=EF=84=B8"; } + +.icon-chevron-sign-up::before { content: "=EF=84=B9"; } + +.icon-chevron-sign-down::before { content: "=EF=84=BA"; } + +.icon-html5::before { content: "=EF=84=BB"; } + +.icon-css3::before { content: "=EF=84=BC"; } + +.icon-anchor::before { content: "=EF=84=BD"; } + +.icon-unlock-alt::before { content: "=EF=84=BE"; } + +.icon-bullseye::before { content: "=EF=85=80"; } + +.icon-ellipsis-horizontal::before { content: "=EF=85=81"; } + +.icon-ellipsis-vertical::before { content: "=EF=85=82"; } + +.icon-rss-sign::before { content: "=EF=85=83"; } + +.icon-play-sign::before { content: "=EF=85=84"; } + +.icon-ticket::before { content: "=EF=85=85"; } + +.icon-minus-sign-alt::before { content: "=EF=85=86"; } + +.icon-check-minus::before { content: "=EF=85=87"; } + +.icon-level-up::before { content: "=EF=85=88"; } + +.icon-level-down::before { content: "=EF=85=89"; } + +.icon-check-sign::before { content: "=EF=85=8A"; } + +.icon-edit-sign::before { content: "=EF=85=8B"; } + +.icon-external-link-sign::before { content: "=EF=85=8C"; } + +.icon-share-sign::before { content: "=EF=85=8D"; } + +.icon-compass::before { content: "=EF=85=8E"; } + +.icon-collapse::before { content: "=EF=85=90"; } + +.icon-collapse-top::before { content: "=EF=85=91"; } + +.icon-expand::before { content: "=EF=85=92"; } + +.icon-euro::before, .icon-eur::before { content: "=EF=85=93"; } + +.icon-gbp::before { content: "=EF=85=94"; } + +.icon-dollar::before, .icon-usd::before { content: "=EF=85=95"; } + +.icon-rupee::before, .icon-inr::before { content: "=EF=85=96"; } + +.icon-yen::before, .icon-jpy::before { content: "=EF=85=97"; } + +.icon-renminbi::before, .icon-cny::before { content: "=EF=85=98"; } + +.icon-won::before, .icon-krw::before { content: "=EF=85=99"; } + +.icon-bitcoin::before, .icon-btc::before { content: "=EF=85=9A"; } + +.icon-file::before { content: "=EF=85=9B"; } + +.icon-file-text::before { content: "=EF=85=9C"; } + +.icon-sort-by-alphabet::before { content: "=EF=85=9D"; } + +.icon-sort-by-alphabet-alt::before { content: "=EF=85=9E"; } + +.icon-sort-by-attributes::before { content: "=EF=85=A0"; } + +.icon-sort-by-attributes-alt::before { content: "=EF=85=A1"; } + +.icon-sort-by-order::before { content: "=EF=85=A2"; } + +.icon-sort-by-order-alt::before { content: "=EF=85=A3"; } + +.icon-thumbs-up::before { content: "=EF=85=A4"; } + +.icon-thumbs-down::before { content: "=EF=85=A5"; } + +.icon-youtube-sign::before { content: "=EF=85=A6"; } + +.icon-youtube::before { content: "=EF=85=A7"; } + +.icon-xing::before { content: "=EF=85=A8"; } + +.icon-xing-sign::before { content: "=EF=85=A9"; } + +.icon-youtube-play::before { content: "=EF=85=AA"; } + +.icon-dropbox::before { content: "=EF=85=AB"; } + +.icon-stackexchange::before { content: "=EF=85=AC"; } + +.icon-instagram::before { content: "=EF=85=AD"; } + +.icon-flickr::before { content: "=EF=85=AE"; } + +.icon-adn::before { content: "=EF=85=B0"; } + +.icon-bitbucket::before { content: "=EF=85=B1"; } + +.icon-bitbucket-sign::before { content: "=EF=85=B2"; } + +.icon-tumblr::before { content: "=EF=85=B3"; } + +.icon-tumblr-sign::before { content: "=EF=85=B4"; } + +.icon-long-arrow-down::before { content: "=EF=85=B5"; } + +.icon-long-arrow-up::before { content: "=EF=85=B6"; } + +.icon-long-arrow-left::before { content: "=EF=85=B7"; } + +.icon-long-arrow-right::before { content: "=EF=85=B8"; } + +.icon-apple::before { content: "=EF=85=B9"; } + +.icon-windows::before { content: "=EF=85=BA"; } + +.icon-android::before { content: "=EF=85=BB"; } + +.icon-linux::before { content: "=EF=85=BC"; } + +.icon-dribbble::before { content: "=EF=85=BD"; } + +.icon-skype::before { content: "=EF=85=BE"; } + +.icon-foursquare::before { content: "=EF=86=80"; } + +.icon-trello::before { content: "=EF=86=81"; } + +.icon-female::before { content: "=EF=86=82"; } + +.icon-male::before { content: "=EF=86=83"; } + +.icon-gittip::before { content: "=EF=86=84"; } + +.icon-sun::before { content: "=EF=86=85"; } + +.icon-moon::before { content: "=EF=86=86"; } + +.icon-archive::before { content: "=EF=86=87"; } + +.icon-bug::before { content: "=EF=86=88"; } + +.icon-vk::before { content: "=EF=86=89"; } + +.icon-weibo::before { content: "=EF=86=8A"; } + +.icon-renren::before { content: "=EF=86=8B"; } +------MultipartBoundary--woPjoy8Y4Af6z7kPeFw2jGCIU9O3A2jLmleyvZRmJk---- +Content-Type: text/css +Content-Transfer-Encoding: quoted-printable +Content-Location: https://gto76.github.io/python-cheatsheet/web/style.css + +@charset "utf-8"; + +@import url("https://fonts.googleapis.com/css?family=3DPT+Serif|PT+Serif:b|= +PT+Serif:i|PT+Sans|PT+Sans:b"); + +.ocks-org body { background: rgb(252, 252, 250); color: rgb(51, 51, 51); fo= +nt-family: "PT Serif", serif; margin: 1em auto 4em; position: relative; wid= +th: 960px; padding: 1rem; } + +.ocks-org header, .ocks-org footer, .ocks-org aside, .ocks-org h1, .ocks-or= +g h2, .ocks-org h3, .ocks-org h4 { font-family: "PT Sans", sans-serif; } + +.ocks-org h1, .ocks-org h2, .ocks-org h3, .ocks-org h4 { color: rgb(0, 0, 0= +); } + +.ocks-org header, .ocks-org footer { color: rgb(99, 99, 99); } + +h1 { font-size: 64px; font-weight: 300; letter-spacing: -2px; margin: 0.3em= + 0px 0.1em; } + +h2 { margin-top: 2em; } + +h1, h2 { text-rendering: optimizelegibility; } + +h2 a[name], h2 a[id] { color: rgb(204, 204, 204); padding-right: 0.3em; } + +header, footer { font-size: small; } + +.ocks-org header aside, .ocks-org footer aside { float: left; margin-right:= + 0.5em; } + +.ocks-org header aside::after, .ocks-org footer aside::after { padding-left= +: 0.5em; content: "/"; } + +footer { margin-top: 6em; } + +h1 ~ aside { font-size: small; right: 0px; position: absolute; width: 180px= +; } + +.attribution { font-size: small; margin-bottom: 2em; } + +body > p, li > p, div > p { line-height: 1.5em; } + +body > p, div > p { width: 720px; } + +body > blockquote { width: 640px; } + +blockquote q { display: block; font-style: oblique; } + +ul { padding: 0px; } + +li { width: 690px; margin-left: 30px; } + +a { color: steelblue; } + +a:not(:hover) { text-decoration: none; } + +pre, code, textarea { font-family: Menlo, "Menlo Web", monospace; } + +code { line-height: 1em; } + +textarea { font-size: 100%; } + +pre { border-left: 2px solid rgb(204, 204, 204); padding-left: 18px; margin= +: 2em 0px; } + +.html .value, .javascript .string, .javascript .regexp { color: rgb(117, 10= +7, 177); } + +.html .tag, .css .tag, .javascript .keyword { color: rgb(49, 130, 189); } + +.comment { color: rgb(99, 99, 99); } + +.html .doctype, .javascript .number { color: rgb(49, 163, 84); } + +.html .attribute, .css .attribute, .javascript .class, .javascript .special= + { color: rgb(230, 85, 13); } + +svg { font: 10px sans-serif; } + +.axis path, .axis line { fill: none; stroke: rgb(0, 0, 0); shape-rendering:= + crispedges; } + +sup, sub { line-height: 0; } + +q::before { content: "=C3=A2=E2=82=AC=C5=93"; } + +q::after { content: "=C3=A2=E2=82=AC=C2=9D"; } + +blockquote q { line-height: 1.5em; display: inline; } + +blockquote q::before, blockquote q::after { content: ""; } + +h3, h4, p, ul { padding-left: 1.2rem; } + +.banner { padding: 0px; } + +#toc { margin-top: 0px; } + +@media only screen and (max-device-width: 1023px) { + .ocks-org body { font-size: 72%; padding: 0.5rem; } + body > p, div > p { width: 90vw !important; } + li { width: 82vw; } + h3, h4, p, ul { padding-left: 0.7rem; width: 90vw; } + h1 { font-size: 2rem; } + pre { padding-left: 0.5rem; } + .banner, h1, img { max-width: calc(100vw - 2em); min-width: calc(100vw - = +2em); } +} + +@font-face { font-family: "Menlo web"; src: url("OnlineWebFonts_COM_cb7eb79= +6ae7de7195a34c485cacebad1\\@font-face\\9f94dc20bb2a09c15241d3a880b7ad01.wof= +f2") format("woff2"), url("OnlineWebFonts_COM_cb7eb796ae7de7195a34c485caceb= +ad1\\@font-face\\9f94dc20bb2a09c15241d3a880b7ad01.woff") format("woff"); fo= +nt-weight: normal; } + +@font-face { font-family: "Menlo web"; src: url("OnlineWebFonts_COM_d6ba633= +f6ea4cafe1a39ab736fe55e88\\Menlo Bold\\@font-face\\a6ffc5d72a96b65159e710ea= +6d258ba4.woff2") format("woff2"), url("OnlineWebFonts_COM_d6ba633f6ea4cafe1= +a39ab736fe55e88\\Menlo Bold\\@font-face\\a6ffc5d72a96b65159e710ea6d258ba4.w= +off") format("woff"); font-weight: bold; } + +.join, .link, .node rect { fill: none; stroke: rgb(99, 99, 99); stroke-widt= +h: 1.5px; } + +.link { stroke: rgb(150, 150, 150); } + +.node rect { fill: white; } + +.link path, .node rect, .node text, .join { transition: stroke-opacity 500m= +s linear 0s, fill-opacity 500ms linear 0s; } + +.node .element rect { fill: rgb(189, 189, 189); stroke: none; } + +.node .null rect { fill: none; stroke: none; } + +.node .null text { fill: rgb(99, 99, 99); } + +.node .selection rect { stroke: rgb(230, 85, 13); } + +.node .data rect { stroke: rgb(49, 130, 189); } + +.node .datum rect { fill: rgb(217, 217, 217); stroke: none; } + +.node .code text { font-family: monospace; } + +.node .key rect { fill: rgb(161, 217, 155); stroke: none; } + +.link .to-key, .join { stroke: rgb(161, 217, 155); } + +.join { stroke-dasharray: 2, 2; } + +.link .to-null { stroke-dasharray: 0.5, 3.5; stroke-linecap: round; } + +.link .from-data { stroke: rgb(49, 130, 189); } + +.play circle { fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0); stroke-width= +: 3px; } + +.play:hover path { fill: rgb(255, 0, 0); } + +.play.mousedown circle { fill: rgb(255, 0, 0); } + +.play.mousedown path { fill: rgb(255, 255, 255); } + +.play rect { fill: none; pointer-events: all; cursor: pointer; } + +code span { transition: background 250ms linear 0s; } + +pre.prettyprint, code.prettyprint { background-color: rgb(34, 34, 34); bord= +er-radius: 8px; font-size: 15px; } + +pre.prettyprint { width: 90%; margin: 0.5em; padding: 1em; white-space: pre= +-wrap; } + +#return-to-top { position: fixed; bottom: 20px; right: 20px; background: rg= +ba(0, 0, 0, 0.2); width: 50px; height: 50px; text-decoration: none; border-= +radius: 35px; display: none; transition: all 0.3s ease 0s; } + +#return-to-top i { color: rgb(255, 255, 255); margin: 0px; position: relati= +ve; left: 16px; top: 13px; font-size: 19px; transition: all 0.3s ease 0s; } + +#return-to-top:hover { background: rgba(0, 0, 0, 0.35); } + +#return-to-top:hover i { color: rgb(240, 240, 240); } + +@media print { + .pagebreak { break-before: page; } + div { break-inside: avoid; } + pre { break-inside: avoid; } +} + +.modebar { display: none !important; } +------MultipartBoundary--woPjoy8Y4Af6z7kPeFw2jGCIU9O3A2jLmleyvZRmJk---- +Content-Type: text/css +Content-Transfer-Encoding: quoted-printable +Content-Location: https://fonts.googleapis.com/css?family=PT+Serif|PT+Serif:b|PT+Serif:i|PT+Sans|PT+Sans:b + +@charset "utf-8"; + +@font-face { font-family: "PT Sans"; font-style: normal; font-weight: 400; = +src: url("https://fonts.gstatic.com/s/ptsans/v17/jizaRExUiTo99u79D0-ExdGM.w= +off2") format("woff2"); unicode-range: U+460-52F, U+1C80-1C88, U+20B4, U+2D= +E0-2DFF, U+A640-A69F, U+FE2E-FE2F; } + +@font-face { font-family: "PT Sans"; font-style: normal; font-weight: 400; = +src: url("https://fonts.gstatic.com/s/ptsans/v17/jizaRExUiTo99u79D0aExdGM.w= +off2") format("woff2"); unicode-range: U+301, U+400-45F, U+490-491, U+4B0-4= +B1, U+2116; } + +@font-face { font-family: "PT Sans"; font-style: normal; font-weight: 400; = +src: url("https://fonts.gstatic.com/s/ptsans/v17/jizaRExUiTo99u79D0yExdGM.w= +off2") format("woff2"); unicode-range: U+100-2AF, U+304, U+308, U+329, U+1E= +00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F= +, U+A720-A7FF; } + +@font-face { font-family: "PT Sans"; font-style: normal; font-weight: 400; = +src: url("https://fonts.gstatic.com/s/ptsans/v17/jizaRExUiTo99u79D0KExQ.wof= +f2") format("woff2"); unicode-range: U+0-FF, U+131, U+152-153, U+2BB-2BC, U= ++2C6, U+2DA, U+2DC, U+304, U+308, U+329, U+2000-206F, U+2074, U+20AC, U+212= +2, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } + +@font-face { font-family: "PT Sans"; font-style: normal; font-weight: 700; = +src: url("https://fonts.gstatic.com/s/ptsans/v17/jizfRExUiTo99u79B_mh0OOtLQ= +0Z.woff2") format("woff2"); unicode-range: U+460-52F, U+1C80-1C88, U+20B4, = +U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } + +@font-face { font-family: "PT Sans"; font-style: normal; font-weight: 700; = +src: url("https://fonts.gstatic.com/s/ptsans/v17/jizfRExUiTo99u79B_mh0OqtLQ= +0Z.woff2") format("woff2"); unicode-range: U+301, U+400-45F, U+490-491, U+4= +B0-4B1, U+2116; } + +@font-face { font-family: "PT Sans"; font-style: normal; font-weight: 700; = +src: url("https://fonts.gstatic.com/s/ptsans/v17/jizfRExUiTo99u79B_mh0OCtLQ= +0Z.woff2") format("woff2"); unicode-range: U+100-2AF, U+304, U+308, U+329, = +U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-= +2C7F, U+A720-A7FF; } + +@font-face { font-family: "PT Sans"; font-style: normal; font-weight: 700; = +src: url("https://fonts.gstatic.com/s/ptsans/v17/jizfRExUiTo99u79B_mh0O6tLQ= +.woff2") format("woff2"); unicode-range: U+0-FF, U+131, U+152-153, U+2BB-2B= +C, U+2C6, U+2DA, U+2DC, U+304, U+308, U+329, U+2000-206F, U+2074, U+20AC, U= ++2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } + +@font-face { font-family: "PT Serif"; font-style: italic; font-weight: 400;= + src: url("https://fonts.gstatic.com/s/ptserif/v18/EJRTQgYoZZY2vCFuvAFT_rC1= +chb-.woff2") format("woff2"); unicode-range: U+460-52F, U+1C80-1C88, U+20B4= +, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } + +@font-face { font-family: "PT Serif"; font-style: italic; font-weight: 400;= + src: url("https://fonts.gstatic.com/s/ptserif/v18/EJRTQgYoZZY2vCFuvAFT_rm1= +chb-.woff2") format("woff2"); unicode-range: U+301, U+400-45F, U+490-491, U= ++4B0-4B1, U+2116; } + +@font-face { font-family: "PT Serif"; font-style: italic; font-weight: 400;= + src: url("https://fonts.gstatic.com/s/ptserif/v18/EJRTQgYoZZY2vCFuvAFT_rO1= +chb-.woff2") format("woff2"); unicode-range: U+100-2AF, U+304, U+308, U+329= +, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C6= +0-2C7F, U+A720-A7FF; } + +@font-face { font-family: "PT Serif"; font-style: italic; font-weight: 400;= + src: url("https://fonts.gstatic.com/s/ptserif/v18/EJRTQgYoZZY2vCFuvAFT_r21= +cg.woff2") format("woff2"); unicode-range: U+0-FF, U+131, U+152-153, U+2BB-= +2BC, U+2C6, U+2DA, U+2DC, U+304, U+308, U+329, U+2000-206F, U+2074, U+20AC,= + U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } + +@font-face { font-family: "PT Serif"; font-style: normal; font-weight: 400;= + src: url("https://fonts.gstatic.com/s/ptserif/v18/EJRVQgYoZZY2vCFuvAFbzr-t= +dg.woff2") format("woff2"); unicode-range: U+460-52F, U+1C80-1C88, U+20B4, = +U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } + +@font-face { font-family: "PT Serif"; font-style: normal; font-weight: 400;= + src: url("https://fonts.gstatic.com/s/ptserif/v18/EJRVQgYoZZY2vCFuvAFSzr-t= +dg.woff2") format("woff2"); unicode-range: U+301, U+400-45F, U+490-491, U+4= +B0-4B1, U+2116; } + +@font-face { font-family: "PT Serif"; font-style: normal; font-weight: 400;= + src: url("https://fonts.gstatic.com/s/ptserif/v18/EJRVQgYoZZY2vCFuvAFYzr-t= +dg.woff2") format("woff2"); unicode-range: U+100-2AF, U+304, U+308, U+329, = +U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-= +2C7F, U+A720-A7FF; } + +@font-face { font-family: "PT Serif"; font-style: normal; font-weight: 400;= + src: url("https://fonts.gstatic.com/s/ptserif/v18/EJRVQgYoZZY2vCFuvAFWzr8.= +woff2") format("woff2"); unicode-range: U+0-FF, U+131, U+152-153, U+2BB-2BC= +, U+2C6, U+2DA, U+2DC, U+304, U+308, U+329, U+2000-206F, U+2074, U+20AC, U+= +2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } + +@font-face { font-family: "PT Serif"; font-style: normal; font-weight: 700;= + src: url("https://fonts.gstatic.com/s/ptserif/v18/EJRSQgYoZZY2vCFuvAnt66qf= +VyvHpA.woff2") format("woff2"); unicode-range: U+460-52F, U+1C80-1C88, U+20= +B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } + +@font-face { font-family: "PT Serif"; font-style: normal; font-weight: 700;= + src: url("https://fonts.gstatic.com/s/ptserif/v18/EJRSQgYoZZY2vCFuvAnt66qW= +VyvHpA.woff2") format("woff2"); unicode-range: U+301, U+400-45F, U+490-491,= + U+4B0-4B1, U+2116; } + +@font-face { font-family: "PT Serif"; font-style: normal; font-weight: 700;= + src: url("https://fonts.gstatic.com/s/ptserif/v18/EJRSQgYoZZY2vCFuvAnt66qc= +VyvHpA.woff2") format("woff2"); unicode-range: U+100-2AF, U+304, U+308, U+3= +29, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2= +C60-2C7F, U+A720-A7FF; } + +@font-face { font-family: "PT Serif"; font-style: normal; font-weight: 700;= + src: url("https://fonts.gstatic.com/s/ptserif/v18/EJRSQgYoZZY2vCFuvAnt66qS= +Vys.woff2") format("woff2"); unicode-range: U+0-FF, U+131, U+152-153, U+2BB= +-2BC, U+2C6, U+2DA, U+2DC, U+304, U+308, U+329, U+2000-206F, U+2074, U+20AC= +, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } +------MultipartBoundary--woPjoy8Y4Af6z7kPeFw2jGCIU9O3A2jLmleyvZRmJk---- +Content-Type: image/jpeg +Content-Transfer-Encoding: base64 +Content-Location: https://gto76.github.io/python-cheatsheet/web/image_888.jpeg + +/9j/4AAQSkZJRgABAQAAyADIAAD/4QE2RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUA +AAABAAAAYgEbAAUAAAABAAAAagEoAAMAAAABAAIAAAExAAIAAAAmAAAAcgEyAAIAAAAUAAAAmIdp +AAQAAAABAAAArAAAAAAAAADIAAAAAQAAAMgAAAABV2luZG93cyBQaG90byBFZGl0b3IgMTAuMC4x +MDAxMS4xNjM4NAAyMDE2OjA3OjI2IDE0OjI4OjU1AAAHkAMAAgAAABQAAAEGkAQAAgAAABQAAAEa +kpEAAgAAAAMwMAAAkpIAAgAAAAMwMAAAoAEAAwAAAAEAAQAAoAIABAAAAAEAAAN4oAMABAAAAAEA +AADOAAAAADIwMTY6MDc6MjYgMTQ6MjQ6MTgAMjAxNjowNzoyNiAxNDoyNDoxOAD/4QozaHR0cDov +L25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENl +aGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4 +OnhtcHRrPSJYTVAgQ29yZSA1LjQuMCI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53 +My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFi +b3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6cGhv +dG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bXA6TW9kaWZ5RGF0 +ZT0iMjAxNi0wNy0yNlQxNDoyODo1NSIgeG1wOkNyZWF0ZURhdGU9IjIwMTYtMDctMjZUMTQ6MjQ6 +MTguMDAiIHhtcDpDcmVhdG9yVG9vbD0iV2luZG93cyBQaG90byBFZGl0b3IgMTAuMC4xMDAxMS4x +NjM4NCIgcGhvdG9zaG9wOkRhdGVDcmVhdGVkPSIyMDE2LTA3LTI2VDE0OjI0OjE4LjAwIi8+IDwv +cmRmOlJERj4gPC94OnhtcG1ldGE+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgPD94cGFja2V0IGVuZD0idyI/PgD/7QB4UGhvdG9zaG9wIDMuMAA4 +QklNBAQAAAAAAD8cAVoAAxslRxwCAAACAAIcAj8ABjE0MjQxOBwCPgAIMjAxNjA3MjYcAjcACDIw +MTYwNzI2HAI8AAYxNDI0MTgAOEJJTQQlAAAAAAAQhG7+MU6hb9U9cYjjluJSqf/AABEIAM4DeAMB +IgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUE +BAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1 +Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOk +paanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAf +AQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQF +ITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdI +SUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1 +tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2wBDAAMCAgMCAgMDAwME +AwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBD +AQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU +FBQUFBQUFBT/3QAEADj/2gAMAwEAAhEDEQA/AP1KooooAKKKKACiiigAooyKMigAooyKMigAooyK +MigAooyKMigAooyKMigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKK +KACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAoooo +AKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigA +ooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigD/9D9SqKKKACiiigApp606m0AFFFF +ABRRRQAUUlLQAUUUUAFFFFADqKbk0ZNADqKbk0ZNADqKbk0ZNADqKbk0ZNADqKbk0ZNADqKAc0UA +FFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAU +UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRR +RQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAf//R +/Uqig8CvmT9pP9v/AOGX7NmpT6Hf3Fx4k8VwgGXRdHKFrbIBXz5GISIlSGCk7iO3IoA+m+tFfnT8 +Ef8AgrnY/E34qaP4Z17wPD4f0rVruOxhv7XVGuZLeWRgkZlUxKNhYgEqxwWHUcj9FFPY5BHXNADj +0ptO7U2gAooooAKKK8j/AGnv2jtA/Zf+Gb+Ltdt59QeW5SysdMtXVJbu4fJCgsQAoUMzHsqk4NAH +rZ9aM1+M3jr/AIK8/F3XdWmfw9a6D4W00kLDax2bX0ij1aaRkyT7IK+5v2Hf219M/aD+HccfjDXN +F03x7aXb2k1kJFtjdofmimjiZycMvBwSNysPagD60opFbcMjpS0AFFFFABRRRQAUUUUAFFFFABRR +RQAUUUUAKvSlpoOKXcaAFopNxoBJoAWijmkyaAFopNxo3GgBaKTcaNxoAWik3GjcaAFopNxo3GgB +aKTcaA1AC0UA5OKKACiiigAooooAKKKD0oAMijIptFADsiim0lAD6OlMwM5o2jOaAH5opmKAMUAP +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 +/9k= + +------MultipartBoundary--woPjoy8Y4Af6z7kPeFw2jGCIU9O3A2jLmleyvZRmJk------