При работе с объектами, когда обычно требуется иметь строковые представления наших объектов в двух разных контекстах, когда:
- Написание кода на REPL.
- Использование объектов в строковом форматировании или интерполяции.
С Юлией работает тихо из коробки. Определим точечный объект на обоих языках. Это для Юли.
struct Point
x::Float64
y::Float64
end
А это для питона
class Point:
def __init__(self, x: float, y: float):
self.x = x
self.y = y
Если мы создадим экземпляр в Julia, он по умолчанию будет печатать объект, как вы написали бы для создания объекта с использованием синтаксиса Julia:
julia> p = Point(10, 20)
Point(10.0, 20.0)
В Python нам не так повезло. Вместо этого мы получаем:
python> p = Point(10, 20)
python> p
<__main__.Point object at 0x108a1f940>
Вместо этого нам нужно реализовать метод __repr__
, который в python используется для определения того, как объект должен отображаться в 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})"
Префикс f является частью современного подхода Python к интерполяции строк, называемого f-string, который я обсуждаю здесь. В любом случае точки теперь можно отображать в REPL:
python> p = Point(10, 3)
python> p
Point(10, 3)
python> str(p)
'Point(10, 3)'
Вы можете видеть, что при использовании с форматированием строк это выглядит так же. Если вам нужно другое представление для использования с форматированием строк, вы должны реализовать метод __str__
. Измените класс Point
, чтобы включить это определение:
def __str__(self):
f"({self.x}, {self.y})"
Теперь, когда вы получите этот результат:
python> str(p)
'(10, 3)'
Для любого читателя Python, интересующегося Джулией, логика совершенно иная. Вы реализуете одну функцию show
.
show(io::IO, p::Point) = print(io, "($(p.x), $(p.y))")
Если вы хотите поддерживать разные представления для разных типов MIME, вы можете зарегистрировать функцию для каждого типа следующим образом:
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
Затем мы можем отобразить точку в разных форматах:
julia> display("text/json", p)
{x = 3.0, y = 4.0}
julia> display("text/json", p)
{x = 3.0, y = 4.0}
Если вместо вывода на стандартный вывод вы хотите получить строковое представление, вы можете использовать функцию repr
. Обе функции используют show
.
julia> repr("text/plain", p)
"Point(3.0, 4.0)"
julia> repr("text/json", p)
"{x = 3.0, y = 4.0}"
Кроме того, можно предоставить определенный контекст для изменения способа отображения объекта.
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
В этом случае мы изменили функцию show
для text/plain
, чтобы проверять пары ключ-значение, хранящиеся в контексте ввода-вывода.
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)"
В следующий раз мы сравним интерполяцию строк в Julia и Python.