protip.py: the main-main pattern

TLDR: Your Python program will be better if you define a main() function separate from the __main__ block.

Consider a Python program leftpad.py, which takes an input string (say, trans rights), and pads it to the left (so, python leftpad.py -s 'trans rights' -n 16 prints ' trans rights'.)

This is a great way to structure it:

# leftpad.py
import argparse

# leftpad function in global scope can be imported
def leftpad(string, num_chars):
    if len(string) >= num_chars:
        return string
    else:
        pad = ' ' * (num_chars - len(string))
        return pad + string

parser = argparse.ArgumentParser()
parser.add_argument("--string", "-s", type=str, nargs=1)
parser.add_argument("--num","-n", type=int)

if __name__ == '__main__':
    args = parser.parse_args()
    print(leftpad(args.string[0], args.num))

The main functionality and the parser can be imported as leftpad.leftpad(...) and leftpad.parser. These could not be imported if __main__ had the definition for leftpad and the instantiation of parser.

Here's a template you can use for your Python scripts:

import sys

def main():
    try:
        return 1
    except:
        return 0

if __name__ == '__main__':
    sys.exit(main())

Let me explain why this is good, how it could be worse, and how it could be better.

Read more  ↩︎

❖◈◆◈❖

❖◈◈❖

Opt out of Discord's arbitration clause by sending a quick email. (Template included)

TLDR: Send an email to arbitration-opt-out@discord.com using the email associated with your Discord account. For good measure, add your username. Template below!

(btw, i'm not a lawyer and i'm not your representative)


Update: Want to opt out of arbitration for more services? I'm building a collection of arbitration opt-out templates here: github.com/lynnpepin/arbitration-opt-out-templates. Check them out and let me know what you think.


You can opt out of Discord's arbitration clause by sending them an email

Send an email to arbitration-opt-out@discord.com, from the email address you use for your account, stating you wish to opt out of the arbitration clause. For good measure, I recommend adding your account ID!

Read more  ↩︎

❖◈◆◈❖

❖◈◈❖

Things I read, 2022

TLDR: Leaving a PhD gives someone a lot of time to read new things. Here's some of my takeaways:

  • ChatGPT and StableDiffusion are scary and new and cool.
  • Philip Rogaway's work presents some important ethical considerations for cryptographers.
  • ThreeBlueOneBrown is one of many educational YouTubers that I'm enjoying.
  • Anyone writing Rust would benefit from reading the cursed words in the Rustonomicon.
  • As usual, 538 podcasts are worth listening to around elections.
  • Audiobooks are good actually.
  • TV is also really good now.
  • Outer Wilds is the best game, I reckon.
  • Nope (the movie) is really really good.
Read more  ↩︎

❖◈◆◈❖

❖◈◈❖

Python on your phone sucks less with `ooo.py` and the `-i` flag.

TLDR: Copy the script below, and run it as python -i ooo.py. This will give you a bunch of useful imports with short aliases, and throw you into an interactive shell.

'''Run as `python3 -i ooo.py`

I use this when writing Python scripts on my phone (through Termux). The point is to minimize the keypresses needed when writing Python on a phone.

This will start Python, import a bunch of modules with short names, and then throw you into an interpreter.
'''

import numpy as np
import pandas as pd
import math as mt
import random as rd
import time
import itertools as it
import functools as ft
import re
import os
import sys
import glob
import pickle as pl
import hashlib as hl
import secrets as ss
import socket as sk

print("imported numpy as np, pandas as pd, math as mt, random as rd, time, itertools as it, functools as ft, re, os, sys, glob, pickle as pl, hashlib as hl, secrets as ss, and socket as sk!")

A = np.array

PI = mt.pi
TAU = mt.tau
E = mt.e

print("Constants available: PI, TAU, E .")

H = help
Q = quit

print("Functions `help(...)` and `quit()` available as `H(...)` and `Q()`.")
Read more  ↩︎

❖◈◆◈❖

❖◈◈❖

You can sort in linear time!

A log-scale graph showing the runtime (ns) of sorting N elements for different integer depths. They all show a trend towards linear runtime for large N.
A log-scale graph showing the linear runtime of count-sort

TLDR: Yes-- you can sort numbers in linear time. Yes, including floats! The proof that you can sort in $O(n \log n)$ time is still true, but that assumes you're sorting on the infinite set of real numbers (or integers.) We can sort in linear time because we work with finite sets: Floats and ints. The algorithm is very simple, and is called counting sort (or bin sort or radix sort.)

See the Python notebook wrapping an unoptimized Rust countsort implementation:

--

Is this truly $O(n)$? Yes!

  • Counting sort is not a randomized algorithm, it always outputs the correct solution.
  • Counting sort is not a parallelized algorithm. (And you can't use parallelism to speed past a worst-case big-O run time anyway!)
  • Counting sort is not an amortized algorithm. It is truly $O(n)$, not 'expected' or 'amortized' $O(n)$.
  • Counting sort is technically $Θ(n)$, that is, the worst and best case running time is linear.
  • This can be used in the real world.
  • However, it is not an in-place sorting algorithm.
Read more  ↩︎

❖◈◆◈❖

❖◈◈❖