diff --git a/README.md b/README.md index 6e429db21..98d33fb3c 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,9 @@ List ---- ```python = [from_inclusive : to_exclusive : step_size] +``` + +```python .append() .extend() += [] @@ -37,17 +40,16 @@ sum_of_elements = sum() elementwise_sum = [sum(pair) for pair in zip(list_a, list_b)] sorted_by_second = sorted(, key=lambda el: el[1]) sorted_by_both = sorted(, key=lambda el: (el[1], el[0])) -flattened_list = list(itertools.chain.from_iterable()) -list_of_chars = list() +flatter_list = list(itertools.chain.from_iterable()) product_of_elems = functools.reduce(lambda out, x: out * x, ) -no_duplicates = list(dict.fromkeys()) +list_of_chars = list() ``` ```python index = .index() # Returns first index of item. .insert(index, ) # Inserts item at index and moves the rest to the right. = .pop([index]) # Removes and returns item at index or from the end. -.remove() # Removes first occurrence of item. +.remove() # Removes first occurrence of item or raises ValueError. .clear() # Removes all items. ``` @@ -61,17 +63,17 @@ Dictionary ``` ```python -value = .get(key, default) # Returns default if key does not exist. -value = .setdefault(key, default) # Same, but also adds default to dict. - = collections.defaultdict() # Creates a dictionary with default value of type. - = collections.defaultdict(lambda: 1) # Creates a dictionary with default value 1. +value = .get(key, default=None) # Returns default if key does not exist. +value = .setdefault(key, default=None) # Same, but also adds default to dict. + = collections.defaultdict() # Creates a dict with default value of type. + = collections.defaultdict(lambda: 1) # Creates a dict with default value 1. ``` ```python -.update() # Or: dict_a = {**dict_a, **dict_b}. - = dict() # Initiates a dict from list of key-value pairs. - = dict(zip(keys, values)) # Initiates a dict from two lists. - = dict.fromkeys(keys [, value]) # Initiates a dict from list of keys. +.update() # Or: dict_a = {**dict_a, **dict_b}. + = dict() # Creates a dict from coll. of key-value pairs. + = dict(zip(keys, values)) # Creates a dict from two collections. + = dict.fromkeys(keys [, value]) # Creates a dict from collection of keys. ``` ```python @@ -82,11 +84,11 @@ value = .pop(key) # Removes item from dictionary. ### Counter ```python >>> from collections import Counter ->>> colors = ['blue', 'red', 'blue', 'yellow', 'blue', 'red'] +>>> colors = ['red', 'blue', 'yellow', 'blue', 'red', 'blue'] >>> counter = Counter(colors) Counter({'blue': 3, 'red': 2, 'yellow': 1}) ->>> counter.most_common()[0][0] -'blue' +>>> counter.most_common()[0] +('blue', 3) ``` @@ -94,6 +96,9 @@ Set --- ```python = set() +``` + +```python .add() .update() |= {} @@ -115,7 +120,7 @@ Set ``` ### Frozenset -#### Is hashable and can be used as a key in dictionary. +#### Is hashable, meaning it can be used as a key in dictionary or as an element in set. ```python = frozenset() ``` @@ -124,10 +129,9 @@ Set Range ----- ```python -range(to_exclusive) -range(from_inclusive, to_exclusive) -range(from_inclusive, to_exclusive, step_size) -range(from_inclusive, to_exclusive, -step_size) + = range(to_exclusive) + = range(from_inclusive, to_exclusive) + = range(from_inclusive, to_exclusive, ±step_size) ``` ```python @@ -146,8 +150,12 @@ for i, el in enumerate( [, i_start]): Named Tuple ----------- +* **Tuple is an immutable and hashable list.** +* **Named tuple is its subclass with named elements.** + ```python ->>> Point = collections.namedtuple('Point', 'x y') +>>> from collections import namedtuple +>>> Point = namedtuple('Point', 'x y') >>> p = Point(1, y=2) Point(x=1, y=2) >>> p[0] @@ -163,29 +171,33 @@ Point(x=1, y=2) Iterator -------- +**In this cheatsheet `''` can also mean an iterator.** + +```python +from itertools import count, repeat, cycle, chain, islice +``` + ```python = iter() - = iter(, to_exclusive) + = iter(, to_exclusive) # Sequence of return values until 'to_exclusive'. + = next( [, default]) # Raises StopIteration or returns 'default' on end. ``` -#### Skips first element: ```python -next() -for element in : - ... + = count(start=0, step=1) # Returns incremented value endlessly. + = repeat( [, times]) # Returns element endlessly or 'times' times. + = cycle() # Repeats the sequence indefinitely. ``` -#### Reads input until it reaches an empty line: ```python -for line in iter(input, ''): - ... + = chain(, ) # Empties collections in order. + = chain.from_iterable() # Empties collections inside a collection in order. ``` -#### Same, but prints a message every time: ```python -from functools import partial -for line in iter(partial(input, 'Please enter value: '), ''): - ... + = islice(, to_exclusive) + = islice(, from_inclusive, to_exclusive) + = islice(, from_inclusive, to_exclusive, step_size) ``` @@ -194,15 +206,15 @@ Generator **Convenient way to implement the iterator protocol.** ```python -def step(start, step_size): +def count(start, step): while True: yield start - start += step_size + start += step ``` ```python ->>> stepper = step(10, 2) ->>> next(stepper), next(stepper), next(stepper) +>>> counter = count(10, 2) +>>> next(counter), next(counter), next(counter) (10, 12, 14) ``` @@ -214,7 +226,7 @@ Type ``` ```python -from numbers import Number, Integral, Real, Rational, Complex +from numbers import Integral, Rational, Real, Complex, Number = isinstance(, Number) ``` @@ -226,8 +238,8 @@ from numbers import Number, Integral, Real, Rational, Complex String ------ ```python - = .strip() # Strips all whitespace characters. - = .strip('') # Strips all passed characters. + = .strip() # Strips all whitespace characters from both ends. + = .strip('') # Strips all passed characters from both ends. ``` ```python @@ -237,12 +249,15 @@ String ``` ```python - = .replace(old_str, new_str) - = .startswith() # Pass tuple of strings for multiple options. - = .endswith() # Pass tuple of strings for multiple options. - = .index() # Returns first index of a substring. - = .isnumeric() # True if str contains only numeric characters. - = textwrap.wrap(, width) # Nicely breaks string into lines. + = .replace(old, new [, count]) # Replaces 'old' with 'new' at most 'count' times. + = .startswith() # Pass tuple of strings for multiple options. + = .endswith() # Pass tuple of strings for multiple options. + = .index() # Returns start index of first match. +``` + +```python + = .isnumeric() # True if str contains only numeric characters. + = textwrap.wrap(, width) # Nicely breaks string into lines. ``` ### Char @@ -276,7 +291,7 @@ import re * **Parameter `'flags=re.IGNORECASE'` can be used with all functions.** * **Parameter `'flags=re.DOTALL'` makes dot also accept newline.** * **Use `r'\1'` or `'\\\\1'` for backreference.** -* **Use `'?'` to make operators non-greedy.** +* **Use `'?'` to make operator non-greedy.** ### Match Object ```python @@ -288,7 +303,7 @@ import re ``` ### Special Sequences -**Use capital letter for negation.** +**Expressions below hold true for strings that contain only ASCII characters. Use capital letter for negation.** ```python '\d' == '[0-9]' # Digit '\s' == '[ \t\n\r\f\v]' # Whitespace @@ -304,12 +319,12 @@ Format ``` ```python ->>> Person = namedtuple('Person', 'name height') +>>> Person = collections.namedtuple('Person', 'name height') >>> person = Person('Jean-Luc', 187) ->>> f'{person.height:10}' -' 187' ->>> '{p.height:10}'.format(p=person) -' 187' +>>> f'{person.height}' +'187' +>>> '{p.height}'.format(p=person) +'187' ``` ### General Options @@ -371,33 +386,21 @@ Numbers ```python = pow(, ) # Or: ** = abs() - = round( [, ndigits]) + = round() + = round(, ±ndigits) ``` -### Constants +### Math ```python from math import e, pi -``` - -### Trigonometry -```python from math import cos, acos, sin, asin, tan, atan, degrees, radians -``` - -### Logarithm -```python from math import log, log10, log2 - = log( [, base]) # Base e, if not specified. -``` - -### Infinity, nan -```python from math import inf, nan, isinf, isnan ``` -#### Or: +### Statistics ```python -float('inf'), float('nan') +from statistics import mean, median, variance, pvariance, pstdev ``` ### Random @@ -410,22 +413,80 @@ shuffle() ``` +Combinatorics +------------- +* **Every function returns an iterator.** +* **If you want to print the iterator, you need to pass it to the list() function!** + +```python +from itertools import product, combinations, combinations_with_replacement, permutations +``` + +```python +>>> 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)] +``` + +```python +>>> product('ab', '12') +[('a', '1'), ('a', '2'), + ('b', '1'), ('b', '2')] +``` + +```python +>>> combinations('abc', 2) +[('a', 'b'), ('a', 'c'), ('b', 'c')] +``` + +```python +>>> combinations_with_replacement('abc', 2) +[('a', 'a'), ('a', 'b'), ('a', 'c'), + ('b', 'b'), ('b', 'c'), + ('c', 'c')] +``` + +```python +>>> permutations('abc', 2) +[('a', 'b'), ('a', 'c'), + ('b', 'a'), ('b', 'c'), + ('c', 'a'), ('c', 'b')] +``` + + Datetime -------- ```python -from datetime import datetime, strptime +from datetime import datetime now = datetime.now() -now.month # 3 -now.strftime('%Y%m%d') # '20180315' -now.strftime('%Y%m%d%H%M%S') # '20180315002834' - = strptime('2015-05-12 00:39', '%Y-%m-%d %H:%M') +now.month # 3 +now.strftime('%Y%m%d') # '20180315' +now.strftime('%Y%m%d%H%M%S') # '20180315002834' + = datetime.strptime('2015-05-12 00:39', '%Y-%m-%d %H:%M') ``` Arguments --------- -**`'*'` is the splat operator, that takes a list as input, and expands it into actual positional arguments in the function call.** +### Inside Function Call +```python +() # f(0, 0) +() # f(x=0, y=0) +(, ) # f(0, y=0) +``` +### Inside Function Definition +```python +def f(): # def f(x, y) +def f(): # def f(x=0, y=0) +def f(, ): # def f(x, y=0) +``` + + +Splat Operator +-------------- +### Inside Function Call +**Splat expands collection into positional arguments, while splatty-splat expands dictionary into keyword arguments.** ```python args = (1, 2) kwargs = {'x': 3, 'y': 4, 'z': 5} @@ -437,7 +498,8 @@ func(*args, **kwargs) func(1, 2, x=3, y=4, z=5) ``` -#### Splat operator can also be used in function declarations: +### Inside Function Definition +**Splat combines zero or more positional arguments into tuple, while splatty-splat combines zero or more keyword arguments into dictionary.** ```python def add(*a): return sum(a) @@ -448,17 +510,36 @@ def add(*a): 6 ``` -#### And in few other places: +#### Legal argument combinations: ```python ->>> a = (1, 2, 3) ->>> [*a] -[1, 2, 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) ``` ```python ->>> head, *body, tail = [1, 2, 3, 4] ->>> body -[2, 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) +``` + +```python +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) +``` + +### Other Uses +```python + = [* [, ...]] + = {* [, ...]} + = (*, [...]) + = {** [, ...]} +``` + +```python +head, *body, tail = ``` @@ -466,16 +547,16 @@ Inline ------ ### Lambda ```python -lambda: -lambda , : + = lambda: + = lambda , : ``` ### Comprehension ```python = [i+1 for i in range(10)] # [1, 2, ..., 10] = {i for i in range(10) if i > 5} # {6, 7, 8, 9} - = {i: i*2 for i in range(10)} # {0: 0, 1: 2, ..., 9: 18} = (i+5 for i in range(10)) # (5, 6, ..., 14) + = {i: i*2 for i in range(10)} # {0: 0, 1: 2, ..., 9: 18} ``` ```python @@ -554,12 +635,12 @@ def get_multiplier(a): ``` * **If multiple nested functions within enclosing function reference the same value, that value gets shared.** -* **To dynamicaly acces functions first free variable use `'.__closure__[0].cell_contents'`.** +* **To dynamically access function's first free variable use `'.__closure__[0].cell_contents'`.** -#### Or: +### Partial ```python from functools import partial - = partial(, [, , ...]) + = partial( [, , , ...]) ``` ```python @@ -569,15 +650,15 @@ from functools import partial ``` ### Nonlocal -**If variable is assigned to anywhere in the scope, it is regarded as a local variable, unless it is declared as global or nonlocal.** +**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 'nonlocal'.** ```python def get_counter(): - a = 0 + i = 0 def out(): - nonlocal a - a += 1 - return a + nonlocal i + i += 1 + return i return out ``` @@ -626,15 +707,10 @@ from functools import lru_cache @lru_cache(maxsize=None) def fib(n): - return n if n < 2 else fib(n-1) + fib(n-2) + return n if n < 2 else fib(n-2) + fib(n-1) ``` -```python ->>> [fib(n) for n in range(10)] -[0, 1, 1, 2, 3, 5, 8, 13, 21, 34] ->>> fib.cache_info() -CacheInfo(hits=16, misses=10, maxsize=None, currsize=10) -``` +* **Recursion depth is limited to 1000 by default. To increase it use `'sys.setrecursionlimit()'`.** ### Parametrized Decorator ```python @@ -663,7 +739,7 @@ class : def __init__(self, a): self.a = a def __repr__(self): - class_name = type(self).__name__ + class_name = self.__class__.__name__ return f'{class_name}({self.a!r})' def __str__(self): return str(self.a) @@ -747,10 +823,36 @@ class MySequence: ```python class Counter: def __init__(self): - self.a = 0 + self.i = 0 def __call__(self): - self.a += 1 - return self.a + self.i += 1 + return self.i +``` + +```python +>>> counter = Counter() +>>> counter(), counter(), counter() +(1, 2, 3) +``` + +### Withable +```python +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() +``` + +```python +>>> with open('test.txt', 'w') as file: +... file.write('Hello World!') +>>> with MyOpen('test.txt') as file: +... print(file.read()) +Hello World! ``` ### Copy @@ -819,7 +921,7 @@ while True: break ``` -#### Raising exception: +### Raising Exception ```python raise ValueError('A very specific message!') ``` @@ -837,23 +939,15 @@ KeyboardInterrupt ``` -System ------- -### Command Line Arguments -```python -import sys -script_name = sys.argv[0] -arguments = sys.argv[1:] -``` - -### Print Function +Print +----- ```python print(, ..., sep=' ', end='\n', file=sys.stdout, flush=False) ``` * **Use `'file=sys.stderr'` for errors.** -#### Pretty print: +### Pretty Print ```python >>> from pprint import pprint >>> pprint(dir()) @@ -862,10 +956,12 @@ print(, ..., sep=' ', end='\n', file=sys.stdout, flush=False) '__doc__', ...] ``` -### Input Function + +Input +----- * **Reads a line from user input or pipe if present.** -* **The trailing newline gets stripped.** -* **The prompt string is printed to standard output before reading input.** +* **Trailing newline gets stripped.** +* **Prompt string is printed to the standard output before reading input.** ```python = input(prompt=None) @@ -880,45 +976,80 @@ while True: break ``` -### Open Function + +Command Line Arguments +---------------------- +```python +import sys +script_name = sys.argv[0] +arguments = sys.argv[1:] +``` + +### Argparse +```python +from argparse import ArgumentParser, FileType +p = ArgumentParser(description=) +p.add_argument('-', '--', action='store_true') # Flag +p.add_argument('-', '--', type=) # Option +p.add_argument('', type=, nargs=1) # Argument +p.add_argument('', type=, nargs='+') # Arguments +args = p.parse_args() +value = args. +``` + +* **Use `'help='` for argument description.** +* **Use `'type=FileType()'` for files.** + + +Open +---- **Opens file and returns a corresponding file object.** ```python - = open(, mode='r', encoding=None) + = open('', mode='r', encoding=None) ``` -#### Modes: +### 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 beginning.** +* **`'r+'` - Read and write from the start.** * **`'a+'` - Read and write from the end.** -* **`'b'` - Binary mode.** * **`'t'` - Text mode (default).** +* **`'b'` - Binary mode.** -#### Read Text from File: +### Seek +```python +.seek(0) # Move to the start of the file. +.seek(offset) # Move 'offset' chars/bytes from the start. +.seek(offset, ) # Anchor: 0 start, 1 current pos., 2 end. +``` + +### Read Text from File ```python def read_file(filename): with open(filename, encoding='utf-8') as file: return file.readlines() ``` -#### Write Text to File: +### Write Text to File ```python def write_to_file(filename, text): with open(filename, 'w', encoding='utf-8') as file: file.write(text) ``` -### Path + +Path +---- ```python from os import path, listdir - = path.exists() - = path.isfile() - = path.isdir() - = listdir() + = path.exists('') + = path.isfile('') + = path.isdir('') + = listdir('') ``` ```python @@ -927,13 +1058,44 @@ from os import path, listdir ['1.gif', 'card.gif'] ``` -### Command Execution +### Pathlib +```python +from pathlib import Path +cwd = Path() + = Path('' [, '', , ...]) + = / '' / '' +``` + +```python + = .exists() + = .is_file() + = .is_dir() + = .iterdir() + = .glob('') +``` + +```python + = str() # Returns path as string. + = .parts # Returns all components as strings. + = .resolve() # Returns absolute path without symlinks. +``` + +```python + = .name # Final component. + = .stem # Final component without extension. + = .suffix # Final component's extension. + = .parent # Path without final component. +``` + + +Command Execution +----------------- ```python import os = os.popen().read() ``` -#### Or: +### Subprocess ```python >>> import subprocess >>> a = subprocess.run(['ls', '-a'], stdout=subprocess.PIPE) @@ -943,14 +1105,29 @@ b'.\n..\nfile1.txt\nfile2.txt\n' 0 ``` -### Recursion Limit + +CSV +--- +```python +import csv +``` + +### Read Rows from CSV File ```python ->>> import sys ->>> sys.getrecursionlimit() -1000 ->>> sys.setrecursionlimit(5000) +def read_csv_file(filename): + with open(filename, encoding='utf-8') as file: + return csv.reader(file, delimiter=';') +``` + +### Write Rows to CSV File +```python +def write_to_csv_file(filename, rows): + with open(filename, 'w', encoding='utf-8') as file: + writer = csv.writer(file, delimiter=';') + writer.writerows(rows) ``` + JSON ---- ```python @@ -959,20 +1136,14 @@ import json = json.loads() ``` -#### To preserve order: -```python -from collections import OrderedDict - = json.loads(, object_pairs_hook=OrderedDict) -``` - -### Read File +### Read Object from JSON File ```python def read_json_file(filename): with open(filename, encoding='utf-8') as file: return json.load(file) ``` -### Write to File +### Write Object to JSON File ```python def write_to_json_file(filename, an_object): with open(filename, 'w', encoding='utf-8') as file: @@ -1007,14 +1178,14 @@ SQLite ------ ```python import sqlite3 -db = sqlite3.connect() +db = sqlite3.connect('') ... db.close() ``` ### Read ```python -cursor = db.execute() +cursor = db.execute('') if cursor: = cursor.fetchone() # First row. = cursor.fetchall() # Remaining rows. @@ -1022,32 +1193,33 @@ if cursor: ### Write ```python -db.execute() +db.execute('') db.commit() ``` Bytes ----- -**Bytes object is immutable sequence of single bytes. Mutable version is called bytearray.** +**Bytes object is immutable sequence of single bytes. Mutable version is called 'bytearray'.** ```python = b'' = [] = [] + = list() = b''.join() ``` ### Encode ```python = .encode(encoding='utf-8') - = .to_bytes(length, byteorder='big|little', signed=False) - = bytes.fromhex() + = .to_bytes(, byteorder='big|little', signed=False) + = bytes.fromhex('') ``` ### Decode ```python - = .decode('utf-8') + = .decode(encoding='utf-8') = int.from_bytes(, byteorder='big|little', signed=False) = .hex() ``` @@ -1073,9 +1245,10 @@ Struct * **Machine’s native type sizes and byte order are used by default.** ```python -from struct import pack, unpack, calcsize - = pack('', [, , ...]) - = unpack('', ) +from struct import pack, unpack, iter_unpack, calcsize + = pack('', [, , ...]) + = unpack('', ) + = iter_unpack('', ) ``` ### Example @@ -1094,7 +1267,7 @@ b'\x00\x01\x00\x02\x00\x00\x00\x03' * **`'<'` - little-endian** * **`'>'` - big-endian** -#### Use capital letter for unsigned type. Standard size in brackets: +#### Use capital letter for unsigned type. Standard sizes are in brackets: * **`'x'` - pad byte** * **`'c'` - char (1)** * **`'h'` - short (2)** @@ -1107,17 +1280,27 @@ b'\x00\x01\x00\x02\x00\x00\x00\x03' Array ----- -**List that can only hold elements of predefined type. Available types are listed above.** +**List that can hold only elements of predefined type. Available types are listed above.** ```python from array import array - = array( [, ]) + = array('' [, ]) +``` + + +Memory View +----------- +**Used for accessing the internal data of an object that supports the buffer protocol.** + +```python + = memoryview( / / ) +.release() ``` Deque ----- -**A thread-safe list with efficient appends and pops from either side. Pronounced “deck”.** +**Thread-safe list with efficient appends and pops from either side. Pronounced "deck".** ```python from collections import deque @@ -1126,8 +1309,11 @@ from collections import deque ```python .appendleft() -.extendleft() # Collection gets reversed. = .popleft() +``` + +```python +.extendleft() # Collection gets reversed. .rotate(n=1) # Rotates elements to the right. ``` @@ -1155,93 +1341,9 @@ lock.release() ``` -Hashlib -------- -```python ->>> import hashlib ->>> hashlib.md5(.encode()).hexdigest() -'33d0eba106da4d3ebca17fcd3f4c3d77' -``` - - -Itertools ---------- -* **Every function returns an iterator and can accept any collection and/or iterator.** -* **If you want to print the iterator, you need to pass it to the list() function!** - -```python -from itertools import * -``` - -### Combinatoric iterators -```python ->>> 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')] - ->>> product('ab', [1, 2]) -[('a', 1), ('a', 2), - ('b', 1), ('b', 2)] - ->>> 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)] -``` - -### Infinite iterators -```python ->>> i = count(5, 2) ->>> next(i), next(i), next(i) -(5, 7, 9) - ->>> a = cycle('abc') ->>> [next(a) for _ in range(10)] -['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c', 'a'] - ->>> repeat(10, 3) -[10, 10, 10] -``` - -### Iterators -```python ->>> chain([1, 2], range(3, 5)) -[1, 2, 3, 4] - ->>> compress('abc', [True, 0, 1]) -['a', 'c'] - ->>> # islice(, from_inclusive, to_exclusive) ->>> islice([1, 2, 3], 1, None) -[2, 3] - ->>> people = [{'id': 1, 'name': 'Bob'}, - {'id': 2, 'name': 'Bob'}, - {'id': 3, 'name': 'Peter'}] ->>> groups = groupby(people, key=lambda a: a['name']) ->>> {name: list(group) for name, group in groups} -{'Bob': [{'id': 1, 'name': 'Bob'}, - {'id': 2, 'name': 'Bob'}], - 'Peter': [{'id': 3, 'name': 'Peter'}]} -``` - - -Introspection and Metaprograming --------------------------------- -**Inspecting code at runtime and code that generates code. You can:** -* **Look at the attributes** -* **Set new attributes** -* **Create functions dynamically** -* **Traverse the parent classes** -* **Change values in the class** +Introspection +------------- +**Inspecting code at runtime.** ### Variables ```python @@ -1252,25 +1354,10 @@ Introspection and Metaprograming ### Attributes ```python -class Z: - def __init__(self): - self.a = 'abcde' - self.b = 12345 -``` - -```python ->>> z = Z() - ->>> vars(z) -{'a': 'abcde', 'b': 12345} - ->>> getattr(z, 'a') -'abcde' - ->>> hasattr(z, 'c') -False - ->>> setattr(z, 'c', 10) + = vars() + = hasattr(, '') +value = getattr(, '') +setattr(, '', value) ``` ### Parameters @@ -1281,11 +1368,16 @@ no_of_params = len(sig.parameters) param_names = list(sig.parameters.keys()) ``` + +Metaprograming +-------------- +**Code that generates code.** + ### Type -**Type is the root class. If only passed the object it returns it's type. Otherwise it creates a new class (and not the instance!).** +**Type is the root class. If only passed the object it returns it's type (class). Otherwise it creates a new class.** ```python -type(, , ) + = type(, , ) ``` ```python @@ -1315,31 +1407,35 @@ class MyMetaClass(type): ```python class MyClass(metaclass=MyMetaClass): - def __init__(self): - self.b = 12345 + b = 12345 +``` + +```python +>>> MyClass.a, MyClass.b +('abcde', 12345) ``` Operator -------- ```python -from operator import add, sub, mul, truediv, floordiv, mod, pow, neg, abs, \ - eq, ne, lt, le, gt, ge, \ - not_, and_, or_, \ - itemgetter, attrgetter, methodcaller +from operator import add, sub, mul, truediv, floordiv, mod, pow, neg, abs +from operator import eq, ne, lt, le, gt, ge +from operator import not_, and_, or_ +from operator import itemgetter, attrgetter, methodcaller ``` ```python import operator as op -product_of_elems = functools.reduce(op.mul, ) -sorted_by_second = sorted(, key=op.itemgetter(1)) -sorted_by_both = sorted(, key=op.itemgetter(1, 0)) +product_of_elems = functools.reduce(op.mul, ) +sorted_by_second = sorted(, key=op.itemgetter(1)) +sorted_by_both = sorted(, key=op.itemgetter(1, 0)) LogicOp = enum.Enum('LogicOp', {'AND': op.and_, 'OR' : op.or_}) last_el = op.methodcaller('pop')() ``` -Eval +Eval ---- ### Basic ```python @@ -1348,7 +1444,7 @@ Eval 3 >>> literal_eval('[1, 2, 3]') [1, 2, 3] ->>> ast.literal_eval('abs(1)') +>>> literal_eval('abs(1)') ValueError: malformed node or string ``` @@ -1358,13 +1454,13 @@ import ast from ast import Num, BinOp, UnaryOp import operator as op -legal_operators = {ast.Add: op.add, - ast.Sub: op.sub, - ast.Mult: op.mul, - ast.Div: op.truediv, - ast.Pow: op.pow, - ast.BitXor: op.xor, - ast.USub: op.neg} +LEGAL_OPERATORS = {ast.Add: op.add, # + + ast.Sub: op.sub, # - + ast.Mult: op.mul, # * + ast.Div: op.truediv, # / + ast.Pow: op.pow, # ** + ast.BitXor: op.xor, # ^ + ast.USub: op.neg} # - def evaluate(expression): root = ast.parse(expression, mode='eval') @@ -1377,9 +1473,9 @@ def eval_node(node): if node_type not in [BinOp, UnaryOp]: raise TypeError(node) operator_type = type(node.op) - if operator_type not in legal_operators: + if operator_type not in LEGAL_OPERATORS: raise TypeError(f'Illegal operator {node.op}') - operator = legal_operators[operator_type] + operator = LEGAL_OPERATORS[operator_type] if node_type == BinOp: left, right = eval_node(node.left), eval_node(node.right) return operator(left, right) @@ -1400,7 +1496,7 @@ def eval_node(node): Coroutine --------- -* **Similar to Generator, but Generator pulls data through the pipe with iteration, while Coroutine pushes data into the pipeline with send().** +* **Similar to generator, but generator pulls data through the pipe with iteration, while coroutine pushes data into the pipeline with send().** * **Coroutines provide more powerful data routing possibilities than iterators.** * **If you built a collection of simple data processing components, you can glue them together into complex arrangements of pipes, branches, merging, etc.** @@ -1469,36 +1565,13 @@ pyplot.show() ``` -Argparse --------- -```python -from argparse import ArgumentParser -desc = 'calculate X to the power of Y' -parser = ArgumentParser(description=desc) -group = parser.add_mutually_exclusive_group() -group.add_argument('-v', '--verbose', action='store_true') -group.add_argument('-q', '--quiet', action='store_true') -parser.add_argument('x', type=int, help='the base') -parser.add_argument('y', type=int, help='the exponent') -args = parser.parse_args() -answer = args.x ** args.y - -if args.quiet: - print(answer) -elif args.verbose: - print(f'{args.x} to the power {args.y} equals {answer}') -else: - print(f'{args.x}^{args.y} == {answer}') -``` - - Table ----- #### Prints CSV file as ASCII table: ```python # $ pip3 install tabulate -import csv from tabulate import tabulate +import csv with open(, encoding='utf-8') as file: lines = csv.reader(file, delimiter=';') headers = [header.title() for header in next(lines)] @@ -1526,88 +1599,7 @@ def get_border(screen): from collections import namedtuple P = namedtuple('P', 'x y') height, width = screen.getmaxyx() - return P(width - 1, height - 1) -``` - - -Image ------ -#### Creates PNG image of greyscale gradient: -```python -# $ 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('L', (width, height), 'white') -img.putdata(pixels) -img.save('test.png') -``` - -### 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'` - 4x8-bit pixels, true color with transparency mask.** -* **`'HSV'` - 3x8-bit pixels, Hue, Saturation, Value color space.** - - -Audio ------ -#### Saves a list of floats with values between -1 and 1 to a WAV file: -```python -import wave, struct -samples = [struct.pack('] -wf = wave.open('test.wav', 'wb') -wf.setnchannels(1) -wf.setsampwidth(2) -wf.setframerate(44100) -wf.writeframes(b''.join(samples)) -wf.close() -``` - -### Plays Popcorn -```python -# pip3 install simpleaudio -import simpleaudio, math, struct -from itertools import chain, repeat -F = 44100 -S1 = '71♪,69,,71♪,66,,62♪,66,,59♪,,,' -S2 = '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 n: 8.176 * 2 ** (int(n) / 12) -parse_n = lambda note: (get_hz(note[:2]), 0.25 if len(note) > 2 else 0.125) -get_note = lambda note: get_wave(*parse_n(note)) if note else get_pause(0.125) -samples_f = chain.from_iterable(get_note(n) for n in f'{S1}{S1}{S2}'.split(',')) -samples_b = b''.join(struct.pack('>> quote("Can't be in URL!") -'Can%27t%20be%20in%20URL%21' ->>> quote_plus("Can't be in URL!") -'Can%27t+be+in+URL%21' -``` - -### Decode -```python ->>> unquote('Can%27t+be+in+URL%21') -"Can't+be+in+URL!" ->>> unquote_plus('Can%27t+be+in+URL%21') -"Can't be in URL!" + return P(width-1, height-1) ``` @@ -1672,7 +1664,7 @@ def odds_handler(sport): ```python # $ pip3 install requests >>> import requests ->>> url = 'http://localhost:8080/odds/football' +>>> url = 'http://localhost:8080/odds/football' >>> data = {'team': 'arsenal f.c.'} >>> response = requests.post(url, data=data) >>> response.json() @@ -1727,7 +1719,7 @@ Line # Hits Time Per Hit % Time Line Contents ``` ### Call Graph -#### Generates a PNG image of call graph with highlighted bottlenecks: +#### Generates a PNG image of a call graph with highlighted bottlenecks: ```python # $ pip3 install pycallgraph @@ -1743,7 +1735,7 @@ with PyCallGraph(output=drawer): NumPy ----- -**Array manipulation mini language. Can run up to 100 times faster than equivalent Python code.** +**Array manipulation mini language. Can run up to one hundred times faster than equivalent Python code.** ```python # $ pip3 install numpy @@ -1764,12 +1756,12 @@ import numpy as np ``` ```python - = .sum() -indexes = .argmin() + = .sum(axis) +indexes = .argmin(axis) ``` * **Shape is a tuple of dimension sizes.** -* **Axis is an index of dimension that gets collapsed.** +* **Axis is an index of dimension that gets collapsed. Leftmost dimension has index 0.** ### Indexing ```bash @@ -1799,7 +1791,7 @@ left = [[0.1], [0.6], [0.8]] # Shape: (3, 1) right = [ 0.1 , 0.6 , 0.8 ] # Shape: (3) ``` -#### 1. If array shapes differ, left-pad the smaller shape with ones: +#### 1. If array shapes differ in length, left-pad the smaller shape with ones: ```python left = [[0.1], [0.6], [0.8]] # Shape: (3, 1) right = [[0.1 , 0.6 , 0.8]] # Shape: (1, 3) <- ! @@ -1843,6 +1835,105 @@ right = [[0.1, 0.6, 0.8], [0.1, 0.6, 0.8], [0.1, 0.6, 0.8]] # Shape: (3, 3) <- ``` +Image +----- +```python +# $ pip3 install pillow +from PIL import Image +``` + +#### Creates PNG image of rainbow gradient: +```python +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') +``` + +#### Adds noise to a PNG image: +```python +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') +``` + +### 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'` - 4x8-bit pixels, true color with transparency mask.** +* **`'HSV'` - 3x8-bit pixels, Hue, Saturation, Value color space.** + + +Audio +----- +```python +import wave +from struct import pack, iter_unpack +``` + +### Read Frames from WAV File +```python +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('