String Representation of Objects in Julia and Python

Erik Engheim
2 min readMar 9, 2019

--

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.

--

--

Erik Engheim
Erik Engheim

Written by Erik Engheim

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

Responses (1)