Hax
Table of Contents
A menagarie of cool python snippets!
1. Unpacking
def is_palindrome(indexable): if len(indexable) > 1: first, *rest, last = indexable return first == last and is_palindrome(rest) else: return True
1.1. Bonus Hack: Quicksort - EZ Sorting
Not the most efficient implementation, but we can implement quicksort extremely succinctly using list unpacking + recursion:
def quicksort(ls: list): if ls: pivot, *rest = ls smaller, greater = [], [] for item in rest: (smaller if pivot > item else greater).append(item) return quicksort(smaller) + [pivot] + quicksort(greater) else: return []
Of course sorted(ls)
does the job too.
2. Poor Man's Cache
def fib(n: int, cache={0: 1, 1: 1}): if n not in cache: cache[n] = fib(n - 1, cache) + fib(n - 2, cache) return cache[n]
The cache object is created when the function is defined, not every time it is called. You can reset the cache (and change the base cases!) by passing in a new cache object.
Bonus points for fixing up this one so it doesn't blow up the stack.
3. ♥ Generators ♥
def triangle_number(n: int): return sum(k for k in range(n + 1))
sum(k for k in range(n + 1))
is desugared to sum((k for k in range(n + 1)))
, so we're just taking the sum of a generator comprehension. Note this is not equivalent to sum([k for k in range(n + 1)])
as the list comprehension does not use constant memory!
4. Poor Man's defaultdict
my_dict = {"a": 1, "b": 2} print(my_dict.get("A", -1))
If we forego the slice syntax, we can specify a default value to .get
in order to avoid a KeyError
.
5. Zip is it's own Inverse
import string zipped = list(zip(range(10), string.ascii_lowercase, string.ascii_uppercase)) print("Zipped up: " + str(zipped)) dezipped = list(zip(*zipped)) print("Dezipped: " + str(dezipped))
6. =
in Format Strings
Since 3.8 you can prepend the expression text to the evaluated expression if you append an =
to the format expression.
name = "Bob" age = "37" print(f"Person({name=}, {age=})")
7. shlex
for Commands
We can use shlex.split
to transform a command string into a list of arguments suitable for subprocess.Popen
or even:
import shlex, subprocess, pprint command = """find . -type f -printf '%TY-%Tm-%Td %TT %p '""" # Lists files and when they were last edited args = shlex.split(command) result = subprocess.run(args, capture_output=True) recently_edited = sorted(result.stdout.decode("utf-8").splitlines())[-2:] pprint.pp(recently_edited) # ['2022-08-01 18:12:41.0370089750 ./files.org', # '2022-11-05 21:40:23.4741009550 ./hax.org']
Also useful are shlex.quote(s)
which returns a shell escaped version of s
and shlex.join
, the inverse to shlex.split
.
8. Built in Iverson Brackets
We can perform arithmetic with boolean values and integers, basically True = 1
and False = 0
(so much for strong typing!). We can use this behaviour to implement Iverson Brackets fairly readably:
from math import gcd def phi(n): return sum((gcd(n, i) == 1) for i in range(1, n + 1)) def ramp(x): return x*(x > 0)
9. Ad-hoc Timing
IPython's %timeit
is extremely useful, but for situations where this is not possible, we can use time
in conjuction with the -c
flag to time a function belonging to a module in the current directory:
time pypy3 -c "from mymodule import foo;print(foo('arg'))"