Learning python
As a relative newcomer to the AI space I was very aware that a significant proportion of the code that exists is written in Python and that as such I needed to to set aside some time to learn.
Learning the basics of a new language doesn’t really hold any concerns any more as, after you’ve learned a few, the process of learning another new language gets simpler and simpler (I’m told this is also true for spoken languages, alas I only speak the one). Mastering the ins and outs of a langauge tends to require building real things in it for quite some time but while all programming languages have differences you mostly find that the basic concepts remain the same and it’s a matter of mapping the way of doing things in a language you do know to a language you don’t while learning the unique advantages each language has.
There is a catch here though, it’s important to learn to write in your new language in a way that is idiomatic for that language, it’s not great to attempt to force your newly created Go project into a Java shaped box (I can always tell when a nodejs dev was recently a c# dev when there is an unneeded inversion of control layer stuck in the middle of it).
Learning how you learn
One thing that will always speed up your ability to learn is knowing how you learn best. Some people prefer to read textbooks, some videos, some start with a specific goal and some meander through the space. Personally I know I learn best when I have a fixed goal I’m trying to achieve and to have that goal be sufficiently complex that I can learn how to structure something properly.
Building something you know
Rather than building something entirely original I find it helps when learning a new language to re-build something you know quite well. In this way you are focussing on applying the language to the problem rather than working out the conceptual solution to the problem.
As such in my case I’m building:
- An api with a number of small endpoints - done
- A small datastore via Redis - done
- Lintable - done
- Runtime checks on request structures - done
- Structured logging
- Testing - semi-done
- Deployable via Docker
- Structured like it had many endpoints - done
You can see my work in progress at: https://github.com/stevejhiggs/python-fastapi-experiment
Articles I’ve found useful
Things I like so far
Batteries included
I’m using FastApi as the base for the api and its a very nice little framework. It has a number of installation modes but in “standard” mode it seems to come with pretty much everything you need to make a high-quality, production grade api.
Optional typing
This is all new since the last time I looked at Python and as someone who currently spends an lot of his day-to-day in typescript this is a very easy and welcome transition. Typing seems to have been well embraced by the wider Python community and most of the packages I use seem to have types.
Good VsCode integration
Install the “python” extension and that’s pretty much it. You get debugging, language server, test running all in one place…nice.
PDM restores sanity
I was tearing my (non-existent) hair out with the state of package and virtualenv management (see below) when I found PDM. This gave me:
- a package file + lockfile approach to packages with the ability to detect and apply available upgrades
- development dependancy support. Things you want a dev to be able to use but don’t want to be part of the final image
- Task runner support. E.g
pdm run dev
to start my server in dev mode - Virtualenv support built in
Thanks to this getting the project running in a virtualenv with the right packages is a matter of running:
pdm install
pdm dev
Rather than the multi-tool monstrosity I had before. With a small amount of config tweaking I also made it so that vsCode automatically uses the correct virtualenv.
Things I don’t like so far
Package / Python version management
I originally followed a set of resonably recent guides on getting a python development environment set up. I was aware of the fact that packages in python are effectively global to the version of python you are running. As such you use a virtualenv which sets up an isolated version of python and the “pip” package manager. You then use pip to install packages. If you want to save what packages you are using you tell pip to dump its state out to a file using pip freeze > requirements.txt
.
The requirements.txt file would be the equivalent of a lockfile in other languages. It contains version information not only for your packages but for all sub-dependacies of those packages. I imagine this makes upgrades all sorts of fun.
I had a reasonably working setup based on:
pyenv + python-version.txt
- manage different versions of python on a per project basispyenv-virtualenv
- setup virtualenvs for a projectpip
- package management
This worked but going from a git checkout to a running project kindof sucked:
- checkout files
- create virtualenv with correct version of python + correct virtualenv name
- go into directory, hopefully your virtualenv name in python version matches the one you set up
- run
pip -r requirements.txt
- open vscode, wonder why it shows all your packages as missing, realise you need to manually set the virtualenv
All of this set off “This can’t be what people actually do, right?” alarm bells in my head and set me off to go find PDM. Maybe I was using it wrong?
Getting testing running was much harder than it should be
I’m using pytest for testing and while writing tests themselves was simple, getting the tests consistently running when I ran pdm pytest
was incredibly painful due to subtle differences in how python resolves files when ran directly and how the pytest executable resolves files. Eventually figured it out with some semi-magical config settings but unfortunately most of the advice online amounted to “I randomly poked and moved files around until it worked and now I don’t touch it”.
Well that and I spent a number of hours wondering why my test was not running then realised I hadn’t actually written one :)
Overall
So far I’m enjoying my experiences with Python. I would in no way claim what I’m going here is right or idiomatic Python but so far it seems to look like other peoples code and I can now understand their github repo’s which is a good sign.