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 dict and set.
Dictionary
1 2 3
<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.
1 2 3 4
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.
1 2 3 4
<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.
1 2
value = <dict>.pop(key) # Removes item from dictionary. {k: v for k, v in <dict>.items() if k in keys} # Filters dictionary by keys.
<str> = <str>.strip() # Strips all whitespace characters from both ends. <str> = <str>.strip('<chars>') # Strips all passed characters from both ends.
1 2 3 4
<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.
1 2 3 4 5
<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.
1 2 3
<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.
Also: 'lstrip()', 'rstrip()'.
Also: 'lower()', 'upper()', 'capitalize()' and 'title()'.
Char
1 2
<str> = chr(<int>) # Converts int to unicode char. <int> = ord(<str>) # Converts unicode char to int.
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.
Argument 'flags=re.IGNORECASE' can be used with all functions.
Argument 'flags=re.MULTILINE' makes '^' and '$' match the start/end of each line.
Argument 'flags=re.DOTALL' makes dot also accept newline.
Use r'\1' or '\\1' for backreference.
Use '?' to make an operator non-greedy.
Match Object
1 2 3 4 5
<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.
Special Sequences
By default digits, whitespaces and alphanumerics from all alphabets are matched, unless 'flags=re.ASCII' argument is used.
Use '<D/DT>.weekday()' to get the day of the week (Mon == 0).
'fold=1' means second pass in case of time jumping back for one hour.
Now
1 2 3
<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.
To extract time use '<DTn>.time()', '<DTa>.time()' or '<DTa>.timetz()'.
Timezone
1 2 3
<tzinfo> = UTC # UTC timezone. London without DST. <tzinfo> = tzlocal() # Local timezone. Also gettz(). <tzinfo> = gettz('<Cont.>/<City>') # Timezone from 'Continent/City_Name' str.
1 2
<DTa> = <DT>.astimezone(<tzinfo>) # Datetime, converted to passed timezone. <Ta/DTa> = <T/DT>.replace(tzinfo=<tzinfo>) # Unconverted object with new timezone.
Encode
1 2 3 4 5
<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.
ISO strings come in following forms: 'YYYY-MM-DD', 'HH:MM:SS.ffffff[±<offset>]', or both separated by 'T'. Offset is formatted as: 'HH:MM'.
On Unix systems Epoch is '1970-01-01 00:00 UTC', '1970-01-01 01:00 CET', …
Decode
1 2 3 4 5
<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.
Format
1 2 3 4
>>> 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"
For abbreviated weekday and month use '%a' and '%b'.
<list> = [i+1for i in range(10)] # [1, 2, ..., 10] <set> = {i for i in range(10) if i > 5} # {6, 7, 8, 9} <iter> = (i+5for i in range(10)) # (5, 6, ..., 14) <dict> = {i: i*2for i in range(10)} # {0: 0, 1: 2, ..., 9: 18}
1
out = [i+j for i in range(10) for j in range(10)]
Is the same as:
1 2 3 4
out = [] for i in range(10): for j in range(10): out.append(i+j)
Decorator that prints function’s name every time it gets called.
1 2 3 4 5 6 7 8 9 10 11 12
from functools import wraps
defdebug(func): @wraps(func) defout(*args, **kwargs): print(func.__name__) return func(*args, **kwargs) return out
@debug defadd(x, y): return x + y
Wraps is a helper decorator that copies metadata of function add() to function out().
Without it 'add.__name__' would return 'out'.
LRU Cache
Decorator that caches function’s return values. All function’s arguments must be hashable.
1 2 3 4 5
from functools import lru_cache
@lru_cache(maxsize=None) deffib(n): return n if n < 2else fib(n-2) + fib(n-1)
Recursion depth is limited to 1000 by default. To increase it use 'sys.setrecursionlimit(<depth>)'.
Parametrized Decorator
A decorator that accepts arguments and returns a normal decorator that accepts a function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
from functools import wraps
defdebug(print_result=False): defdecorator(func): @wraps(func) defout(*args, **kwargs): result = func(*args, **kwargs) print(func.__name__, result if print_result else'') return result return out return decorator
@debug(print_result=True) defadd(x, y): return x + y
Class
1 2 3 4 5 6 7 8 9 10 11 12
class <name>: def__init__(self, a): self.a = a def__repr__(self): class_name = self.__class__.__name__ returnf'{class_name}({self.a!r})' def__str__(self): return str(self.a)
A duck type is an implicit type that prescribes a set of special methods. Any object that has those methods defined is considered a member of that duck type.
Comparable
If eq() method is not overridden, it returns 'id(self) == id(other)', which is the same as 'self is other'.
That means all objects compare not equal by default.
Only left side object has eq() method called, unless it returns ‘NotImplemented’, in which case the right object is consulted.
1 2 3 4 5 6 7
classMyComparable: def__init__(self, a): self.a = a def__eq__(self, other): if isinstance(other, type(self)): return self.a == other.a returnNotImplemented
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 value, meaning default hash() that returns 'id(self)' will not do.
That is why Python automatically makes classes unhashable if you only implement eq().
>>> with open('test.txt', 'w') as file: ... file.write('Hello World!') >>> with MyOpen('test.txt') as file: ... print(file.read()) Hello World!
List of existing context managers:
1 2 3 4 5
with open('<path>', ...) as file: ... with wave.open('<path>', ...) as wave_file: ... with memoryview(<bytes/bytearray/array>) as view: ... db = sqlite3.connect('<path>'); with db: db.execute('<insert_query>') lock = threading.RLock(); with lock: ...
Iterable Duck 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() defined.
1 2 3 4 5 6
classMyIterable: def__init__(self, a): self.a = a def__iter__(self): for el in self.a: yield el
1 2 3 4 5
>>> a = MyIterable([1, 2, 3]) >>> iter(a) <generator object MyIterable.__iter__ at 0x1026c18b8> >>> 1in a True
Collection
Only required methods are iter() and len().
This cheatsheet actually means '<iterable>' when it uses '<collection>'.
I chose not to use the name ‘iterable’ because it sounds scarier and more vague than ‘collection’.
1 2 3 4 5 6 7 8 9 10
classMyCollection: def__init__(self, a): self.a = a def__iter__(self): for el in self.a: yield el def__contains__(self, el): return el in self.a def__len__(self): return len(self.a)
Sequence
Only required methods are len() and getitem(), that should return an item at index or raise ‘IndexError’.
Iter() and contains() automatically work on any object that has getitem() defined.
Reversed() automatically works on any object that has getitem() and len() defined.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classMySequence: def__init__(self, a): self.a = a def__iter__(self): for el in self.a: yield el 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)
Collections.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 is why 'issubclass(MySequence, collections.abc.Sequence)' would return ‘False’ even if it had all the methods defined.
@classmethod defget_member_names(cls): return [a.name for a in cls.__members__.values()]
If there are no numeric values before auto(), it returns 1.
Otherwise it returns an increment of last numeric value.
1 2 3 4 5
<member> = <enum>.<member_name> <member> = <enum>['<member_name>'] <member> = <enum>(<value>) name = <member>.name value = <member>.value
1 2 3 4
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>))
raise ValueError('Argument is of right type but inappropriate value!') raise TypeError('Argument is of wrong type!') raise RuntimeError('None of above!')
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.
'encoding=None' means default encoding is used, which is platform dependent. Best practice is to use 'encoding="utf-8"' whenever possible.
'newline=None' means all different end of line combinations are converted to ‘\n’ on read, while on write all ‘\n’ characters are converted to system’s default line separator.
'newline=""' means no conversions take place, but lines are still broken by readline() on either ‘\n’, ‘\r’ or ‘\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.
Exceptions
'FileNotFoundError' can be risen when reading with 'r' or 'r+'.
'FileExistsError' can be risen when writing with 'x'.
'IsADirectoryError' and 'PermissionError' can be risen by any.
'OSError' is the parent class of all listed exceptions.
File
1 2 3 4
<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.
1 2 3 4
<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 lines or empty list. <str/bytes> = next(<file>) # Returns a line using buffer. Do not mix.
1 2 3
<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.
Methods do not add or strip trailing newlines, even writelines().
Read Text from File
1 2 3
defread_file(filename): with open(filename, encoding='utf-8') as file: return file.readlines()
Write Text to File
1 2 3
defwrite_to_file(filename, text): with open(filename, 'w', encoding='utf-8') as file: file.write(text)
Path
1 2
from os import path, listdir from glob import glob
<iter> = <Path>.iterdir() # Iterator of filenames located at path. <iter> = <Path>.glob('<pattern>') # Filenames matching the wildcard pattern.
1 2 3
<str> = str(<Path>) # Returns path as a string. <tup.> = <Path>.parts # Returns all components as strings. <Path> = <Path>.resolve() # Returns absolute Path without symlinks.
1 2 3 4
<str> = <Path>.name # Final component. <str> = <Path>.stem # Final component without extension. <str> = <Path>.suffix # Final component's extension. <Path> = <Path>.parent # Path without final component.
Command Execution
Files and Directories Commands
Paths can be either strings or Path objects.
All exceptions are either ‘OSError’ or its subclasses.
1 2 3
import os os.chdir(<path>) # Changes the current working directory. <str> = os.getcwd() # Returns current working directory.
1 2 3
os.remove(<path>) # Deletes the file. os.rmdir(<path>) # Deletes empty directory. shutil.rmtree(<path>) # Deletes an entire directory tree.
1 2
os.rename(from, to) # Renames the file or directory. os.replace(from, to) # Same, but overwrites 'to' if it exists.
1 2
os.mkdir(<path>, mode=0o777) # Creates a directory. <iter> = os.scandir(path='.') # Returns os.DirEntry objects located at path.
DirEntry:
1 2 3
<str> = <DirEntry>.name # Final component of the path. <str> = <DirEntry>.path # Path with final component. <Path> = Path(<DirEntry>) # Path object.
defread_pickle_file(filename): with open(filename, 'rb') as file: return pickle.load(file)
Write Object to File
1 2 3
defwrite_to_pickle_file(filename, an_object): with open(filename, 'wb') as file: pickle.dump(an_object, file)
SQLite
Server-less database engine that stores each database into separate file.
1 2 3 4
import sqlite3 db = sqlite3.connect('<path>') # Also ':memory:'. ... db.close()
New database will be created if path doesn’t exist.
Read
1 2 3 4
cursor = db.execute('<query>') if cursor: <tuple> = cursor.fetchone() # First row. <list> = cursor.fetchall() # Remaining rows.
Returned values can be of type str, int, float, bytes or None.
Write
1 2
db.execute('<query>') db.commit()
Placeholders
1 2 3
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.
Passed values can be of type str, int, float, bytes, None, bool, datetime.date or datetime.datetme.
MySQL
Has a very similar interface, with differences listed below.
1 2 3 4 5 6 7
# $ 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>') # Connector doesn't have 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
Bytes object is an immutable sequence of single bytes. Mutable version is called ‘bytearray’.
1 2 3 4
<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.
Encode
1 2 3 4
<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>')
Decode
1 2 3 4
<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()
Read Bytes from File
1 2 3
defread_bytes(filename): with open(filename, 'rb') as file: return file.read()
Write Bytes to File
1 2 3
defwrite_bytes(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 C struct, represented as a Python bytes object.
Machine’s native type sizes and byte order are used by default.
<list> = dir() # Names of variables in current scope. <dict> = locals() # Dict of local variables. Also vars(). <dict> = globals() # Dict of global variables.
New() is a class method that gets called before init(). If it returns an instance of its class, then that instance gets passed to init() as a ‘self’ argument.
It receives the same arguments as init(), except for the first one that specifies the desired class of returned instance ('MyMetaClass'in our case).
New() can also be called directly, usually from a new() method of a child class (def __new__(cls): return super().__new__(cls)), in which case init() is not called.
Metaclass Attribute
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().
1 2
classMyClass(metaclass=MyMetaClass): b = 12345
1 2
>>> MyClass.a, MyClass.b ('abcde', 12345)
Type Diagram
1 2
type(MyClass) == MyMetaClass # MyClass is an instance of MyMetaClass. type(MyMetaClass) == type # MyMetaClass is an instance of type.
# $ 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)
Curses
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
from curses import wrapper, ascii
defmain(): wrapper(draw)
defdraw(screen): screen.clear() screen.addstr(0, 0, 'Press ESC to quit.') while screen.getch() != ascii.ESC: pass
defget_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()
Logging
1 2
# $ pip3 install loguru from loguru import logger
1 2 3
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.')
from time import time start_time = time() # Seconds since Epoch. ... duration = time() - start_time
High Performance
1 2 3 4
from time import perf_counter as pc start_time = pc() # Seconds since restart. ... duration = pc() - start_time
Timing a Snippet
1 2 3 4
>>> from timeit import timeit >>> timeit('"-".join(str(a) for a in range(100))', ... number=10000, globals=globals(), setup='pass') 0.34986
Line Profiler
1 2 3 4 5 6
# $ pip3 install line_profiler @profile defmain(): a = [*range(10000)] b = {*range(10000)} main()
Usage:
1 2 3 4 5 6 7
$ 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)}
Call Graph
Generates a PNG image of a call graph with highlighted bottlenecks:
1 2 3 4 5 6 7 8
# $ 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>
NumPy
Array manipulation mini language. Can run up to one hundred times faster than equivalent Python code.
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:
1 2 3 4 5
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
1 2
import wave from struct import pack, iter_unpack
Read Frames from WAV File
1 2 3 4
defread_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)]
Write Frames to WAV File
1 2 3 4 5 6 7
defwrite_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(1if mono else2) wf.setsampwidth(2) wf.setframerate(44100) wf.writeframes(b''.join(frames_short))
Examples
Saves a sine wave to a mono WAV file:
1 2 3 4
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)
Adds noise to a mono WAV file:
1 2 3 4
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)
Synthesizer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# $ 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.25if'♪'in note else0.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 inf'{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)