- if __name__ == '__main__': # Runs main() if file wasn't imported.
- main()
- <list> = <list>[from_inclusive : to_exclusive : ±step_size]
- <list>.append(<el>) # Or: <list> += [<el>]
- <list>.extend(<collection>) # Or: <list> += <collection>
- <list>.sort()
- <list>.reverse()
- <list> = sorted(<collection>)
- <iter> = reversed(<list>)
- sum_of_elements = sum(<collection>)
- elementwise_sum = [sum(pair) for pair in zip(list_a, list_b)]
- sorted_by_second = sorted(<collection>, key=lambda el: el[1])
- sorted_by_both = sorted(<collection>, key=lambda el: (el[1], el[0]))
- flatter_list = list(itertools.chain.from_iterable(<list>))
- product_of_elems = functools.reduce(lambda out, x: out * x, <collection>)
- list_of_chars = list(<str>)
- index = <list>.index(<el>) # Returns index of first occurrence or raises ValueError.
- <list>.insert(index, <el>) # Inserts item at index and moves the rest to the right.
- <el> = <list>.pop([index]) # Removes and returns item at index or from the end.
- <list>.remove(<el>) # Removes first occurrence of item or raises ValueError.
- <list>.clear() # Removes all items. Also works on dictionary and set.
- <view> = <dict>.keys() # Coll. of keys that reflects changes.
- <view> = <dict>.values() # Coll. of values that reflects changes.
- <view> = <dict>.items() # Coll. of key-value tuples.
- value = <dict>.get(key, default=None) # Returns default if key does not exist.
- value = <dict>.setdefault(key, default=None) # Same, but also adds default to dict.
- <dict> = collections.defaultdict(<type>) # Creates a dict with default value of type.
- <dict> = collections.defaultdict(lambda: 1) # Creates a dict with default value 1.
- <dict>.update(<dict>)
- <dict> = dict(<collection>) # Creates a dict from coll. of key-value pairs.
- <dict> = dict(zip(keys, values)) # Creates a dict from two collections.
- <dict> = dict.fromkeys(keys [, value]) # Creates a dict from collection of keys.
- value = <dict>.pop(key) # Removes item from dictionary.
- {k: v for k, v in <dict>.items() if k in keys} # Filters dictionary by keys.
- >>> from collections import Counter
- >>> colors = ['red', 'blue', 'yellow', 'blue', 'red', 'blue']
- >>> counter = Counter(colors)
- Counter({'blue': 3, 'red': 2, 'yellow': 1})
- >>> counter.most_common()[0]
- ('blue', 3)
- <set> = set()
- <set>.add(<el>) # Or: <set> |= {<el>}
- <set>.update(<collection>) # Or: <set> |= <set>
- <set> = <set>.union(<coll.>) # Or: <set> | <set>
- <set> = <set>.intersection(<coll.>) # Or: <set> & <set>
- <set> = <set>.difference(<coll.>) # Or: <set> - <set>
- <set> = <set>.symmetric_difference(<coll.>) # Or: <set> ^ <set>
- <bool> = <set>.issubset(<coll.>) # Or: <set> <= <set>
- <bool> = <set>.issuperset(<coll.>) # Or: <set> >= <set>
- <set>.remove(<el>) # Raises KeyError.
- <set>.discard(<el>) # Doesn't raise an error.
- <frozenset> = frozenset(<collection>)
Tuple is an immutable and hashable list.
- <tuple> = ()
- <tuple> = (<el>, )
- <tuple> = (<el_1>, <el_2>, ...)
Tuple's subclass with named elements.
- >>> from collections import namedtuple
- >>> Point = namedtuple('Point', 'x y')
- >>> p = Point(1, y=2)
- Point(x=1, y=2)
- >>> p[0]
- 1
- >>> p.x
- 1
- >>> getattr(p, 'y')
- 2
- >>> p._fields # Or: Point._fields
- ('x', 'y')
- <range> = range(to_exclusive)
- <range> = range(from_inclusive, to_exclusive)
- <range> = range(from_inclusive, to_exclusive, ±step_size)
- from_inclusive = <range>.start
- to_exclusive = <range>.stop
- for i, el in enumerate(<collection> [, i_start]):
- ...
- <iter> = iter(<collection>) # `iter(<iter>)` returns unmodified iterator.
- <iter> = iter(<function>, to_exclusive) # Sequence of return values until 'to_exclusive'.
- <el> = next(<iter> [, default]) # Raises StopIteration or returns 'default' on end.
- from itertools import count, repeat, cycle, chain, islice
- <iter> = count(start=0, step=1) # Returns incremented value endlessly.
- <iter> = repeat(<el> [, times]) # Returns element endlessly or 'times' times.
- <iter> = cycle(<collection>) # Repeats the sequence indefinitely.
- <iter> = chain(<coll.>, <coll.> [, ...]) # Empties collections in order.
- <iter> = chain.from_iterable(<collection>) # Empties collections inside a collection in order.
- <iter> = islice(<collection>, to_exclusive)
- <iter> = islice(<collection>, from_inclusive, to_exclusive)
- <iter> = islice(<collection>, from_inclusive, to_exclusive, +step_size)
- def count(start, step):
- while True:
- yield start
- start += step
- >>> counter = count(10, 2)
- >>> next(counter), next(counter), next(counter)
- (10, 12, 14)
- <type> = type(<el>) # Or: <el>.__class__
- <bool> = isinstance(<el>, <type>) # Or: issubclass(type(<el>), <type>)
- >>> type('a'), 'a'.__class__, str
- (<class 'str'>, <class 'str'>, <class 'str'>)
- from types import FunctionType, MethodType, LambdaType, GeneratorType
An abstract base class introduces virtual subclasses, that don’t inherit from it but are still recognized by isinstance() and issubclass().
- >>> from collections.abc import Sequence, Collection, Iterable
- >>> isinstance([1, 2, 3], Iterable)
- True
- +------------------+----------+------------+----------+
- | | Sequence | Collection | Iterable |
- +------------------+----------+------------+----------+
- | list, range, str | yes | yes | yes |
- | dict, set | | yes | yes |
- | iter | | | yes |
- +------------------+----------+------------+----------+
-
- >>> from numbers import Integral, Rational, Real, Complex, Number
- >>> isinstance(123, Number)
- True
- +--------------------+----------+----------+--------+---------+--------+
- | | Integral | Rational | Real | Complex | Number |
- +--------------------+----------+----------+--------+---------+--------+
- | int | yes | yes | yes | yes | yes |
- | fractions.Fraction | | yes | yes | yes | yes |
- | float | | | yes | yes | yes |
- | complex | | | | yes | yes |
- | decimal.Decimal | | | | | yes |
- +--------------------+----------+----------+--------+---------+--------+
-
- <str> = <str>.strip() # Strips all whitespace characters from both ends.
- <str> = <str>.strip('<chars>') # Strips all passed characters from both ends.
- <list> = <str>.split() # Splits on one or more whitespace characters.
- <list> = <str>.split(sep=None, maxsplit=-1) # Splits on 'sep' str at most 'maxsplit' times.
- <list> = <str>.splitlines(keepends=False) # Splits on line breaks. Keeps them if 'keepends'.
- <str> = <str>.join(<coll_of_strings>) # Joins elements using string as separator.
- <bool> = <sub_str> in <str> # Checks if string contains a substring.
- <bool> = <str>.startswith(<sub_str>) # Pass tuple of strings for multiple options.
- <bool> = <str>.endswith(<sub_str>) # Pass tuple of strings for multiple options.
- <int> = <str>.find(<sub_str>) # Returns start index of first match or -1.
- <int> = <str>.index(<sub_str>) # Same but raises ValueError.
- <str> = <str>.replace(old, new [, count]) # Replaces 'old' with 'new' at most 'count' times.
- <bool> = <str>.isnumeric() # True if str contains only numeric characters.
- <list> = textwrap.wrap(<str>, width) # Nicely breaks string into lines.
- <str> = chr(<int>) # Converts int to unicode char.
- <int> = ord(<str>) # Converts unicode char to int.
- >>> ord('0'), ord('9')
- (48, 57)
- >>> ord('A'), ord('Z')
- (65, 90)
- >>> ord('a'), ord('z')
- (97, 122)
- import re
- <str> = re.sub(<regex>, new, text, count=0) # Substitutes all occurrences.
- <list> = re.findall(<regex>, text) # Returns all occurrences.
- <list> = re.split(<regex>, text, maxsplit=0) # Use brackets in regex to keep the matches.
- <Match> = re.search(<regex>, text) # Searches for first occurrence of pattern.
- <Match> = re.match(<regex>, text) # Searches only at the beginning of the text.
- <iter> = re.finditer(<regex>, text) # Returns all occurrences as match objects.
- <str> = <Match>.group() # Whole match. Also group(0).
- <str> = <Match>.group(1) # Part in first bracket.
- <tuple> = <Match>.groups() # All bracketed parts.
- <int> = <Match>.start() # Start index of a match.
- <int> = <Match>.end() # Exclusive end index of a match.
- '\d' == '[0-9]' # Digit
- '\s' == '[ \t\n\r\f\v]' # Whitespace
- '\w' == '[a-zA-Z0-9_]' # Alphanumeric
- <str> = f'{<el_1>}, {<el_2>}'
- <str> = '{}, {}'.format(<el_1>, <el_2>)
- >>> from collections import namedtuple
- >>> Person = namedtuple('Person', 'name height')
- >>> person = Person('Jean-Luc', 187)
- >>> f'{person.height}'
- '187'
- >>> '{p.height}'.format(p=person)
- '187'
- {<el>:<10} # '<el> '
- {<el>:^10} # ' <el> '
- {<el>:>10} # ' <el>'
- {<el>:.<10} # '<el>......'
- {<el>:>0} # '<el>'
'!r' calls object's repr() method, instead of str(), to get a string.
- {'abcde'!r:<10} # "'abcde' "
- {'abcde':.3} # 'abc'
- {'abcde':10.3} # 'abc '
- { 123456:10,} # ' 123,456'
- { 123456:10_} # ' 123_456'
- { 123456:+10} # ' +123456'
- {-123456:=10} # '- 123456'
- { 123456: } # ' 123456'
- {-123456: } # '-123456'
- {1.23456:10.3} # ' 1.23'
- {1.23456:10.3f} # ' 1.235'
- {1.23456:10.3e} # ' 1.235e+00'
- {1.23456:10.3%} # ' 123.456%'
- +----------------+----------------+---------------+----------------+-----------------+
- | | {<float>} | {<float>:f} | {<float>:e} | {<float>:%} |
- +----------------+----------------+---------------+----------------+-----------------+
- | 0.000056789 | '5.6789e-05' | '0.000057' | '5.678900e-05' | '0.005679%' |
- | 0.00056789 | '0.00056789' | '0.000568' | '5.678900e-04' | '0.056789%' |
- | 0.0056789 | '0.0056789' | '0.005679' | '5.678900e-03' | '0.567890%' |
- | 0.056789 | '0.056789' | '0.056789' | '5.678900e-02' | '5.678900%' |
- | 0.56789 | '0.56789' | '0.567890' | '5.678900e-01' | '56.789000%' |
- | 5.6789 | '5.6789' | '5.678900' | '5.678900e+00' | '567.890000%' |
- | 56.789 | '56.789 ' | '56.789000' | '5.678900e+01' | '5678.900000%' |
- | 567.89 | '567.89' |'567.890000' | '5.678900e+02' | '56789.000000%' |
- +----------------+----------------+---------------+----------------+-----------------+
-
- +----------------+----------------+---------------+----------------+-----------------+
- | | {<float>:.2} | {<float>:.2f} | {<float>:.2e} | {<float>:.2%} |
- +----------------+----------------+---------------+----------------+-----------------+
- | 0.000056789 | '5.7e-05' | '0.00' | '5.68e-05' | '0.01%' |
- | 0.00056789 | '0.00057' | '0.00' | '5.68e-04' | '0.06%' |
- | 0.0056789 | '0.0057' | '0.01' | '5.68e-03' | '0.57%' |
- | 0.056789 | '0.057' | '0.06' | '5.68e-02' | '5.68%' |
- | 0.56789 | '0.57' | '0.57' | '5.68e-01' | '56.79%' |
- | 5.6789 | '5.7' | '5.68' | '5.68e+00' | '567.89%' |
- | 56.789 | '5.7e+01' | '56.79' | '5.68e+01' | '5678.90%' |
- | 567.89 | '5.7e+02' | '567.89' | '5.68e+02' | '56789.00%' |
- +----------------+----------------+---------------+----------------+-----------------+
-
- {90:c} # 'Z'
- {90:X} # '5A'
- {90:b} # '1011010'
- <int> = int(<float/str/bool>) # Or: math.floor(<float>)
- <float> = float(<int/str/bool>)
- <complex> = complex(real=0, imag=0) # Or: <real> + <real>j
- <Fraction> = fractions.Fraction(numerator=0, denominator=1)
- <Decimal> = decimal.Decimal(<int/float/str>)
- <num> = pow(<num>, <num>) # Or: <num> ** <num>
- <num> = abs(<num>)
- <int> = round(<num>)
- <num> = round(<num>, ±ndigits) # `round(126, -1) == 130`
- from math import e, pi, inf, nan
- from math import cos, acos, sin, asin, tan, atan, degrees, radians
- from math import log, log10, log2
- from statistics import mean, median, variance, pvariance, pstdev
- from random import random, randint, choice, shuffle
- <float> = random()
- <int> = randint(from_inclusive, to_inclusive)
- <el> = choice(<list>)
- shuffle(<list>)
- <int> = 0b<bin> # Or: 0x<hex>
- <int> = int('<bin>', 2) # Or: int('<hex>', 16)
- <int> = int('0b<bin>', 0) # Or: int('0x<hex>', 0)
- '0b<bin>' = bin(<int>) # Or: '0x<hex>' = hex(<int>)
- <int> = <int> & <int> # And
- <int> = <int> | <int> # Or
- <int> = <int> ^ <int> # Xor (0 if both bits equal)
- <int> = <int> << n_bits # Shift left
- <int> = <int> >> n_bits # Shift right
- <int> = ~<int> # Compliment (flips bits)
- from itertools import product, combinations, combinations_with_replacement, permutations
- >>> product([0, 1], repeat=3)
- [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1),
- (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]
- >>> product('ab', '12')
- [('a', '1'), ('a', '2'),
- ('b', '1'), ('b', '2')]
- >>> combinations('abc', 2)
- [('a', 'b'), ('a', 'c'), ('b', 'c')]
- >>> combinations_with_replacement('abc', 2)
- [('a', 'a'), ('a', 'b'), ('a', 'c'),
- ('b', 'b'), ('b', 'c'),
- ('c', 'c')]
- >>> permutations('abc', 2)
- [('a', 'b'), ('a', 'c'),
- ('b', 'a'), ('b', 'c'),
- ('c', 'a'), ('c', 'b')]
- from datetime import date, time, datetime, timedelta
- from dateutil.tz import UTC, tzlocal, gettz
- <D> = date(year, month, day)
- <T> = time(hour=0, minute=0, second=0, microsecond=0, tzinfo=None, fold=0)
- <DT> = datetime(year, month, day, hour=0, minute=0, second=0, ...)
- <TD> = timedelta(days=0, seconds=0, microseconds=0, milliseconds=0,
- minutes=0, hours=0, weeks=0)
- <D/DTn> = D/DT.today() # Current local date or naive datetime.
- <DTn> = DT.utcnow() # Naive datetime from current UTC time.
- <DTa> = DT.now(<tzinfo>) # Aware datetime from current tz time.
- <tzinfo> = UTC # UTC timezone. London without DST.
- <tzinfo> = tzlocal() # Local timezone. Also gettz().
- <tzinfo> = gettz('<Cont.>/<City>') # Timezone from 'Continent/City_Name' str.
- <DTa> = <DT>.astimezone(<tzinfo>) # Datetime, converted to passed timezone.
- <Ta/DTa> = <T/DT>.replace(tzinfo=<tzinfo>) # Unconverted object with new timezone.
- <D/T/DT> = D/T/DT.fromisoformat('<iso>') # Object from ISO string.
- <DT> = DT.strptime(<str>, '<format>') # Datetime from str, according to format.
- <D/DTn> = D/DT.fromordinal(<int>) # D/DTn from days since Christ, at midnight.
- <DTn> = DT.fromtimestamp(<real>) # Local time DTn from seconds since Epoch.
- <DTa> = DT.fromtimestamp(<real>, <tz.>) # Aware datetime from seconds since Epoch.
- <str> = <D/T/DT>.isoformat() # ISO string representation.
- <str> = <D/T/DT>.strftime('<format>') # Custom string representation.
- <int> = <D/DT>.toordinal() # Days since Christ, ignoring time and tz.
- <float> = <DTn>.timestamp() # Seconds since Epoch from DTn in local time.
- <float> = <DTa>.timestamp() # Seconds since Epoch from DTa.
- >>> from datetime import datetime
- >>> dt = datetime.strptime('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"
- <D/DT> = <D/DT> ± <TD>
- <TD> = <TD> ± <TD>
- <TD> = <TD> */ <real>
- <float> = <TD> / <TD>
- <function>(<positional_args>) # f(0, 0)
- <function>(<keyword_args>) # f(x=0, y=0)
- <function>(<positional_args>, <keyword_args>) # f(0, y=0)
- def f(<nondefault_args>): # def f(x, y):
- def f(<default_args>): # def f(x=0, y=0):
- def f(<nondefault_args>, <default_args>): # def f(x, y=0):
Splat expands a collection into positional arguments, while splatty-splat expands a dictionary into keyword arguments.
- args = (1, 2)
- kwargs = {'x': 3, 'y': 4, 'z': 5}
- func(*args, **kwargs)
- func(1, 2, x=3, y=4, z=5)
Splat combines zero or more positional arguments into a tuple, while splatty-splat combines zero or more keyword arguments into a dictionary.
- def add(*a):
- return sum(a)
- >>> add(1, 2, 3)
- 6
- def f(x, y, z): # f(x=1, y=2, z=3) | f(1, y=2, z=3) | f(1, 2, z=3) | f(1, 2, 3)
- def f(*, x, y, z): # f(x=1, y=2, z=3)
- def f(x, *, y, z): # f(x=1, y=2, z=3) | f(1, y=2, z=3)
- def f(x, y, *, z): # f(x=1, y=2, z=3) | f(1, y=2, z=3) | f(1, 2, z=3)
- def f(*args): # f(1, 2, 3)
- def f(x, *args): # f(1, 2, 3)
- def f(*args, z): # f(1, 2, z=3)
- def f(x, *args, z): # f(1, 2, z=3)
- def f(**kwargs): # f(x=1, y=2, z=3)
- def f(x, **kwargs): # f(x=1, y=2, z=3) | f(1, y=2, z=3)
- def f(*, x, **kwargs): # f(x=1, y=2, z=3)
- def f(*args, **kwargs): # f(x=1, y=2, z=3) | f(1, y=2, z=3) | f(1, 2, z=3) | f(1, 2, 3)
- def f(x, *args, **kwargs): # f(x=1, y=2, z=3) | f(1, y=2, z=3) | f(1, 2, z=3) | f(1, 2, 3)
- def f(*args, y, **kwargs): # f(x=1, y=2, z=3) | f(1, y=2, z=3)
- def f(x, *args, z, **kwargs): # f(x=1, y=2, z=3) | f(1, y=2, z=3) | f(1, 2, z=3)
- <list> = [*<collection> [, ...]]
- <set> = {*<collection> [, ...]}
- <tuple> = (*<collection>, [...])
- <dict> = {**<dict> [, ...]}
- head, *body, tail = <collection>
- <function> = lambda: <return_value>
- <function> = lambda <argument_1>, <argument_2>: <return_value>
- <list> = [i+1 for i in range(10)] # [1, 2, ..., 10]
- <set> = {i for i in range(10) if i > 5} # {6, 7, 8, 9}
- <iter> = (i+5 for i in range(10)) # (5, 6, ..., 14)
- <dict> = {i: i*2 for i in range(10)} # {0: 0, 1: 2, ..., 9: 18}
- out = [i+j for i in range(10) for j in range(10)]
- out = []
- for i in range(10):
- for j in range(10):
- out.append(i+j)
- from functools import reduce
- <iter> = map(lambda x: x + 1, range(10)) # (1, 2, ..., 10)
- <iter> = filter(lambda x: x > 5, range(10)) # (6, 7, 8, 9)
- <int> = reduce(lambda out, x: out + x, range(10)) # 45
- <bool> = any(<collection>) # False if empty.
- <bool> = all(el[1] for el in <collection>) # True if empty.
- <expression_if_true> if <condition> else <expression_if_false>
- >>> [a if a else 'zero' for a in (0, 1, 0, 3)]
- ['zero', 1, 'zero', 3]
- from collections import namedtuple
- Point = namedtuple('Point', 'x y')
- point = Point(0, 0)
- from enum import Enum
- Direction = Enum('Direction', 'n e s w')
- direction = Direction.n
- from dataclasses import make_dataclass
- Creature = make_dataclass('Creature', ['location', 'direction'])
- creature = Creature(Point(0, 0), Direction.n)
We have a closure in Python when:
- def get_multiplier(a):
- def out(b):
- return a * b
- return out
- >>> multiply_by_3 = get_multiplier(3)
- >>> multiply_by_3(10)
- 30
- from functools import partial
- <function> = partial(<function> [, <arg_1>, <arg_2>, ...])
- >>> import operator as op
- >>> multiply_by_3 = partial(op.mul, 3)
- >>> multiply_by_3(10)
- 30
If variable is being assigned to anywhere in the scope, it is regarded as a local variable, unless it is declared as a 'global' or a 'nonlocal'.
- def get_counter():
- i = 0
- def out():
- nonlocal i
- i += 1
- return i
- return out
- >>> counter = get_counter()
- >>> counter(), counter(), counter()
- (1, 2, 3)
A decorator takes a function, adds some functionality and returns it.
- @decorator_name
- def function_that_gets_passed_to_decorator():
- ...
Decorator that prints function's name every time it gets called.
- from functools import wraps
-
- def debug(func):
- @wraps(func)
- def out(*args, **kwargs):
- print(func.__name__)
- return func(*args, **kwargs)
- return out
-
- @debug
- def add(x, y):
- return x + y
Decorator that caches function's return values. All function's arguments must be hashable.
- from functools import lru_cache
-
- @lru_cache(maxsize=None)
- def fib(n):
- return n if n < 2 else fib(n-2) + fib(n-1)
A decorator that accepts arguments and returns a normal decorator that accepts a function.
- from functools import wraps
-
- def debug(print_result=False):
- def decorator(func):
- @wraps(func)
- def out(*args, **kwargs):
- result = func(*args, **kwargs)
- print(func.__name__, result if print_result else '')
- return result
- return out
- return decorator
-
- @debug(print_result=True)
- def add(x, y):
- return x + y
- class <name>:
- def __init__(self, a):
- self.a = a
- def __repr__(self):
- class_name = self.__class__.__name__
- return f'{class_name}({self.a!r})'
- def __str__(self):
- return str(self.a)
-
- @classmethod
- def get_class_name(cls):
- return cls.__name__
- print(<el>)
- print(f'{<el>}')
- raise Exception(<el>)
- logging.debug(<el>)
- csv.writer(<file>).writerow([<el>])
- print([<el>])
- print(f'{<el>!r}')
- >>> <el>
- loguru.logger.exception()
- Z = dataclasses.make_dataclass('Z', ['a']); print(Z(<el>))
- class <name>:
- def __init__(self, a=None):
- self.a = a
- class Person:
- def __init__(self, name, age):
- self.name = name
- self.age = age
-
- class Employee(Person):
- def __init__(self, name, age, staff_num):
- super().__init__(name, age)
- self.staff_num = staff_num
- class A: pass
- class B: pass
- class C(A, B): pass
MRO determines the order in which parent classes are traversed when searching for a method:
- >>> C.mro()
- [<class 'C'>, <class 'A'>, <class 'B'>, <class 'object'>]
- class MyClass:
- @property
- def a(self):
- return self._a
-
- @a.setter
- def a(self, value):
- self._a = value
- >>> el = MyClass()
- >>> el.a = 123
- >>> el.a
- 123
Decorator that automatically generates init(), repr() and eq() special methods.
- from dataclasses import dataclass, field
-
- @dataclass(order=False, frozen=False)
- class <class_name>:
- <attr_name_1>: <type>
- <attr_name_2>: <type> = <default_value>
- <attr_name_3>: list/dict/set = field(default_factory=list/dict/set)
Mechanism that restricts objects to attributes listed in 'slots' and significantly reduces their memory footprint.
- class MyClassWithSlots:
- __slots__ = ['a']
- def __init__(self):
- self.a = 1
- from copy import copy, deepcopy
- <object> = copy(<object>)
- <object> = deepcopy(<object>)
A duck type is an implicit type that prescribes a set of special methods. Any object that has those methods defined is considered a member of that duck type.
- class MyComparable:
- def __init__(self, a):
- self.a = a
- def __eq__(self, other):
- if isinstance(other, type(self)):
- return self.a == other.a
- return NotImplemented
- class MyHashable:
- def __init__(self, a):
- self._a = copy.deepcopy(a)
- @property
- def a(self):
- return self._a
- def __eq__(self, other):
- if isinstance(other, type(self)):
- return self.a == other.a
- return NotImplemented
- def __hash__(self):
- return hash(self.a)
- from functools import total_ordering
-
- @total_ordering
- class MySortable:
- def __init__(self, a):
- self.a = a
- def __eq__(self, other):
- if isinstance(other, type(self)):
- return self.a == other.a
- return NotImplemented
- def __lt__(self, other):
- if isinstance(other, type(self)):
- return self.a < other.a
- return NotImplemented
- class Counter:
- def __init__(self):
- self.i = 0
- def __next__(self):
- self.i += 1
- return self.i
- def __iter__(self):
- return self
- >>> counter = Counter()
- >>> next(counter), next(counter), next(counter)
- (1, 2, 3)
- class Counter:
- def __init__(self):
- self.i = 0
- def __call__(self):
- self.i += 1
- return self.i
- >>> counter = Counter()
- >>> counter(), counter(), counter()
- (1, 2, 3)
- class MyOpen():
- def __init__(self, filename):
- self.filename = filename
- def __enter__(self):
- self.file = open(self.filename)
- return self.file
- def __exit__(self, *args):
- 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!
- with open('<path>') as file: ...
- with wave.open('<path>') as wave_file: ...
- with memoryview(<bytes/bytearray/array>) as view: ...
- with concurrent.futures.ThreadPoolExecutor() as executor: ...
- db = sqlite3.connect('<path>'); with db: ...
- lock = threading.RLock(); with lock: ...
- class MyIterable:
- def __init__(self, a):
- self.a = a
- def __iter__(self):
- for el in self.a:
- yield el
- >>> a = MyIterable([1, 2, 3])
- >>> iter(a)
- <generator object MyIterable.__iter__ at 0x1026c18b8>
- >>> 1 in a
- True
- class MyCollection:
- def __init__(self, a):
- self.a = a
- def __iter__(self):
- return iter(self.a)
- def __contains__(self, el):
- return el in self.a
- def __len__(self):
- return len(self.a)
- class MySequence:
- def __init__(self, a):
- self.a = a
- def __iter__(self):
- return iter(self.a)
- def __contains__(self, el):
- return el in self.a
- def __len__(self):
- return len(self.a)
- def __getitem__(self, i):
- return self.a[i]
- def __reversed__(self):
- return reversed(self.a)
- class MyAbcSequence(collections.abc.Sequence):
- def __init__(self, a):
- self.a = a
- def __len__(self):
- return len(self.a)
- def __getitem__(self, i):
- return self.a[i]
- +------------+----------+------------+----------+--------------+
- | | Iterable | Collection | Sequence | abc.Sequence |
- +------------+----------+------------+----------+--------------+
- | iter() | REQ | REQ | yes | yes |
- | contains() | yes | yes | yes | yes |
- | len() | | REQ | REQ | REQ |
- | getitem() | | | REQ | REQ |
- | reversed() | | | yes | yes |
- | index() | | | | yes |
- | count() | | | | yes |
- +------------+----------+------------+----------+--------------+
-
- from enum import Enum, auto
-
- class <enum_name>(Enum):
- <member_name_1> = <value_1>
- <member_name_2> = <value_2_a>, <value_2_b>
- <member_name_3> = auto()
-
- @classmethod
- def get_member_names(cls):
- return [a.name for a in cls.__members__.values()]
- <member> = <enum>.<member_name>
- <member> = <enum>['<member_name>']
- <member> = <enum>(<value>)
- name = <member>.name
- value = <member>.value
- list_of_members = list(<enum>)
- member_names = [a.name for a in <enum>]
- member_values = [a.value for a in <enum>]
- random_member = random.choice(list(<enum>))
- Cutlery = Enum('Cutlery', ['fork', 'knife', 'spoon'])
- Cutlery = Enum('Cutlery', 'fork knife spoon')
- Cutlery = Enum('Cutlery', {'fork': 1, 'knife': 2, 'spoon': 3})
- from functools import partial
- LogicOp = Enum('LogicOp', {'AND': partial(lambda l, r: l and r),
- 'OR' : partial(lambda l, r: l or r)})
- try:
- <code>
- except <exception>:
- <code>
- try:
- <code_1>
- except <exception_a>:
- <code_2_a>
- except <exception_b>:
- <code_2_b>
- else:
- <code_2_c>
- finally:
- <code_3>
- except <exception>:
- except <exception> as <name>:
- except (<exception_1>, <exception_2>, ...):
- except (<exception_1>, <exception_2>, ...) as <name>:
- raise <exception>
- raise <exception>()
- raise <exception>(<el>)
- raise <exception>(<el_1>, <el_2>, ...)
- raise ValueError('Argument is of right type but inappropriate value!')
- raise TypeError('Argument is of wrong type!')
- raise RuntimeError('None of above!')
- except <exception>:
- <code>
- raise
- BaseException
- +-- SystemExit # Raised by the sys.exit() function.
- +-- KeyboardInterrupt # Raised when the user hits the interrupt key.
- +-- Exception # User-defined exceptions should be derived from this class.
- +-- StopIteration # Raised by next() when run on an empty iterator.
- +-- ArithmeticError # Base class for arithmetic errors.
- | +-- ZeroDivisionError # Raised when dividing by zero.
- +-- AttributeError # Raised when an attribute is missing.
- +-- EOFError # Raised by input() when it hits end-of-file condition.
- +-- LookupError # Raised when a look-up on sequence or dict fails.
- | +-- IndexError # Raised when a sequence index is out of range.
- | +-- KeyError # Raised when a dictionary key is not found.
- +-- NameError # Raised when a variable name is not found.
- +-- OSError # Failures such as “file not found” or “disk full”.
- | +-- FileNotFoundError # When a file or directory is requested but doesn't exist.
- +-- RuntimeError # Raised by errors that don't fall in other categories.
- | +-- RecursionError # Raised when the the maximum recursion depth is exceeded.
- +-- TypeError # Raised when an argument is of wrong type.
- +-- ValueError # When an argument is of right type but inappropriate value.
- +-- UnicodeError # Raised when encoding/decoding strings from/to bytes fails.
-
- class MyError(Exception):
- pass
-
- class MyInputError(MyError):
- pass
- print(<el_1>, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
- >>> from pprint import pprint
- >>> pprint(dir())
- ['__annotations__',
- '__builtins__',
- '__doc__', ...]
- <str> = input(prompt=None)
- while True:
- try:
- print(input())
- except EOFError:
- break
- import sys
- script_name = sys.argv[0]
- arguments = sys.argv[1:]
- from argparse import ArgumentParser, FileType
- p = ArgumentParser(description=<str>)
- p.add_argument('-<short_name>', '--<name>', action='store_true') # Flag
- p.add_argument('-<short_name>', '--<name>', type=<type>) # Option
- p.add_argument('<name>', type=<type>, nargs=1) # Argument
- p.add_argument('<name>', type=<type>, nargs='+') # Arguments
- args = p.parse_args()
- value = args.<name>
Opens a file and returns a corresponding file object.
- <file> = open('<path>', mode='r', encoding=None, newline=None)
- <file>.seek(0) # Moves to the start of the file.
- <file>.seek(offset) # Moves 'offset' chars/bytes from the start.
- <file>.seek(0, 2) # Moves to the end of the file.
- <bin_file>.seek(±offset, <anchor>) # Anchor: 0 start, 1 current pos., 2 end.
- <str/bytes> = <file>.read(size=-1) # Reads 'size' chars/bytes or until EOF.
- <str/bytes> = <file>.readline() # Returns a line or empty string on EOF.
- <list> = <file>.readlines() # Returns a list of remaining lines.
- <str/bytes> = next(<file>) # Returns a line using buffer. Do not mix.
- <file>.write(<str/bytes>) # Writes a string or bytes object.
- <file>.writelines(<coll.>) # Writes a coll. of strings or bytes objects.
- <file>.flush() # Flushes write buffer.
- def read_file(filename):
- with open(filename, encoding='utf-8') as file:
- return file.readlines()
- def write_to_file(filename, text):
- with open(filename, 'w', encoding='utf-8') as file:
- file.write(text)
- from os import path, listdir
- from glob import glob
- <bool> = path.exists('<path>')
- <bool> = path.isfile('<path>')
- <bool> = path.isdir('<path>')
- <list> = listdir('<path>') # List of filenames located at path.
- <list> = glob('<pattern>') # Filenames matching the wildcard pattern.
- from pathlib import Path
- cwd = Path()
- <Path> = Path('<path>' [, '<path>', <Path>, ...])
- <Path> = <Path> / '<dir>' / '<file>'
- <bool> = <Path>.exists()
- <bool> = <Path>.is_file()
- <bool> = <Path>.is_dir()
- <iter> = <Path>.iterdir() # Returns dir contents as Path objects.
- <iter> = <Path>.glob('<pattern>') # Returns Paths matching the wildcard pattern.
- <str> = str(<Path>) # Path as a string.
- <str> = <Path>.name # Final component.
- <str> = <Path>.stem # Final component without extension.
- <str> = <Path>.suffix # Final component's extension.
- <tup.> = <Path>.parts # All components as strings.
- <Path> = <Path>.resolve() # Returns absolute path without symlinks.
- <Path> = <Path>.parent # Returns path without final component.
- <file> = open(<Path>) # Opens a file and returns file object.
- import os, shutil
- <str> = os.getcwd() # Returns the current working directory.
- os.chdir(<path>) # Changes current working directory.
- shutil.copy(from, to) # Copies the file.
- os.rename(from, to) # Renames the file or directory.
- os.replace(from, to) # Same, but overwrites 'to' if it exists.
- os.remove(<path>) # Deletes the file.
- os.rmdir(<path>) # Deletes empty directory.
- shutil.rmtree(<path>) # Deletes the entire directory tree.
- os.mkdir(<path>, mode=0o777) # Creates a directory.
- <iter> = os.scandir(path='.') # Returns os.DirEntry objects located at path.
- <bool> = <DirEntry>.is_file()
- <bool> = <DirEntry>.is_dir()
- <str> = <DirEntry>.path # Path as a string.
- <str> = <DirEntry>.name # Final component.
- <Path> = Path(<DirEntry>) # Path object.
- <file> = open(<DirEntry>) # File object.
- import os
- <str> = os.popen('<shell_command>').read()
- >>> import subprocess, shlex
- >>> a = subprocess.run(shlex.split('ls -a'), stdout=subprocess.PIPE)
- >>> a.stdout
- b'.\n..\nfile1.txt\nfile2.txt\n'
- >>> a.returncode
- 0
- from csv import reader, writer
- <reader> = reader(<file>, dialect='excel', delimiter=',')
- <list> = next(<reader>) # Returns next row as list of strings.
- <writer> = writer(<file>, dialect='excel', delimiter=',')
- <writer>.writerow(<collection>) # Encodes objects using `str(<el>)`.
- <writer>.writerows(<coll_of_coll>)
- +------------------+-----------+-----------+--------------+
- | | excel | excel_tab | unix_dialect |
- +------------------+-----------+-----------+--------------+
- | delimiter | ',' | '\t' | ',' |
- | quotechar | '"' | '"' | '"' |
- | doublequote | True | True | True |
- | skipinitialspace | False | False | False |
- | lineterminator | '\r\n' | '\r\n' | '\n' |
- | quoting | 0 | 0 | 1 |
- | escapechar | None | None | None |
- +------------------+-----------+-----------+--------------+
-
- def read_csv_file(filename):
- with open(filename, encoding='utf-8', newline='') as file:
- return csv.reader(file)
- def write_to_csv_file(filename, rows):
- with open(filename, 'w', encoding='utf-8', newline='') as file:
- writer = csv.writer(file)
- writer.writerows(rows)
- import json
- <str> = json.dumps(<object>, ensure_ascii=True, indent=None)
- <object> = json.loads(<str>)
- def read_json_file(filename):
- with open(filename, encoding='utf-8') as file:
- return json.load(file)
- def write_to_json_file(filename, an_object):
- with open(filename, 'w', encoding='utf-8') as file:
- json.dump(an_object, file, ensure_ascii=False, indent=2)
- import pickle
- <bytes> = pickle.dumps(<object>)
- <object> = pickle.loads(<bytes>)
- def read_pickle_file(filename):
- with open(filename, 'rb') as file:
- return pickle.load(file)
- def write_to_pickle_file(filename, an_object):
- with open(filename, 'wb') as file:
- pickle.dump(an_object, file)
Server-less database engine that stores each database into separate file.
- import sqlite3
- db = sqlite3.connect('<path>') # Also ':memory:'.
- ...
- db.close()
- cursor = db.execute('<query>')
- if cursor:
- <tuple> = cursor.fetchone() # First row. Also next(cursor).
- <list> = cursor.fetchall() # Remaining rows.
- db.execute('<query>')
- db.commit()
- with db:
- db.execute('<query>')
- db.execute('<query>', <list/tuple>) # Replaces '?'s in query with values.
- db.execute('<query>', <dict/namedtuple>) # Replaces ':<key>'s with values.
- db.executemany('<query>', <coll_of_above>) # Runs execute() many times.
- >>> db = sqlite3.connect('test.db')
- >>> db.execute('create table t (a, b, c)')
- >>> db.execute('insert into t values (1, 2, 3)')
- >>> db.execute('select * from t').fetchall()
- [(1, 2, 3)]
Has a very similar interface, with differences listed below.
- # $ pip3 install mysql-connector
- from mysql import connector
- db = connector.connect(host=<str>, user=<str>, password=<str>, database=<str>)
- cursor = db.cursor()
- cursor.execute('<query>') # Only cursor has execute method.
- cursor.execute('<query>', <list/tuple>) # Replaces '%s's in query with values.
- cursor.execute('<query>', <dict/namedtuple>) # Replaces '%(<key>)s's with values.
Bytes object is an immutable sequence of single bytes. Mutable version is called 'bytearray'.
- <bytes> = b'<str>' # Only accepts ASCII characters and \x00 - \xff.
- <int> = <bytes>[<index>] # Returns int in range from 0 to 255.
- <bytes> = <bytes>[<slice>] # Returns bytes even if it has only one element.
- <bytes> = <bytes>.join(<coll_of_bytes>) # Joins elements using bytes object as separator.
- <bytes> = <str>.encode('utf-8') # Or: bytes(<str>, 'utf-8')
- <bytes> = bytes(<coll_of_ints>) # Ints must be in range from 0 to 255.
- <bytes> = <int>.to_bytes(<length>, byteorder='big|little', signed=False)
- <bytes> = bytes.fromhex('<hex>')
- <str> = <bytes>.decode('utf-8') # Or: str(<bytes>, 'utf-8')
- <list> = list(<bytes>) # Returns ints in range from 0 to 255.
- <int> = int.from_bytes(<bytes>, byteorder='big|little', signed=False)
- '<hex>' = <bytes>.hex()
- def read_bytes(filename):
- with open(filename, 'rb') as file:
- return file.read()
- def write_bytes(filename, bytes_obj):
- with open(filename, 'wb') as file:
- file.write(bytes_obj)
- from struct import pack, unpack, iter_unpack, calcsize
- <bytes> = pack('<format>', <num_1> [, <num_2>, ...])
- <tuple> = unpack('<format>', <bytes>)
- <tuples> = iter_unpack('<format>', <bytes>)
- >>> pack('>hhl', 1, 2, 3)
- b'\x00\x01\x00\x02\x00\x00\x00\x03'
- >>> unpack('>hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
- (1, 2, 3)
List that can only hold numbers of predefined type. Available types and their sizes in bytes are listed above.
- from array import array
- <array> = array('<typecode>' [, <collection>])
Used for accessing the internal data of an object that supports the buffer protocol.
- <memoryview> = memoryview(<bytes> / <bytearray> / <array>)
- <memoryview>.release()
A thread-safe list with efficient appends and pops from either side. Pronounced "deck".
- from collections import deque
- <deque> = deque(<collection>, maxlen=None)
- <deque>.appendleft(<el>)
- <el> = <deque>.popleft()
- <deque>.extendleft(<collection>) # Collection gets reversed.
- <deque>.rotate(n=1) # Rotates elements to the right.
- >>> a = deque([1, 2, 3], maxlen=3)
- >>> a.append(4)
- [2, 3, 4]
- >>> a.appendleft(5)
- [5, 2, 3]
- >>> a.insert(1, 6)
- IndexError: deque already at its maximum size
- from threading import Thread, RLock
- thread = Thread(target=<function>, args=(<first_arg>, ))
- thread.start()
- ...
- thread.join()
- lock = RLock()
- lock.acquire()
- ...
- lock.release()
- lock = RLock()
- with lock:
- ...
- from concurrent.futures import ThreadPoolExecutor
- with ThreadPoolExecutor(max_workers=None) as executor:
- results = executor.map(lambda x: x + 1, range(3)) # (1, 2, 3)
- results = executor.map(lambda x, y: x + y, 'abc', '123') # ('a1', 'b2', 'c3')
- from operator import add, sub, mul, truediv, floordiv, mod, pow, neg, abs
- from operator import eq, ne, lt, le, gt, ge
- from operator import and_, or_, not_
- from operator import itemgetter, attrgetter, methodcaller
- import operator as op
- sorted_by_second = sorted(<collection>, key=op.itemgetter(1))
- sorted_by_both = sorted(<collection>, key=op.itemgetter(1, 0))
- product_of_elems = functools.reduce(op.mul, <collection>)
- LogicOp = enum.Enum('LogicOp', {'AND': op.and_, 'OR' : op.or_})
- last_el = op.methodcaller('pop')(<list>)
- >>> from ast import literal_eval
- >>> literal_eval('1 + 2')
- 3
- >>> literal_eval('[1, 2, 3]')
- [1, 2, 3]
- >>> literal_eval('abs(1)')
- ValueError: malformed node or string
Inspecting code at runtime.
- <list> = dir() # Names of variables in current scope.
- <dict> = locals() # Dict of local variables. Also vars().
- <dict> = globals() # Dict of global variables.
- <dict> = vars(<object>)
- <bool> = hasattr(<object>, '<attr_name>')
- value = getattr(<object>, '<attr_name>')
- setattr(<object>, '<attr_name>', value)
- from inspect import signature
- <sig> = signature(<function>)
- no_of_params = len(<sig>.parameters)
- param_names = list(<sig>.parameters.keys())
Code that generates code.
Type is the root class. If only passed an object it returns its type (class). Otherwise it creates a new class.
- <class> = type(<class_name>, <parents_tuple>, <attributes_dict>)
- >>> Z = type('Z', (), {'a': 'abcde', 'b': 12345})
- >>> z = Z()
Class that creates class.
- def my_meta_class(name, parents, attrs):
- attrs['a'] = 'abcde'
- return type(name, parents, attrs)
- class MyMetaClass(type):
- def __new__(cls, name, parents, attrs):
- attrs['a'] = 'abcde'
- return type.__new__(cls, name, parents, attrs)
Right before a class is created it checks if it has metaclass defined. If not, it recursively checks if any of his parents has it defined and eventually comes to type().
- class MyClass(metaclass=MyMetaClass):
- b = 12345
- >>> MyClass.a, MyClass.b
- ('abcde', 12345)
- type(MyClass) == MyMetaClass # MyClass is an instance of MyMetaClass.
- type(MyMetaClass) == type # MyMetaClass is an instance of type.
- +---------+-------------+
- | Classes | Metaclasses |
- +---------+-------------|
- | MyClass > MyMetaClass |
- | | v |
- | object ---> type <+ |
- | | ^ +---+ |
- | str -------+ |
- +---------+-------------+
-
- MyClass.__base__ == object # MyClass is a subclass of object.
- MyMetaClass.__base__ == type # MyMetaClass is a subclass of type.
- +---------+-------------+
- | Classes | Metaclasses |
- +---------+-------------|
- | MyClass | MyMetaClass |
- | v | v |
- | object <--- type |
- | ^ | |
- | str | |
- +---------+-------------+
-
- def coroutine(func):
- def out(*args, **kwargs):
- cr = func(*args, **kwargs)
- next(cr)
- return cr
- return out
- def reader(target):
- for i in range(10):
- target.send(i)
- target.close()
-
- @coroutine
- def adder(target):
- while True:
- value = (yield)
- target.send(value + 100)
-
- @coroutine
- def printer():
- while True:
- value = (yield)
- print(value)
-
- reader(adder(printer())) # 100, 101, ..., 109
- # $ pip3 install tqdm
- from tqdm import tqdm
- from time import sleep
- for i in tqdm([1, 2, 3]):
- sleep(0.2)
- for i in tqdm(range(100)):
- sleep(0.02)
- # $ pip3 install matplotlib
- from matplotlib import pyplot
- pyplot.plot(<data_1> [, <data_2>, ...]) # Or: hist(<data>).
- pyplot.savefig(<filename>)
- pyplot.show()
- pyplot.clf() # Clears figure.
- # $ pip3 install tabulate
- from tabulate import tabulate
- import csv
- with open(<filename>, encoding='utf-8', newline='') as file:
- lines = csv.reader(file)
- headers = [header.title() for header in next(lines)]
- table = tabulate(lines, headers)
- print(table)
- from curses import wrapper, ascii
-
- def main():
- wrapper(draw)
-
- def draw(screen):
- screen.clear()
- screen.addstr(0, 0, 'Press ESC to quit.')
- while screen.getch() != ascii.ESC:
- pass
-
- def get_border(screen):
- from collections import namedtuple
- P = namedtuple('P', 'y x')
- height, width = screen.getmaxyx()
- return P(height-1, width-1)
-
- if __name__ == '__main__':
- main()
- # $ pip3 install loguru
- from loguru import logger
- logger.add('debug_{time}.log', colorize=True) # Connects a log file.
- logger.add('error_{time}.log', level='ERROR') # Another file for errors or higher.
- logger.<level>('A logging message.')
Error description, stack trace and values of variables are appended automatically.
- try:
- ...
- except <exception>:
- logger.exception('An error happened.')
Argument that sets a condition when a new log file is created.
- rotation=<int>|<datetime.timedelta>|<datetime.time>|<str>
Sets a condition which old log files are deleted.
- retention=<int>|<datetime.timedelta>|<str>
- # $ pip3 install requests beautifulsoup4
- import requests
- from bs4 import BeautifulSoup
- url = 'https://en.wikipedia.org/wiki/Python_(programming_language)'
- html = requests.get(url).text
- doc = BeautifulSoup(html, 'html.parser')
- table = doc.find('table', class_='infobox vevent')
- rows = table.find_all('tr')
- link = rows[11].find('a')['href']
- ver = rows[6].find('div').text.split()[0]
- url_i = rows[0].find('img')['src']
- image = requests.get(f'https:{url_i}').content
- with open('test.png', 'wb') as file:
- file.write(image)
- print(link, ver)
- # $ pip3 install bottle
- from bottle import run, route, post, template, request, response
- import json
- run(host='localhost', port=8080)
- run(host='0.0.0.0', port=80, server='cherrypy')
- @route('/img/<image>')
- def send_image(image):
- return static_file(image, 'images/', mimetype='image/png')
- @route('/<sport>')
- def send_page(sport):
- return template('<h1>{{title}}</h1>', title=sport)
- @post('/odds/<sport>')
- def odds_handler(sport):
- team = request.forms.get('team')
- home_odds, away_odds = 2.44, 3.29
- response.headers['Content-Type'] = 'application/json'
- response.headers['Cache-Control'] = 'no-cache'
- return json.dumps([team, home_odds, away_odds])
- # $ pip3 install requests
- >>> import requests
- >>> url = 'http://localhost:8080/odds/football'
- >>> data = {'team': 'arsenal f.c.'}
- >>> response = requests.post(url, data=data)
- >>> response.json()
- ['arsenal f.c.', 2.44, 3.29]
- from time import time
- start_time = time() # Seconds since Epoch.
- ...
- duration = time() - start_time
- from time import perf_counter as pc
- start_time = pc() # Seconds since restart.
- ...
- duration = pc() - start_time
- >>> from timeit import timeit
- >>> timeit('"-".join(str(a) for a in range(100))',
- ... number=10000, globals=globals(), setup='pass')
- 0.34986
- # $ pip3 install line_profiler
- @profile
- def main():
- a = [*range(10000)]
- b = {*range(10000)}
- main()
- $ kernprof -lv test.py
- Line # Hits Time Per Hit % Time Line Contents
- ==============================================================
- 1 @profile
- 2 def main():
- 3 1 1128.0 1128.0 27.4 a = [*range(10000)]
- 4 1 2994.0 2994.0 72.6 b = {*range(10000)}
-
- # $ pip3 install pycallgraph
- from pycallgraph import output, PyCallGraph
- from datetime import datetime
- time_str = datetime.now().strftime('%Y%m%d%H%M%S')
- filename = f'profile-{time_str}.png'
- drawer = output.GraphvizOutput(output_file=filename)
- with PyCallGraph(drawer):
- <code_to_be_profiled>
Array manipulation mini language. Can run up to one hundred times faster than equivalent Python code.
- # $ pip3 install numpy
- import numpy as np
- <array> = np.array(<list>)
- <array> = np.arange(from_inclusive, to_exclusive, ±step_size)
- <array> = np.ones(<shape>)
- <array> = np.random.randint(from_inclusive, to_exclusive, <shape>)
- <array>.shape = <shape>
- <view> = <array>.reshape(<shape>)
- <view> = np.broadcast_to(<array>, <shape>)
- <array> = <array>.sum(axis)
- indexes = <array>.argmin(axis)
- <el> = <2d_array>[0, 0] # First element.
- <1d_view> = <2d_array>[0] # First row.
- <1d_view> = <2d_array>[:, 0] # First column. Also [..., 0].
- <3d_view> = <2d_array>[None, :, :] # Expanded by dimension of size 1.
- <1d_array> = <2d_array>[<1d_row_indexes>, <1d_column_indexes>]
- <2d_array> = <2d_array>[<2d_row_indexes>, <2d_column_indexes>]
- <2d_bools> = <2d_array> > 0
- <1d_array> = <2d_array>[<2d_bools>]
Broadcasting is a set of rules by which NumPy functions operate on arrays of different sizes and/or dimensions.
- left = [[0.1], [0.6], [0.8]] # Shape: (3, 1)
- right = [ 0.1 , 0.6 , 0.8 ] # Shape: (3)
- left = [[0.1], [0.6], [0.8]] # Shape: (3, 1)
- right = [[0.1 , 0.6 , 0.8]] # Shape: (1, 3) <- !
- left = [[0.1, 0.1, 0.1], [0.6, 0.6, 0.6], [0.8, 0.8, 0.8]] # Shape: (3, 3) <- !
- right = [[0.1, 0.6, 0.8], [0.1, 0.6, 0.8], [0.1, 0.6, 0.8]] # Shape: (3, 3) <- !
- >>> points = np.array([0.1, 0.6, 0.8])
- [ 0.1, 0.6, 0.8]
- >>> wrapped_points = points.reshape(3, 1)
- [[ 0.1],
- [ 0.6],
- [ 0.8]]
- >>> distances = wrapped_points - points
- [[ 0. , -0.5, -0.7],
- [ 0.5, 0. , -0.2],
- [ 0.7, 0.2, 0. ]]
- >>> distances = np.abs(distances)
- [[ 0. , 0.5, 0.7],
- [ 0.5, 0. , 0.2],
- [ 0.7, 0.2, 0. ]]
- >>> i = np.arange(3)
- [0, 1, 2]
- >>> distances[i, i] = np.inf
- [[ inf, 0.5, 0.7],
- [ 0.5, inf, 0.2],
- [ 0.7, 0.2, inf]]
- >>> distances.argmin(1)
- [1, 2, 1]
- # $ pip3 install pillow
- from PIL import Image
- width = 100
- height = 100
- size = width * height
- pixels = [255 * i/size for i in range(size)]
-
- img = Image.new('HSV', (width, height))
- img.putdata([(int(a), 255, 255) for a in pixels])
- img.convert(mode='RGB').save('test.png')
- from random import randint
- add_noise = lambda value: max(0, min(255, value + randint(-20, 20)))
- img = Image.open('test.png').convert(mode='HSV')
- img.putdata([(add_noise(h), s, v) for h, s, v in img.getdata()])
- img.convert(mode='RGB').save('test.png')
- import wave
- from struct import pack, iter_unpack
- def read_wav_file(filename):
- with wave.open(filename, 'rb') as wf:
- frames = wf.readframes(wf.getnframes())
- return [a[0] for a in iter_unpack('<h', frames)]
- def write_to_wav_file(filename, frames_int, mono=True):
- frames_short = (pack('<h', a) for a in frames_int)
- with wave.open(filename, 'wb') as wf:
- wf.setnchannels(1 if mono else 2)
- wf.setsampwidth(2)
- wf.setframerate(44100)
- wf.writeframes(b''.join(frames_short))
- from math import pi, sin
- frames_f = (sin(i * 2 * pi * 440 / 44100) for i in range(100000))
- frames_i = (int(a * 30000) for a in frames_f)
- write_to_wav_file('test.wav', frames_i)
- from random import randint
- add_noise = lambda value: max(-32768, min(32767, value + randint(-500, 500)))
- frames_i = (add_noise(a) for a in read_wav_file('test.wav'))
- write_to_wav_file('test.wav', frames_i)
- # $ pip3 install simpleaudio
- import simpleaudio, math, struct
- from itertools import chain, repeat
- F = 44100
- P1 = '71♪,69,,71♪,66,,62♪,66,,59♪,,,'
- P2 = '71♪,73,,74♪,73,,74,,71,,73♪,71,,73,,69,,71♪,69,,71,,67,,71♪,,,'
- get_pause = lambda seconds: repeat(0, int(seconds * F))
- sin_f = lambda i, hz: math.sin(i * 2 * math.pi * hz / F)
- get_wave = lambda hz, seconds: (sin_f(i, hz) for i in range(int(seconds * F)))
- get_hz = lambda key: 8.176 * 2 ** (int(key) / 12)
- parse_note = lambda note: (get_hz(note[:2]), 0.25 if '♪' in note else 0.125)
- get_frames = lambda note: get_wave(*parse_note(note)) if note else get_pause(0.125)
- frames_f = chain.from_iterable(get_frames(n) for n in f'{P1}{P1}{P2}'.split(','))
- frames_b = b''.join(struct.pack('<h', int(f * 30000)) for f in frames_f)
- simpleaudio.play_buffer(frames_b, 1, 2, F)
- #!/usr/bin/env python3
- #
- # Usage: .py
-
- from collections import namedtuple
- from dataclasses import make_dataclass
- from enum import Enum
- import re
- import sys
-
- def main():
- pass
-
- ###
- ## UTIL
- #
-
- def read_file(filename):
- with open(filename, encoding='utf-8') as file:
- return file.readlines()
-
- if __name__ == '__main__':
- main()