I should always give my Python classes a __str__
method
I have been going back and forth between Python and Go lately, and as part of that I have (re-)learned a sharp edged lesson about working in Python because of something that Go has built in that Python doesn't.
I do much of my debugging via print()
statements or the equivalent.
One of the conveniences of Go is that its formatted output package has built-in support for dumping
structures. If you have a structure, and usually you do because
they're often the Go equivalent of instances of classes, you can just
tell fmt.Printf()
to print the whole thing out for you with all
the values and even the field names.
If you try this trick with a plain ordinary Python class that you've knocked together, what you get is of course:
>>> f = SomeClass("abc", 10) >>> print(f) <__main__.SomeClass object at 0x7f4b1f3c7fd0>
To do better, I need to implement a __str__
method. When I'm
just putting together first round code to develop my approach to
the problem and prove my ideas, it's often been very easy for me
to skip this step; after all, I don't need that __str__
method
to get my code working. Then I go to debug my code or, more often,
explore how it's working in the Python interpreter
and I discover that I really could use the ability to just see the
insides of my objects without fishing around with dir()
and direct
field access and so on.
By the time I'm resorting to dir()
and direct field access in the
Python REPL, I'm not exactly doing print-based debugging any more.
Running into this during exploration is especially annoying; I'll
call a routine I've just written and I'm now testing, and I'll get
back some almost opaque blobs. I could peer inside them, but it's
especially annoying because I know I've done this to myself.
As the result of writing some Python both today and yesterday,
today's Python resolution is that I'll write basic __str__
methods for all of my little data-holding classes. It only takes
a minute or two and it will make my life significantly better.
(If I'm smart I'll make that __str__
follow some useful standard
form instead of being clever and making up a format that is specific
to the type of thing that I'm putting in a class. There are some
times when I want a class-specific __str__
format, but in most
cases I think I can at least live with a basically standard format.
Probably I should copy what attrs
does.)
PS: collections.namedtuple() is generally not what I want for various reasons, including that I'm often going to mutate the fields of my instance objects after they've been created.
Sidebar: Solving this problem with attrs
If I was or am willing to use attrs (which I have pragmatic concerns with for some code), it will solve this problem for me with no fuss or muss:
>>> @attr.s ... class SomeClass: ... barn = attr.ib() ... fred = attr.ib() ... >>> f = SomeClass("abc", 10) >>> print(f) SomeClass(barn='abc', fred=10)
I'm not quite sure that this will get me to use attrs all by itself, but I admit that it's certainly tempting. Attrs is even available as a standard package in Ubuntu 18.04 (with what is a relatively current version right now, 17.4.0 from the end of 2017).
I confess that I now really wish attrs was in the Python standard
library so that I could use it without qualms as part of 'standard
Python', just as I feel free to use things like urllib
and json
.
Comments on this page:
|
|