String Representation of Objects in Julia and Python
When working with objects when typically want to have string representations of our objects in two different contexts, when:
- Writing code on the REPL.
- Using objects in string formatting or interpolation.
With Julia the works quiet out of the box. Let us define a point object in both languages. This is for Julia.
struct Point
x::Float64
y::Float64
end
And this is for Python
class Point:
def __init__(self, x: float, y: float):
self.x = x
self.y = y
If we create an instance in Julia, it will default to printing the object as you would have written in to construct the object using Julia syntax:
julia> p = Point(10, 20)
Point(10.0, 20.0)
In Python we are not that lucky. Instead we get:
python> p = Point(10, 20)
python> p
<__main__.Point object at 0x108a1f940>
Instead we need to implement the __repr__
method, which in python is used to define how an object should be displayed in the REPL.
class Point:
def __init__(self, x: float, y: float):
self.x = x
self.y = y
def __repr__(self):
f"Point({self.x}, {self.y})"
The f prefix is part of a modern Python string interpolation approach called f-string, which I discuss here. Anyway points can now be displayed in the REPL:
python> p = Point(10, 3)
python> p
Point(10, 3)
python> str(p)
'Point(10, 3)'
You can see that when used with string formatting, it looks the same. If you want a different representation for use with string formatting, you have to implement the __str__
method. Modify the Point
class to include this definition:
def __str__(self):
f"({self.x}, {self.y})"
Now when you will get this result:
python> str(p)
'(10, 3)'
For any python readers interested in Julia, the logic is entirely different. You implement a single show
function.
show(io::IO, p::Point) = print(io, "($(p.x), $(p.y))")
If you want to support different representations for different MIME types, you can register a function for each type like this:
function show(io::IO, ::MIME"text/json", p::Point)
print(io, "{x = $(p.x), y = $(p.y)}")
end
function show(io::IO, ::MIME"text/plain", p::Point)
print(io, "Point($(p.x), $(p.y))")
end
We can then display point in different formats:
julia> display("text/json", p)
{x = 3.0, y = 4.0}
julia> display("text/json", p)
{x = 3.0, y = 4.0}
If instead of printing to stdout, you want to get the string representation, you can use the repr
function. Both functions utilize show
.
julia> repr("text/plain", p)
"Point(3.0, 4.0)"
julia> repr("text/json", p)
"{x = 3.0, y = 4.0}"
In addition one can provide a specific context to alter the manner in which an object is displayed.
function show(io::IO, ::MIME"text/plain", p::Point)
if get(io, :compact, true)
print(io, "($(p.x), $(p.y))")
else
print(io, "Point($(p.x), $(p.y))")
end
end
In this case we have altered the show
function for the text/plain
to check key-value pairs stored on the IO context.
julia> show(IOContext(stdout, :compact => false), MIME("text/plain"), p)
Point(3.0, 4.0)
julia> show(IOContext(stdout, :compact => true), MIME("text/plain"), p)
(3.0, 4.0)
julia> repr("text/plain", p, context=IOContext(stdout, :compact => true))
"(3.0, 4.0)"
julia> repr("text/plain", p, context=IOContext(stdout, :compact => false))
"Point(3.0, 4.0)"
Next time we’ll compare string interpolation in Julia and Python.