PythonWise

If it won't be simple, it simply won't be. [Hire me, source code] by Miki Tebeka, CEO, 353Solutions

Thursday, April 09, 2020

Functions as State Machine (Go)

Let's say you'd like to check that a string is a valid floating point (e.g. "3.14", ".2", "-2.718" ...).
One common techinque to solve these kind of problems is to write a state machine.

In our case, the state machine is:

Instead of writng the state machine a one big function with a lot of state and a bunch of "if" statements, we're going to write states as functions.


To simplify things, the end state is going to be nil for easy comparison.
Then our main function will look like:

An here's how startState looks like


When you write this style of code, states are small and contained function. Easier to test and reason about.

Final comments:
  • You can see the full code here
  • This blog was inspired by the Valid Number problem on leetcode
  • Rob Pike has an excellent "Lexcical Scanning in Go" talk that demonstrates this methon

Wednesday, April 01, 2020

A Twitter Quote Bot on GAE

I like quotes and have an extensive list stored in a text file. I was toying with the idea of making a twitter bot that will post a quote per day. Reading that Google cloud is now offering a Secret Manager rekindled this idea.

The result is @quotamiki (which you should follow ;) It posts one quote per day (9am Asia/Jerusalem). It even has a simple web site.

The code was simple to write, I like how Google App Engine let you focus on writing code and not futz with operations.

You can view the code at https://gitlab.com/tebeka/quotamiki

Thursday, March 05, 2020

Using __getattr__ for nicer configuration API

Typically, you'll read configuration from files (such as YAML) and get them as a dictionary. However in Python you'd like to write config.httpd.port and not config['httpd']['port']

__getattr__ is a hook method that's called by Python when regular attribute lookup fails (not to be confused with the lower level __getattribute__, which is much harder to work with). You can use it to wrap the configuration dictionary. Here's a small example.


Tuesday, February 04, 2020

Adding a timer to Go's "present" tool

Go has a nice present tool which let's you present code and run it. I wanted to use it in my lightning talk at GopherCon Israel. The talk is a quiz and I wanted a timer to show on each quiz slide.

present syntax supports .html directive which lets you add any HTML code to the slide. From there it easy to add a timer. I wrote timer.html below and added .html timer.html to the first slide.

Here's how it looks (bottom left):

Here's the code:

Sunday, January 05, 2020

Nested structs for HTTP Calls

Some API's return complex structures. Here's for an example from Stocktwits API.
Instead of creating a specific type for every element in the structre, we use use a anonymous structure and define only the fields we're intrested in. In our example we'd like to see the symbols most mentioned for a given symbol (in our case AAPL). And the output:
$ go run stocktwits.go
SPY    10
TSLA    7
AMZN    5
BTC.X   5
TVIX    2

Monday, August 12, 2019

viaenv

These days, I write a lot of Go and a lot of Python (and some other languages in the mix). What's great is that I'm getting ideas from both ecosystems and find myself more productive.

In the Go world, I like Kelsey Hightower's envconfig for a simple application configuration from environment variables. I couldn't find something similar in the Python world, so I wrote viaenv which uses variable annotation.

One design decision I took is not to invent my own serialization format when getting lists & dicts from the environment (where everything is a string). I'm using JSON, there's really no need to invent yet another serialization format (as envconfig does).

The code itself is not that long (less than 150 lines of code). I'm showing it below:


Wednesday, March 20, 2019

Speed: Default value vs checking for None

Python's dict has a get method. It'll either return an existing value for a given key or return a default value if the key is not in the dict. It's very tempting to write code like val = d.get(key, Object()), however you need to think about the performance implications. Since function arguments are evaluated before calling the function, this means the a new Object will be created regardless if it's in the dict or not. Let's see this affects performance.

get_default will create new Point every time and get_none will create only if there's no such object, it works since or evaluate it's arguments lazily and will stop once the first one is True.

First we'll try with a missing key:

In [1]: %run default_vs_none.py                                     
In [2]: locations = {}  # name -> Location 
In [3]: %timeit get_default(locations, 'carmen')
384 ns ± 2.56 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [4]: %timeit get_none(locations, 'carmen')
394 ns ± 1.61 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Not so much difference. However if the key exists:

In [5]: locations['carmen'] = Location(7, 3)
In [6]: %timeit get_default(locations, 'carmen')                 
377 ns ± 1.84 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [7]: %timeit get_none(locations, 'carmen')
135 ns ± 0.108 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

We get much faster results.

Blog Archive