这一篇把 Julia 与 Python、MATLAB 的主要差异集中整理一下,方便在系统看各个专题之前先有个整体印象。

先说明几点:

  • 下文默认读者已经熟悉 Python 和 MATLAB;
  • 默认以 Julia 1.12 系列为准;
  • 这里只做迁移视角下的差异整理,不追求把所有细节一次性讲完;
  • 真正的语法和行为细节,仍然以后面各专题笔记为主。

概述

如果只用一句话概括,Julia 大致可以理解为:

  • 语法观感上吸收了 Python、MATLAB、Fortran 等科学计算语言的很多习惯;
  • 执行模型上又明显更接近带 JIT 的编译型语言;
  • 语言设计中心不是 class,而是数组、数值计算、泛型函数和多重分派。

因此,从 Python 或 MATLAB 迁移到 Julia 时,真正需要适应的往往不是“语法会不会写”,而是下面这些更底层的习惯:

  • 语言默认鼓励什么样的代码组织方式;
  • 哪些直觉来自 Python,哪些来自 MATLAB,而 Julia 恰好都不完全一样;
  • 编译、类型推断和方法分派会如何反过来影响日常写法。

整体定位

和 Python 相比,Julia 最明显的差异在于:它并不是先把语言做成通用脚本语言,再靠大量 C/C++ 扩展补上数值性能,而是一开始就把“高性能科学计算”当作核心目标。

  • Python 的科学计算主力通常来自 Numpy、SciPy、PyTorch 这类扩展库;
  • Julia 则希望大量数值代码直接写在语言本身中,也能获得不错的性能;
  • Python 中很多“为了绕开解释器开销”的技巧,在 Julia 里未必仍然是必要的。

和 MATLAB 相比,Julia 也明显不是“开源版 MATLAB”。

MATLAB 的强项在于:

  • 数值计算语法成熟;
  • 工具箱生态稳定;
  • 工作区、脚本、矩阵心智模型非常统一。

Julia 更像:

  • 继承了科学计算语言的书写便利;
  • 但抛掉了不少 MATLAB 的历史包袱;
  • 同时引入了更完整的模块系统、类型系统和包管理。

如果再把视野放宽一点,Julia 的整体设计还能看出一些和其他语言的亲缘关系:

  • 在科学计算定位上,它和 MATLAB、Fortran、R 属于同一大类,都是把数值计算当成核心任务来设计;
  • 在底层执行模型上,它又明显比 Python、MATLAB 更接近带 JIT 的现代编译型路线,这一点更容易让人联想到 JVM、LLVM 体系中的语言;
  • 在泛型函数和分派机制上,它和 C++ 的重载、模板思维有一定相通之处,但 Julia 把这套能力直接做成了语言运行时的常规机制;
  • 在 Unicode 标识符、数学记号、广播和点语法这些地方,它又带有一种很强的“让代码尽量接近公式”的设计倾向,这在传统通用编程语言里并不常见。

语法和数据模型

在代码块结构上:

  • Julia 使用 end 结束代码块;
  • MATLAB 也大量使用 end
  • Python 则依赖缩进。

在一些零碎但高频的语法点上:

  • Julia 使用 # 注释,和 Python 一样,而 MATLAB 使用 %
  • Julia 使用 elseif,MATLAB 也使用 elseif,Python 使用 elif
  • Julia 语句通常不需要 ;,但在 REPL 中加 ; 可以抑制结果显示;MATLAB 中 ; 的存在感更强。

在数组和索引上,Julia 同时像 Python/Numpy,又像 MATLAB:

  • Julia 从 1 开始索引,这点和 MATLAB 一样、和 Python 不同;
  • Julia 使用 A[i, j] 访问元素,这点和 Numpy 一样、和 MATLAB 不同;
  • Julia 默认列优先,这点和 MATLAB/Fortran 更接近;
  • Julia 有真正的一维数组 Vector,而 MATLAB 更偏向“万物皆矩阵”;
  • Julia 切片范围是闭区间,普通切片默认返回拷贝而不是视图,这一点和 Numpy 的常见直觉差异很大。

在线性代数和逐元素运算上,Julia 又明显更像 MATLAB:

  • * 表示矩阵乘法;
  • .* 表示逐元素乘法;
  • ^ 表示幂;
  • .^ 表示逐元素幂。

这和 MATLAB 很接近,而 Python / Numpy 中 * 默认是逐元素乘法,@ 才是矩阵乘法。

在基本数据类型上,Julia 的风格通常比 Python 和 MATLAB 都更“明确”:

  • Julia 默认整数通常是固定位数整数,而 Python 整数是任意精度,MATLAB 默认数值大多先落在浮点数上;
  • Julia 用 nothing 表示空值,Python 用 None,MATLAB 里很多类似语义场景会写成 []
  • Julia 单引号表示字符、双引号表示字符串,这和 Python 不同;
  • Julia 用 im 表示虚数单位,而 MATLAB 常见写法是 i/j,Python 使用 j

