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:

  1. Writing code on the REPL.
  2. 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.

Written by

Geek dad, living in Oslo, Norway with passion for UX, Julia programming, science, teaching, reading and writing.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store