The purpose of this repository is for me to have a place where I’m practicing Python.
On Macos, I use the brew
ecosystem. I need some dependencies installed:
brew install python
- If I’m going to play with Python, I should probably install it.
brew install uv
- a Rust based package manager for Python.
- brew install python-lsp-server
- wire this into Eglot for LSP functionality.
uv venv
uv pip install virtualenv
I added the following to my Emacs configuration:
(use-package python
:straight (:type built-in)
:hook (python-mode . jf/python-mode-configurator)
:config
(defun jf/python-mode-configurator ()
(eldoc-mode t)
(eglot-ensure)
(python-docstring-mode t)
(setq-default python-indent-offset 4)
;; I’m loving an 80 column fill…Why? Because on my small computer I can
;; have 4 windows laid out in a quadrant and see all of the code/text.
(setq-local fill-column 80)))
;; The treesit package of Emacs 29+ behaves a bit different.
(add-hook 'python-ts-mode-hook #'jf/python-mode-configurator)
;; A Python syntax validator/linter.
(use-package flymake-ruff
:straight t
:hook (eglot-managed-mode . flymake-ruff-load))
;; To provide some syntax highlighting of docstrings, and more.
(use-package python-docstring
:straight t)
;; To create narrowable groups
(dolist (python '(python-mode python-ts-mode))
(add-to-list 'consult-imenu-config
`(,python
:toplevel "Method"
:types ((?f "Field" font-lock-variable-name-face)
(?c "Class" font-lock-type-face)
(?m "Method" font-lock-function-name-face)
(?v "Variable" font-lock-variable-name-face)
))))
I started reading Brandon Rhodes’ Python Patterns; a dear friend with whom I have dinner and beers every Thursday evening.
With python-mode
enabled, I typed C-c C-c
and Emacs prompted me to start a Python process by typing C-c C-p
. I started the process, and went back to my Python code, then typed C-c C-c
and the print statements were echoed to that Python process. Super helpful for introspection.
I’m also considering installing Crandel/tempel-collection: Collection tempel templates; there’s some templates for Python. I’ve already found the occasional line ending in :
is a bit jarring; it’s one of those “I definitely want a linter running to remind me of this missing value.”
I’ve been back and forth on which LSP package to use. I started with python-lsp-server
, I was a bit overwhelmed looking at https://gist.github.com/doolio/8c1768ebf33c483e6d26e5205896217f. So I explored lsp-pyright
, but as someone who favors the simplicity of eglot
, I went back to python-lsp-server
.
uv pip install "python-lsp-server[all]"
uv pip install pylsp-rope
I installed local documentation for Python 3.12 and Django 5.0 via both the devdocs package and dash-docs package. Having long used devdocs
, I’m currently comparing it’s features and usability with dash-docs
.
I’ve also installed the info pages for Python, providing yet another way to explore the documentation.
Last, I installed the sphinx-doc package; this provides the sphinx-doc
command (bound to C-c M-d
). Calling that command within a method will pre-populate the docstring with parameter and return value information. I find this useful, given that I’m learning a new syntax for documentation.
I have individual practice files, with comments around connecting Python concepts to Ruby counterparts.
- exceptions.py
- A simple reference of the exception handling construction of Python.
- introspection.py
- Exploring named parameters and object introspection.
- iterator.py
- Exploring some of the iterators; though there are more reflections below.
- object-instantiation.py
- Looking at default values for object’s fields/properties.
- static-method.py
- Exploring the
@staticmethod
directive while also reviewing The Abstract Factory Pattern.
In addition to the Python files, I have written further discussion regarding other topics; see below.
As I read The Iterator Pattern, I’m mapping these concepts to Ruby.
Below we map the symbols of elements with an atomic weight greater than 5.
dictionary = {'H': 1.008, 'He': 4.003, 'Li': 6.94}
list(symbol for symbol, weight in dictionary.items() if weight > 5)
# Analogous to the above
[symbol for symbol, weight in d.items() if weight > 5]
dictionary = { H: 1.008, He: 4.003, Li: 6.94 }
dictionary.each_with_object([]) { |(symbol, weight), array| array << symbol.to_s if weight > 5 }
Both return an Array
of one element; namely ["Li"]
. The syntax of Python takes a bit of adjustment, in part because I’m accustomed to Ruby’s idioms and syntax.
Stepping back a bit, the syntax of Python requires less conceptualization. The three symbols: [
, symbol
, and for
provide early indicators that I’m “Making an array of the “symbol” variable defined in the for
loop.
The same applies with starting a dictionary.
Put another way, while I’m familiar with Ruby’s various iterator functions and their blocks, Python front-loads the “What is this object?” Ruby says “Noun, verb, object” and Python says “Object, verb from noun.”
Though setting the results into a local variable can also provide guidance on what the “map” is. And that named variable is declared before the mapping.