如果从更宽泛的语言设计角度看,这里也能看到一些额外的对比:

  • Julia 在数值字面量、复数、有理数、特殊浮点值等方面的支持,比很多通用脚本语言更加“数学化”;
  • 但它又不像 MATLAB 那样几乎把所有默认数值都压到浮点数一条线上,而是保留了更清晰、更适合编译优化的类型区分;
  • 在字符串和值类型处理上,Julia 又比 Python 更强调“不同概念就是不同类型”,这点反而更接近很多静态语言。

函数、类型和作用域

Julia 表面上和 Python 一样,把函数当作一等公民:函数可以赋值、传参、返回。但 Julia 的函数体系远不只是“把 def 换成 function”。

最关键的区别是:

  • Julia 允许最后一个表达式自动作为返回值;
  • Julia 的默认参数是在每次调用时按需计算,而 Python 的默认值是在定义时计算一次;
  • Julia 对关键字参数和位置参数的区分比 Python 更严格;
  • Julia 的同名函数可以对应多组不同的方法实现,调用时再根据参数类型选择具体方法。

这最后一点,就是 Julia 最有代表性的多重分派机制。Python 中类似行为通常要靠动态判断、默认参数、*args/**kwargs 或手工分支来模拟;MATLAB 也有某些重载体验,但远没有 Julia 这样把它放在语言中心。

在类型系统上,Julia 也明显比 Python 和 MATLAB 更强势:

  • Python 是动态类型,但很多时候并不强调显式类型层次;
  • MATLAB 在日常数值代码里通常也不强调类型系统;
  • Julia 则把抽象类型、具体类型、参数化类型、方法分派和类型推断都放在非常核心的位置。

这带来的直接影响是:在 Julia 中,写法是否利于类型稳定和编译器推断,会比 Python 和 MATLAB 中重要得多。

如果把它和其他语言放在一起看,会更容易理解 Julia 的位置:

  • 和 Python、MATLAB 这类动态语言相比,Julia 的类型系统明显更强,也更直接参与性能;
  • 和 Java、C# 这类以 class 为中心的语言相比,Julia 的重心又不在类层次,而在函数和方法;
  • 和 C++ 相比,Julia 也做泛型和重载,但它不是把复杂度主要压在编译期模板机制上,而是通过运行时分派和特化编译来完成;
  • 和传统函数式语言相比,Julia 虽然函数地位很高,但它的目标并不是纯函数式,而是面向数值计算的多范式混合设计。

在作用域和变量语义上,Julia 也有自己的一套风格:

  • 比 MATLAB 更规范完整;
  • 某些地方和 Python 相似;
  • 但因为 soft scope / hard scope、REPL 与脚本行为差异等问题,又不能简单地按 Python 直觉套用。

另外,虽然三种语言都不太鼓励滥用全局变量,但 Julia 对全局变量尤其敏感,因为它不只是代码组织问题,还会直接影响性能推断和编译优化。

工程组织和执行模型

在模块和包管理上,Julia 也不完全像 Python,更不像 MATLAB。

和 Python 相比,一个很重要的不同点是:

  • Python 常常是“一个文件天然就是一个模块”;
  • Julia 更常见的是“一个主模块 + 若干 include(...) 文件”的组织方式。

和 MATLAB 相比,Julia 的模块系统、包系统和项目环境又明显更现代:

  • 有清晰的命名空间概念;
  • 有统一的 Pkg 包管理;
  • Project.toml / Manifest.toml 这种项目环境描述;
  • 环境更像依赖解析上下文,而不是简单的工作区或脚本目录。

最后是执行模型和性能,这也是 Julia 和 Python / MATLAB 差异最大的地方之一。

Python 和 MATLAB 默认都更偏解释器工作流,而 Julia 明显更依赖 JIT:

  • 函数第一次遇到某组参数类型时,可能触发编译;
  • 后续同类调用才更快;
  • 因此“第一次慢、后面快”是正常现象。

这也会直接改变很多性能经验。尤其是在向量化这件事上:

  • 在 Python / MATLAB 中,向量化通常既是写法习惯,也是性能手段;
  • 但在 Julia 中,for 循环本身通常已经足够快;
  • 向量化更多是表达问题,而不是默认的性能捷径;
  • 如果写得不合适,反而可能引入额外分配。

所以从 Python 或 MATLAB 迁移到 Julia 时,很多原本“理所当然”的经验其实都需要重新判断。

如果进一步把它和 C/C++、Fortran 这类传统高性能语言对比,那么 Julia 的特点会更清楚:

  • 它不像 C/C++ 那样把编译期和运行期分得非常开;
  • 也不像 Fortran 那样在数值性能上高度稳定,但语言抽象手段相对保守;
  • Julia 想做的是在高层抽象和高性能之间取得更直接的统一,这也是为什么它一方面很像脚本语言,另一方面又始终带着明显的编译器存在感。

小结

从 Python / MATLAB 迁移到 Julia,最早需要改掉的几个直觉大概就是这些:Julia 的中心不是 class,而是数组、泛型函数和多重分派;语法表面上像 Python 和 MATLAB 的混合体,但执行模型更接近带 JIT 的编译型语言;Python 和 MATLAB 里很多为了迁就解释器或工作区形成的经验,在 Julia 里都要重新判断。