Python

Footguns

  • difference between is and ==

Tips and Tricks

  • from time import sleep
  • Open your current file in interactive mode to inspect/debug it python -i file.py
  • String templating print("%s : %s" % (name, age))
  • Pipenv environments are stored in ~/.local/share/virtualenvs. Can be deleted as part of system cleanup

Lists

`a = [1, 2, 3]

Python now has tools inspired from haskell to operate with lists in the module itertools. Documentation is here

Use a list as stack

stack = [2,3,4] stack.append(5) stack.append(6) stack.pop() stack.pop()

Use a list as Queue

from collections import deque queue = deque(["apple", "banana", "cat"]) queue.append("dog") queue.append("elephant") queue.popleft() queue.popleft()

List Comprehensions a concise way to create list

A list comprehension consists of brackets containing an expression followed by a for clause, then zero or more for or if clauses. The result will be a new list resulting from evaluating the expression in the context of the for and if clauses which follow it.

List Display and Comprehension a = [x*x for x in range(10)]

Generators

If your function uses the yield command, its a generator.

def natural_numbers(): i = 0 while True: yield i i ++

You can pass generators to functions as paramters by prefixing * to the parameter name - def fun(*gen)

Multiple ways to use iterators

  • with a for loop
for num in natural_numbers: print(num)

inline usage

value = sum(next(t) for n in slice(natural_numbers, 10))

Use yield without a value

Simply writing the command yield, yields control to the calling code.

  • Convert a generator into a context manager
from contextlib import contextmanager @contextmanager def db_test(cur): cur.execute('create table points(x int, y int)') try: yield finally: cur.execute('drop table points ')

Class

Special functions in a Class

  • __init__ : constructor
  • __repr__ : print your class sensibly
  • __add__ : operator overload the + operator
  • __iter__, __next__ : make the class iterable
    • raise StopIteration()
  • __enter__, __exit__ : make your class a ContextManger, with setup and teardown functions.

Internals

  • see what happens in the python bytecode
from dis import dis dis(function_name)
  • inspect source code of a function in runtime
from inspect import getsource getsource(add)

Ecosystem

References

Starting a new Python project

Pipenv for package management and virtual environment

Notes from Idiomatic Python

  • ChainMap
  • Clarify function calls with keyword arguments
    • You are sacrificing performance but improving developer time
  • named tuples
from collections import namedtuple def named_tuples(a: int): Results = namedtuple("Result", ["status", "payload"]) if a < 0: return Results("error", {}) if a > 0: return Results("success", {"number": a}) print(named_tuples(3)) print(named_tuples(-1))
  • Updating Multiple state variables
  • Decorators and Context Managers : Help separate business logic from administrative ones

Async

Notes from Keynote on Concurrency, PyBay 2017 Goal : When to use threads, processes, asyncs. Advantages and disadvantages

Functional Programming

Creating partial functions - documenttion

This reminds me of currying in haskell

def user(name, age, role): return {"name":name, "age":age, "role":role} manager = partial(user, role="manager") admin = partial(user, role="admin") print(user(name="denny", age="32", role="user")) print(manager(name="denny", age="38")) print(admin(name="denny", age=42))

Pattern and Matching

https://peps.python.org/pep-0636/ How to implement delegation using pattern matching

Requires python 3.10+

action_pass = {"type": "pass", "payload": {"name": "denny"}} action_keep = {"type": "keep", "payload": {}} action = action_pass match action: case {type, payload}: print(type)

Live Development Process with Reload

Uses the inotify syscall on linux to trigger reload of the program upon file changes

Cli Gif

import inotify.adapters import subprocess def watch(): i = inotify.adapters.Inotify() i.add_watch('./') for event in i.event_gen(yield_nones=False): (_, type_names, path, filename) = event #print("PATH=[{}] FILENAME=[{}] EVENT_TYPES=[{}]".format(path,filename,type_names)) for type in type_names: #print("type: {} path: {} filename: {}".format(type, path, filename)) if type == "IN_CLOSE_WRITE" and ".py" in filename: print('reload file') subprocess.run(["python", "hello.py"]) if __name__ == '__main__': watch()

Numerical and Scientific Computing

import numpy as np import plotly.express as px x = np.linspace(-np.pi, np.pi, 50) y = np.array([np.sin(i) for i in x]) fig = px.scatter(x=x, y=y) fig.show()

numpy simple plot

SciPy, Pandas and OpenCV use numpy array as the common format for data exchange