I finally came up with a way I like to create
PyCairo
drawings in a Jupyter notebook.
A few years ago I wrote here about
how to draw Cairo
SVG in a Jupyter notebook. That worked, but wasn’t as convenient as I
wanted. Now I have a module that manages the PyCairo contexts for me. It
automatically handles the displaying of SVG and PNG directly in the notebook, or
lets me write them to a file.
Lately I’ve been posting Python tidbits on
Twitter. It’s been fun finding
things that people might not yet know, fitting them into a tweet, and giving
them some energy.
People ask how I make them. I tried a few “make a code screenshot” sites at
first, but wanted more control over how the images looked. Now I create the
code shots in vim with a tweaked color scheme
(shades-of-purple).
This lets me do things like highlight specific words I want to draw attention
to. Then I use the Mac screenshot tool to grab an image:
The font is Recursive Mono SemiCasual.
Recursive is a lovely and lively
variable font with a number of axes to play with, especially the Casual axis,
which I’ve set to halfway between Linear and Casual.
You can get it now on
Google Fonts. I’d
like to try using Semi-Mono, but vim only understands monospaced fonts.
Some people have asked about publishing these tidbits here on
nedbatchelder.com also, but I’m not sure it’s worth the effort. Would it be
helpful to have a page like this that
collected them per-month or something? Or one tweet per page? Or just let them
live on Twitter?
Python f-strings use a formatting mini-language, the same as the older
.format() function. After the colon comes short specifications for how to
format the value:
The reason datetime uses different formatting specs than strings is because
datetime defines its own __format__ method. Any object can define its own
formatting mini-language. F-strings and .format() will use the __format__
method on an object, and pass it the formatting directives being used:
>>>classConfused: ...def__format__(self,fmt): ...returnf"What is {fmt}?" ... >>>c=Confused() >>>f"{c:xyz12}" 'What is xyz12?'
Of course, __format__ can be used for more useful formatting than Confused is
doing...
Geographic latitude and longitude are conventionally presented in a few
different formats: degrees; or degrees and minutes; or degrees, minutes and
seconds. Then the numbers can have varying number of decimal places, and
sometimes the units are represented by symbols.
Here’s an implementation of those possibilities in __format__. The format
string starts with “d”, “dm”, or “dms” to indicate the basic format. The number
of decimal places can be specified with “.N”. Finally, symbols can be added,
either plain or fancy, by adding a quote or minute symbol:
This implementation doesn’t handle errors properly, but shows the basic idea.
Also, lat/long are often shown with N/S E/W instead of positive and negative
values. That’s left as an exercise for the reader.
Design patterns are a great way to think about interactions among classes.
But the classic Singleton pattern is bad: you shouldn’t use it and there are
better options.
The classic Singleton pattern is a class which always gives you the same
object when you create an instance of the class. It’s used to ensure that all
users of a class are using the same object.
The first problem with Singleton is that it encourages you to mix together
two different ideas into one class. The first idea is whatever your class is
about. Let’s say you are writing a chess game. Your ChessBoard class should
only be concerned with chess-board-ness. A separate second idea is that your
program only needs one board. That’s not a fact intrinsic to chess boards, so
it shouldn’t be coded into your ChessBoard class.
If your program only needs one of a certain object, you can just make one:
classChessBoard: def__init__(self): ...
the_chess_board=ChessBoard()
If you want centralized management of the instance, use a function to manage
a global:
These ways are simpler than the
usual gymnastics
to implement singletons. They have the additional benefit that the users of the
class clearly understand that they are accessing a global instance. This is
another problem with Singleton: it gives you a class that lies. Calling the
class looks like you are making new objects, but you are not.
These ways also let you still make new instances when you need to. Your
ChessBoard tests will need to create many instances to keep your tests isolated
from each other. The Singleton pattern makes this difficult and requires even
more tricky machinations.
But I just need one!
So just make one. There’s no reason to
complicate the class by adding Singleton enforcement to it.
But I need it everywhere in my code!
OK, use
the_chess_board() wherever you were using
ChessBoard().
But I still want a way to enforce “just one!”
The function manages
the global instance. Why does it have to happen inside the class? You should
separate the concept of what the class is from the idea that there should be
only one.
But someone might make more instances!
Who? Document the right way
to use the class. Make it clear and easy to do it the right way, and then let it
be. You can’t defend against every bug, and it’s their program anyway.
But I thought globals were bad?
They are bad, but your Singleton was
also a global: there was only one for the whole process, and it could be changed
from anywhere. It wasn’t literally a Python global variable, but it had all the
same bad qualities, just hidden behind some tricky meta-programming. If you’re
going to have a global, be up-front about it.
But what about None and things like it?
True, some immutable value
types can be singletons, but that’s not how people use the Singleton
pattern, and how often are you writing a class like None?
But Singleton is in the Design Patterns book!
That doesn’t mean it’s
a good idea. None of the examples in the book are true Singletons, they are all
examples of programs that just happen to need only one instance. And the Design
Patterns book was never meant to be prescriptive: it’s not telling you what to
do, it’s describing what people have done.
Dinghy is a tool I wrote to
summarize activity on GitHub issues and pull requests. You configure it to
look at certain GitHub resources over a recent time period, and it produces a
compact digest of what’s been happening:
I started dinghy because I needed a way to see disparate activity in repos at
work, and it’s been useful for that. So far it has the features I’ve needed.
Maybe others will find it useful too.
It was also a chance to dig into the GitHub GraphQL API. GraphQL syntax is
oddly strict (why can’t I define a fragment that isn’t used?), and GitHub’s
implementation has quirks (sometimes requesting data with the wrong token scope
is an error, other times it returns None). I can see the advantage of being
able to request a graph of data with one request rather than a REST API that
forces me to walk the graph myself, but paginating along multiple axes is still
a pain (listing issues, and also comments on issues).
The code is still a mess in some places, and I haven’t figured out how to
test most of it. But it was interesting to reverse engineer how GitHub decides
on the text color for labels (they
compute
it in CSS!)
This blog is 20 years old today. My first post ever was
My first job ever. 20 years later, this is my 2545th post.
It’s tempting to write a philosophical piece about the meaning of it all, and
provide some grand perspective. But there is no overarching narrrative to this
blog. It’s just been a place to write things and connect with people in various
ways.
Here are some popular deep cuts you might have missed over the years:
Looking back 20 years at the
earlyposts,
many of the things I liked and linked to are gone. But for whatever reason, the
puzzle-makers, geometers and type designers seem most durable. Here are some
that are still around (and mostly look their age!):