Примечательные отличия от других языков
Хотя пользователям MATLAB синтаксис Julia может показаться знакомым, Julia не является клоном MATLAB. Между ними есть важные синтаксические и функциональные различия. Ниже перечислены некоторые примечательные отличия Julia, которые могут сбить с толку пользователей, привыкших к MATLAB.
Отличия от матлаб
-
Индексы массивов в Julia указываются в квадратных скобках: A[i,j].
A = [1 2 3; 4 5 6; 7 8 9]
i = 2
j = 3
element = A[i, j]
println(element)
6
-
Когда массив в Julia присваивается другой переменной, он не копируется. После присваивания A = B изменение элементов B приведет к их изменению в A.
B = [1, 2, 3]
A = B
B[1] = 10
println(A)
[10, 2, 3]
-
В Julia значения, передаваемые в функцию, не копируются. Если функция изменяет массив, эти изменения будут видны вызывающей стороне.
function modify_array(arr)
arr[1] = 100
end
A = [1, 2, 3]
modify_array(A)
println(A)
[100, 2, 3]
-
В Julia массивы не увеличиваются автоматически при использовании оператора присваивания. Тогда как в MATLAB с помощью выражения a(4) = 3.2 можно создать массив a = [0 0 0 3.2], а с помощью выражения a(5) = 7 — увеличить его до a = [0 0 0 3.2 7], в Julia соответствующий оператор a[5] = 7 выдает ошибку, если длина a меньше 5 или если имя a впервые используется в этом операторе. В Julia есть функции push! и append!, которые позволяют увеличивать объекты типа Vector гораздо эффективнее, чем a(end+1) = val в MATLAB.
A = [1, 2, 3]
push!(A, 4)
println(A)
B = [5, 6, 7]
append!(B, [8, 9])
println(B)
[1, 2, 3, 4]
[5, 6, 7, 8, 9]
-
Мнимая единица sqrt(-1) представлена в Julia константой im, а не i или j, как в MATLAB.
z = 2 + 3im
println(z)
println("Действительная часть: ", real(z))
println("Мнимая часть: ", imag(z))
2 + 3im
Действительная часть: 2
Мнимая часть: 3
-
В Julia числовые литералы без десятичного разделителя (например, 42) создают целые числа, а не числа с плавающей запятой. В результате некоторые операции могут приводить к ошибке выхода за пределы области, если они ожидают число с плавающей запятой. Например, julia> a = -1; 2^a выдаст такую ошибку, так как результат не целочисленный (подробные сведения см. в разделе FAQ об ошибках выхода за пределы области).
a = 42 # целое число
b = 42.0 # число с плавающей запятой
c = float(42) # явное преобразование к типу Float64
println(a)
println(b)
println(c)
42
42.0
42.0
-
Если в Julia нужно вернуть или присвоить несколько значений, используются кортежи, например (a, b) = (1, 2) или a, b = 1, 2. В Julia нет функции nargout, которая часто применяется в MATLAB для выполнения дополнительных действий в зависимости от количества возвращенных значений. В аналогичных целях можно использовать необязательные и именованные аргументы.
function get_values()
return 1, 2
end
x, y = get_values()
println(x)
println(y)
1
2
-
В Julia есть истинные одномерные массивы. Векторы столбцов имеют размер N, а не Nx1. Например, выражение rand(N) создает одномерный массив.
v = [1, 2, 3] # одномерный массив
3-element Vector{Int64}:
1
2
3
-
В Julia конструкция [x,y,z] всегда создает массив, содержащий три элемента: x, y и z. — Для конкатенации по первому («вертикальному») измерению вызовите функцию vcat(x,y,z) или используйте в качестве разделителя точку с запятой ([x; y; z]). — Для конкатенации по второму («горизонтальному») измерению вызовите функцию hcat(x,y,z) или используйте в качестве разделителя пробел ([x y z]). — Для создания блочных матриц (с конкатенацией по первым двум измерениям) вызовите функцию hvcat или комбинируйте пробелы и точки с запятой в качестве разделителей ([a b; c d]).
A = [1, 2, 3]
B = [4, 5, 6]
C = [7, 8, 9]
D = vcat(A, B, C) # вертикальная конкатенация
println(D)
E = hcat(A, B, C) # горизонтальная конкатенация
println(E)
F = [A; B; C] # разделитель ";"
println(F)
G = [A B C] # разделитель пробел
println(G)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1 4 7; 2 5 8; 3 6 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1 4 7; 2 5 8; 3 6 9]
-
В Julia конструкции a:b и a:b :c создают объекты AbstractRange. Для создания полного вектора, как в MATLAB, используйте метод collect(a:b). Однако обычно вызывать collect не нужно. Объект AbstractRange в большинстве случаев ведет себя как обычный массив, однако он эффективнее благодаря «ленивому» вычислению значений. Этот шаблон создания специальных объектов вместо полных массивов применяется часто, в том числе с функциями, такими как range, и итераторами, такими как enumerate и zip. Специальные объекты, как правило, можно использовать как обычные массивы.
range = 1:5
vector = collect(range)
println(vector)
[1, 2, 3, 4, 5]
-
Функции в Julia возвращают результат вычисления последнего выражения или выражения с ключевым словом return. Перечислять имена возвращаемых переменных в определении функции не нужно (подробные сведения см. в разделе Ключевое слово return).
function sum(x, y)
x + y
end
result = sum(2, 3)
println(result)
5
-
В Julia при вызове функции без аргументов необходимо использовать круглые скобки, например rand().
function example()
println("Функция без аргументов")
end
example()
Функция без аргументов
-
В Julia не рекомендуется ставить точку с запятой в конце выражений. Результаты выражений не выводятся на экран автоматически (кроме как в интерактивной командной строке), поэтому строки кода нет необходимости заканчивать точкой с запятой. Для вывода на экран определенных данных можно использовать функцию println или макрос @printf.
a = 2
b = 3
c = a + b
println(c)
5
-
В Julia, если A и B — массивы, операции логического сравнения, такие как A == B, не возвращают массив логических значений. Вместо этого используйте A .== B или аналогичные выражения для других логических операторов, таких как < и >.
A = [1, 2, 3]
B = [2, 2, 3]
result = A .== B
println(result)
Bool[0, 1, 1]
-
В Julia операторы &, | и ⊻ (xor) выполняются побитово, так же, как, соответственно, and, or и xor в MATLAB. Их приоритет такой же, как у побитовых операторов в Python (но не такой, как в C). Они могут применяться к скалярным значениям или поэлементно к массивам, а также использоваться для объединения логических массивов. Однако обратите внимание на различие в очередности операций: могут потребоваться круглые скобки (например, для выбора элементов A, равных 1 или 2, используйте выражение (A .== 1) .| (A .== 2)).
a = 5
b = 3
result = a & b
println(result)
A = [true, false, true]
B = [false, true, true]
result = A .& B
println(result)
1
Bool[0, 0, 1]
-
В Julia элементы коллекции могут передаваться в функцию как аргументы с помощью оператора расширения (splat-оператора) …, например xs=[1,2]; f(xs…).
function sum_elements(x, y, z)
return x + y + z
end
values = [1, 2, 3]
result = sum_elements(values...)
println(result)
6
-
Функция svd в Julia возвращает сингулярные значения в виде вектора, а не плотной диагональной матрицы.
using LinearAlgebra
A = [1 2; 3 4]
U, S, V = svd(A)
println(S)
[5.464985704219043, 0.3659661906262575]
-
В Julia символ … не применяется для продолжения строк кода. Вместо этого неполное выражение автоматически продолжается в следующей строке.
a = 2 +
3
println(a)
5
-
Структуры (struct) в Julia не поддерживают динамическое добавление полей во время выполнения, в отличие от классов (class) в MATLAB. Вместо этого используйте Dict. Словари в Julia не упорядочиваются.
struct MyStruct1
field1::Int
end
s = MyStruct1(10)
println(s.field1)
# Используем словарь для добавления поля field2
s_dict = Dict(:field1 => s.field1, :field2 => 20)
println(s_dict[:field2])
10
20
-
В Julia каждый модуль имеет собственную глобальную область или пространство имен, в то время как в MATLAB глобальная область только одна.
module MyModule
global_var = 10
function my_function()
println(global_var)
end
end
MyModule.my_function()
10
WARNING: replacing module MyModule.
-
В MATLAB идиоматическим способом удаления ненужных значений является использование логического индексирования, как в выражении x(x>3) или в операторе x(x>3) = [] для изменения x на месте. В Julia с этой целью предоставляются функции более высокого порядка filter и filter!, которые позволяют использовать выражения filter(z→z>3, x) и filter!(z→z>3, x) в качестве альтернативы для x[x.>3] и x = x[x.>3]. Функция filter! позволяет реже прибегать к временным массивам.
A = [1, 2, 3, 4, 5]
filtered_A = filter(x -> x > 3, A)
println(filtered_A)
filter!(x -> x > 3, A)
println(A)
[4, 5]
[4, 5]
-
Извлечение (или «разыменование») всех элементов массива ячеек, например vertcat(A\{:}) в MATLAB, записывается в Julia с помощью оператора расширения (splat-оператор), например vcat(A…).
A = [1, 2]
B = [3, 4]
C = [5, 6]
array_of_arrays = [A, B, C]
concatenated_array = vcat(array_of_arrays...)
println(concatenated_array)
[1, 2, 3, 4, 5, 6]
-
В Julia функция adjoint производит сопряженное транспонирование; в MATLAB adjoint предоставляет присоединенную матрицу (классическое сопряжение), то есть выполняет транспонирование матрицы алгебраических дополнений.
A = [1+2im 3+4im]
adj_A = adjoint(A)
println(adj_A)
Complex{Int64}[1 - 2im; 3 - 4im;;]
-
В Julia выражение (a ^ b ^ c) вычисляется как a^ (b^c), в то время как в MATLAB — как (a ^ b) ^ c.
a = 3
b = 2
c = 3
result = a^(b^c)
println(result)
6561
Отличия от Python
-
В Julia блоки for, if, while и т. д. заканчиваются ключевым словом end, а не отступом, как в Python. Нет ключевого слова pass.
for i in 1:5
println(i)
end
1
2
3
4
5
-
В Julia строки обозначаются двойными кавычками, используются для многострочных текстов три пары двойных кавычек. Также, для символов используются одинарные кавычки.
str1 = "Hello, World!"
str2 = """Это много-
строчный текст."""
char1 = 'c'
'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
-
В Julia для конкатенации строк используется оператор _, а не +, как в Python. Для повтора строк используется оператор ^, а не _.
str1 = "Hello, "
str2 = "World!"
concatenated_str = str1 * str2
repeated_str = str2 ^ 3
println(concatenated_str)
println(repeated_str)
Hello, World!
World!World!World!
-
В Julia списки соответствуют типу Vector{Any} или более общему типу Vector{T}, где T - некоторый тип элементов. Более эффективные массивы, подобные массивам NumPy, могут быть представлены массивами Array{T}, где T - конкретный тип элементов.
list1 = Any[1, "two", 3.0]
list2 = Vector{Int}(undef, 5)
array1 = Array{Int}(undef, 3, 3)
3×3 Matrix{Int64}:
3762813801648698725 3774918513298847538 7077182949550143800
3762529018811868721 7364623875528025187 140502613063936
3991368380935386977 3906925892200719205 140518684094896
-
Индексирование массивов в Julia начинается с единицы, в отличие от Python, где индексация начинается с нуля.
array = [1, 2, 3, 4, 5]
println(array[1]) # Выведет 1
1
-
При индексировании срезов в Julia последний элемент включается, в отличие от Python. a[2:3] в Julia эквивалентно a[1:3] в Python.
array = [1, 2, 3, 4, 5]
println(array[2:3]) # Выведет [2, 3]
[2, 3]
-
В Julia допустимы массивы AbstractArray с произвольными индексами. Отрицательные индексы, имеющие особый смысл в Python, записываются в Julia в виде a[end] и a[end-1].
array = [1, 2, 3, 4, 5]
println(array[end]) # Выведет 5
println(array[end - 1]) # Выведет 4
5
4
-
Для индексирования до последнего элемента в Julia используется ключевое слово end. x[1:] в Python эквивалентно x[2:end] в Julia.
array = [1, 2, 3, 4, 5]
println(array[2:end]) # Выведет [2, 3, 4, 5]
[2, 3, 4, 5]
-
В Julia индексирование диапазона имеет формат x[start:step:stop], а в Python - x[start:(stop+1):step]. Поэтому x[0:10:2] в Python эквивалентно x[1:2:10] в Julia.
array = [1, 2, 3, 4, 5]
println(array[1:2:end]) # Выведет [1, 3, 5]
[1, 3, 5]
-
В Julia отсутствует синтаксис продолжения строк. Если строка содержит полноценное выражение, то она считается завершенной. В противном случае строка продолжается. Для продолжения выражения можно использовать круглые скобки.
a = (
1 + 2 +
3
)
println(a) # Выведет 6
6
-
В Julia массивы развертываются по столбцам, в то время как массивы NumPy развертываются по строкам. При переборе массивов в Julia порядок циклов должен быть обратным по сравнению с NumPy.
A = [1 2; 3 4; 5 6]
for j in 1:size(A, 2), i in 1:size(A, 1)
println(A[i, j])
end
1
3
5
2
4
6
-
В Julia значения по умолчанию аргументов функции вычисляются при каждом вызове метода, в отличие от Python, где значения вычисляются только при определении функции.
function f(x = rand())
return x
end;
println(f()) # Выполните ячейку несколько раз
0.975434444871681
-
В Julia именованные аргументы должны передаваться с указанием имен, в отличие от Python.
function foo(a; b = 1, c = 2)
return a + b + c
end
println(foo(10, b = 3, c = 4)) # Выведет 17, нельзя вызывать как println(foo(10, 3, 4)), в случае с Python
17
-
В Julia тип Int соответствует машинному целочисленному типу (Int32 или Int64), в то время как в Python int может иметь произвольную длину.
x = Int64(2) ^ Int64(64)
println(x) # Выведет 0
0
-
Мнимая единица в Julia представлена константой im, в то время как в Python используется j.
println(2im) # Выведет 0 + 2im
0 + 2im
-
В Julia оператор возведения в степень обозначается ^, а не **, как в Python.
println(2 ^ 3) # Выведет 8
8
-
Пустое значение в Julia обозначается константой nothing типа Nothing, в то время как в Python используется объект None типа NoneType.
x = nothing
println(x) # Выведет nothing
nothing
-
В Julia оператор * выполняет матричную операцию, в то время как в Python выполняется поэлементное умножение. В Julia для поэлементного умножения используется оператор .*.
A = [1 2;
3 4]
B = [5 6;
7 8]
println(A * B) # Выведет матрицу, [19 22; 43 50]
println(A .* B) # Выведет матрицу, [5 12; 21 32]
[19 22; 43 50]
[5 12; 21 32]
-
В Julia оператор ' возвращает сопряжение вектора, в то время как оператор транспонирования .T в Python возвращает исходный вектор.
x = [1 2 3]
println(x') # Выведет [1; 2; 3]
[1; 2; 3;;]
-
В Julia функция может иметь несколько конкретных реализаций (методов), которые выбираются на основе типов аргументов. В Python функция имеет единственную реализацию, и полиморфизм не поддерживается.
function square(x::Number)
return x * x
end
function square(x::String)
return string(x, x)
end
println(square(2)) # Выведет 4
println(square("hello")) # Выведет "hellohello"
4
hellohello
-
В Julia отсутствуют классы, вместо них используются структуры, которые содержат только данные, но не методы.
struct MyStruct
x::Int
y::Float64
end
function f(obj::MyStruct, z)
return obj.x + obj.y + z
end
my_obj = MyStruct(1, 2.5)
println(f(my_obj, 3.5)) # Выведет 7.0
7.0
-
Вызов метода экземпляра класса в Python соответствует вызову функции в Julia.
struct MyType
x::Int
end
function f(obj::MyType, y)
return obj.x + y
end
my_obj = MyType(10)
println(f(my_obj, 5)) # Выведет 15
15
-
Структура в Julia может иметь только один абстрактный супертип, в то время как классы Python могут наследоваться от нескольких суперклассов.
abstract type Animal end
struct Dog <: Animal
name::String
end
struct Cat <: Animal
name::String
end
dog = Dog("Buddy")
cat = Cat("Whiskers");
-
В Julia тернарный оператор записывается как x > 0 ? 1 : -1, в то время как в Python используется условное выражение 1 if x > 0 else -1.
x = 10
result = x > 0 ? 1 : -1
println(result) # Выведет 1
1
-
В Julia обработка исключений осуществляется с помощью конструкции try-catch-finally, в отличие от Python, где используется try-except-finally.
try
# Код, который может вызвать исключение
catch ex
# Обработка исключения
finally
# Выполнение кода, который будет выполнен в любом случае
end