You finished the course, get the certificate

Getting Started with Rust as Python Devs

Episode #563, published Wed, Sep 16, 2026, recorded Wed, Sep 9, 2026
0:00
01:10:50
Lint the entire CPython code base from scratch. It takes 0.3 seconds. Three blinks of an eye.

That is ruff, and it is written in Rust. So are Pydantic, Polars, uv, and Granian. Rust shows up in Python three ways: tools that happen to be Rust, libraries Python imports, and servers that run Python inside Rust. This is Rust for Python developers, not Rust experts.

Christopher Trudeau is back on Talk Python to discuss Rust and his latest course Up and Running with Rust. The core rule is that only one thing can own a value at a time. Pass it around freely in Python and the garbage collector cleans up. Do that in Rust and it will not compile.

Watch this episode on YouTube
Play on YouTube
Watch the live stream version

Episode Deep Dive

Guest Introduction and Background

Christopher Trudeau is a consultant who spends most of his time working with teams on software architecture and technical process, which in practice means agile and lean methods, automation, and CI/CD. In his spare time he teaches, sometimes in person, sometimes virtually, and often by building online courses, and a large share of that work lands in the Python world. Listeners may know his voice from The Real Python Podcast, which he co-hosts. His Talk Python guest bio adds a bachelor's and master's in computer engineering from the University of Waterloo and industry experience ranging from small startups to IBM, AOL, and Disney. He is also the author of Django in Action from Manning and the creator of dozens of courses at Real Python and Talk Python Training, most recently Up and Running with Rust, the Talk Python course that inspired this episode. His route into Rust runs through a low-level background. He was writing C at 13 or 14, back when there were not many other choices, and went on to write device drivers and embedded systems. That grounding, he says, is the one Rust "kind of expects you to have," and it is why he did not find the language as hard as its reputation suggests. Lately he has been getting into Rust in earnest and figured it was time to compare notes with Michael. This is a return visit: he previously joined the show for HTMX for Django Developers (episode 437) and 17 Libraries You Should Be Using in Django (episode 379).

What to Know If You're New to Python

This episode looks at a second language through Python eyes, so the most useful background is not more Python syntax but the machinery Python normally hides from you: how code gets executed, where values live in memory, and how compiled code ends up importable. A little familiarity with the following will make the comparisons land.

  • Compiled versus interpreted code: Python compiles your source to bytecode and an interpreter runs it, which is why the same .py file works on any platform. Rust compiles to native machine code for one specific platform, which is where its speed comes from and why there is no real Rust REPL. This distinction drives half the differences discussed in the episode.
  • The stack, the heap, and references: In Python every value is an object living on the heap and every variable is a reference to one, so you never think about where things are stored. Rust makes the stack versus heap split and the question of who owns a value explicit, and its compiler checks your answers. Christopher walks through both, and it helps to know the words going in.
  • Type hints: Rust declarations look a lot like typed Python: a variable name, a colon, a type, and an arrow for return types. If you have written or read type-hinted Python, clean Rust code will be surprisingly readable.
  • C extensions and wheels: Python has always been able to import modules written in compiled languages, and a wheel is a pre-built package that can carry that compiled code for a specific platform. Pydantic and Polars ship this way, and the PyO3 and maturin discussion is about doing the same thing from Rust.
  • Modern packaging tools: Knowing what pip, uv, pyproject.toml, and PyPI each do will pay off, because the episode maps every one of them onto its Rust counterpart: rustup, cargo, Cargo.toml, and crates.io.

Key Points and Takeaways

Rust reaches Python three ways, and you can benefit from all of them without writing a line of it

The frame for the whole episode is Christopher's breakdown of how Rust intersects with Python. The first mode has almost nothing to do with Python: tools like ruff are written in Rust because Rust is fast, but they could just as easily have been written for any other language, and you use them without ever seeing the Rust. The second and most common mode is a library written in Rust and exposed to Python as a regular module, which is how Pydantic and Polars get their speed. The third inverts the relationship: a Rust program embeds the Python interpreter, which is what the Granian web server does when it runs your Python web app inside a Rust process. Michael reached for a caramel apple analogy, with Pydantic as a caramel-dipped apple that has Python on the outside and a Rust core, Granian as a caramel M&M with a hard Rust shell around a Python center, and tools like ruff as apple slices next to a bowl of caramel that you mix and match. Christopher admitted they were officially stretching the analogy and that he was now hungry. The point stands: Rust has quietly become the way Python gets fast, and this episode is about knowing enough Rust to read it, poke at it, and reach for it when it counts.

Orders of magnitude change how you work: ruff on 170,000 lines, and all of CPython in 0.3 seconds

Christopher's explanation for why Rust tooling took off so fast is that most of the tools Python developers relied on historically were themselves written in Python, and they were slow in a way nobody noticed because you just went for another cup of coffee. A 10 percent speedup goes unnoticed, but when a tool gets multiple zeros faster, your workflow shifts. Michael's own moment came running ruff over the Talk Python Training app, about 170,000 lines of Python, and having it report four errors before he could blink. He assumed it had stopped early or skipped the subdirectories, because there was no way it had parsed everything against a hundred rules that fast. For a number people can relate to, he cited linting the entire CPython code base from scratch in 0.3 seconds, roughly three blinks of an eye. Christopher added that on his deliberately older hardware the difference is even larger when you lint a couple hundred thousand lines. That step change is why a few key libraries convinced everyone there was real value here, and why so many Rust-backed Python tools have sprung up since.

Ownership is the core idea: only one thing can own a value at a time

The concept Christopher singled out as the hardest part for people arriving from Python is memory management, because Python simply takes care of it. Rust has objects, but every object belongs to somebody, and only one owner is allowed at a time. In Python you pass values around freely and the garbage collector cleans up; in Rust that same habit often becomes a compile error. That is the beauty, since it guarantees certain bugs never happen, and also the frustration, since you cannot play as loosely as you can in a dynamic language. It is the source of the joke that Rust has no bugs, you just spend all your time getting it to compile. The compensation is that the compiler's error messages are, in his words, absolutely fantastic. They are explicit, they usually suggest a fix, and he found the suggestion right 80 or 90 percent of the time. Once you learn the vocabulary of the messages, an error becomes "oh, that's kicking off the borrow checker, I'll go fix it." Michael noted, for the record, that the borrow checker got its first shout-out just under seven minutes into the recording.

A whole category of memory bugs cannot be written in Rust

To explain what the strictness buys you, Christopher told the story of how C stores a string. Store the text "Talk Python" and you get those bytes followed by a null byte, and the null is the only way the program knows where the string ends. Write something longer than the space you reserved and there is no null, so the program keeps walking into the next chunk of memory. Free a block but keep a pointer into it and the computer will happily read whatever is there now. Sometimes that produces a wrong message on screen, and sometimes it takes your program down, which is what makes this family of bugs so tricky: they crash only sometimes. Rust is not bug free, but this category of bug simply cannot be created, and the price is a harder time getting to a successful compile. The same applies to types: in Python without a type checker, a type mismatch is something you discover at runtime, while in Rust it is caught before the program exists. Michael connected this to his own history with the C++ Primer Plus book, where getting code to compile was only the beginning of the suffering, and observed that compiling genuinely means more in Rust than it used to in other languages.

Integers are hardware sized in Rust, and that is exactly where the speed comes from

Python integers are boundless. Christopher mentioned an article about someone building a SIMD-style machine out of bitwise operations on thousand-byte integers, and Python just shrugs and handles it. Rust uses integers the way your CPU does: if you pick an 8-bit integer you cannot put nine bits in it, and you have to decide up front whether the value is signed or unsigned, which for a single byte means 0 to 255 or a range split across negative and positive numbers. The compiler catches many of these problems, but you are now making a design decision about how many bits to store something in, and occasionally hitting boundaries you never had to think about. Christopher pointed out that these concepts exist in Python too, buried further down for people packing network packets, but Rust and most compiled languages do not give you the choice. That lack of choice is the trade: Python's limitless integer needs machinery to grow when it overflows a chunk of memory, and that machinery is overhead. Rust has none of it, so it maps exactly onto what the CPU does, and Michael summed it up with "you're never going to get a Python integer into a CPU register." Both remembered the whiplash of coming to Python from C++ and C# and being unable to find where you tell it how big a number is.

Stack versus heap: Python hides it, Rust puts it in your face

Christopher gave a compact tour of the stack and heap. The stack is where function calls happen: when you jump into a function, the return address and the parameters go onto a stack frame, and when the function returns, that frame pops off. The heap is the general space for longer-lived things and for anything passed around between functions. In Python you only think about the stack when something fails and you get a stack trace, but Rust's memory management differentiates between the two, and once you start passing objects around, the question of "am I on the stack or the heap, and who owns this" becomes essential. Michael pointed out the irony that Python, which never talks about pointers, is actually more pointer heavy than C or Rust because literally everything lives on the heap, even the number one. Christopher's take was that this is how Python got away with not having pointers: if everything is a pointer, there is nothing to differentiate. They detoured into CPython's small integer cache, where numbers from roughly negative five to 255 are pre-allocated so every literal 72 points at the same immutable object, which produced Christopher's line about having three copies of 254 but only one copy of two. Michael added the performance angle: an array of Python numbers is scattered across the heap, while ten Rust integers sit contiguously in memory where the CPU cache can actually use them.

The syntax is more familiar than you expect, with a few things that will bug you

Christopher suggested starting with what is not different. Hand a Python developer some clean Rust and they will probably follow it: the loops are the same, if and else are similar (with no elif, which he never understood in Python anyway), there are tuples and arrays, iterators and collections, and because Rust is strictly typed the declarations look like typed Python, with name-colon-type variables and an arrow for return types. Both agreed this shape is shared across newer typed languages like TypeScript and Swift, and that everyone ultimately borrowed from C, the granddaddy of most languages we use. Then the differences start. Rust uses fn instead of def, which Christopher immediately preferred because it says what it is. Blocks are delimited by braces rather than indentation, and after nearly two decades of Python he has come down on the side of "screw the parser," though Michael countered that indentation-based structure has bitten him when a reformat silently changed what code did, and gave Python's approach an 80 percent plus, 20 percent minus. Almost everything in Rust is an expression, so a brace block can return a value like an inline function, which Christopher finds elegant. What neither of them likes is the implicit return at the end of a function, with Michael declaring he will never be on team implicit return.

Compiled to machine code: a real binary you can hand someone, and no REPL

One fundamental difference Christopher says confuses students is that Python does compile, just not to the same thing. Python compiles source to bytecode, a binary file that is not platform specific; he compared it to a formula stored in an Excel file, where Excel is the thing that actually runs it. Your interpreter is specific to your machine, but the bytecode is not. Rust compiles to a tight binary of machine code for one platform, so if Christopher hands you his binary and you are on the same kind of system, it runs, and if you are not, it does not. Michael confessed to being jealous: he would love a python build command that produced a single file he could put on a server, hand to a person, or drop into Docker without a pile of supporting pieces. The trade is that distribution is easy but platform specific, so targeting several platforms means compiling on each of them. The other casualty is the REPL. Rust has some REPL-like hacks that recompile a whole program every time you enter a line, which Christopher tried and abandoned in favor of a scratch file, and Michael pictured the invisible fn main and braces wrapping each line before a cargo run. That per-platform binary is also the reason you get different wheels for the same Python package, which comes back later in the PyO3 discussion.

A release every six weeks, an edition every three years

Rust ships a new version every six weeks, which Christopher admits sounds insane coming from Python. The thing that makes it workable is editions, a separate concept on a three-year cycle. Everything stays compatible within an edition, and the compiler can build to older editions, so you can specify an edition target in Cargo.toml and keep compiling old code without racing to stay current. Christopher likes the idea a lot and suspects Python would benefit from something similar, though he also admitted this forever-backward-compatibility promise smells like maintenance hell and that Rust may give it up as the language ages. Michael's version: it is fine when there are three editions, but what about 35? For now the language has changed a fair amount in a few years without anyone getting stranded. Michael, for his part, enjoys the freshness, having updated his tools that very morning and found a new Rust waiting.

Getting started: rustup is pyenv, cargo is uv, Cargo.toml is pyproject.toml

On Linux or macOS, installation is a breeze: copy the shell command from the front page of rust-lang.org and paste it into a terminal, which Michael described as the usual practice of running arbitrary code from the internet as root and assuming it is fine. That command installs rustup, which Christopher likened to pyenv because it handles installing and updating the language itself. Rustup installs rustc, the compiler, and more importantly cargo, the tool you actually use, which is very uv-like; you almost never invoke rustc directly. Running cargo new hello creates a Cargo.toml (the pyproject.toml equivalent), a src directory, a stub main file with a working function, and by default a git repository with a .gitignore, which drives Christopher nuts because he wants to control that himself. From there, cargo run builds and runs the program, dropping the result a few directories deep in a target folder. Flags switch between a debug build, which is about 30 percent larger because it carries debug information, and a release build you could distribute. Christopher's one gripe is that cargo run prints a few lines of build output before your program's own output, which the -q flag suppresses.

Crates, crates.io, and the batteries-not-included trade-off

Cargo also manages crates, the Rust equivalent of wheels, and crates.io is the equivalent of PyPI, with a robust community writing and trading code. Michael pulled up the numbers live: 331,019 crates versus roughly 889,000 to 890,000 packages on PyPI, though he doubted the raw count is the core metric. Christopher agreed and argued the comparison is unfair in the other direction: coming from the batteries-included world, there are not a lot of batteries in Rust. Something as simple as a random number is a crate, a choice made to keep the footprint small. That raises a trust question for someone who describes himself as paranoid about where code comes from. In Python, sticking to the standard library buys a degree of safety, and outside it he wants to hear that people have used and trusted a library. He has not yet figured out how to get that signal in the Rust world, so there is a bit more rolling of the dice, which Michael tied to the supply chain problem with "just because you're paranoid doesn't mean they're not after you." Michael also offered a theory for why Python is batteries included at all: it appeared around 1991, before PyPI and before the web, when getting anything after the fact was really hard.

Packaging went in a circle: cargo learned from PyPI and npm, then uv learned from cargo

Michael observed that much of the recent revolution in Python packaging and project management came from the Rust side, with uv and friends openly inspired by cargo and crates. But cargo was built in a world where PyPI and npm already existed, so its designers could look at what went wrong and do it differently, which makes the influence a loop rather than a one-way street. Christopher offered a deliberately spicy take: the decision that package management was not really part of the Python language, leaving a plethora of third-party tools, was a mistake, and the Rust people recognized it and bundled the tooling in. He then softened it by noting Rust's target is simpler, since compiled code removes a lot of the complications that Python's dynamism creates. Michael's example of that complexity: a Python package that also requires a Fortran compiler. Both agreed wheels were the turning point, since they ended the era of every install recompiling from source with bespoke tools, and that Python is making real progress. Christopher's closing thought was generous: we should all be so lucky as to have our early design decisions questioned because people are still using our software 35 years later.

PyO3 and maturin: from a Rust function to a plain Python import

Python was designed from the start as an integration language, and Christopher noted that a good chunk of the standard library is a thin wrapper over the C standard library, with the older parts still creaky enough in their naming that a C programmer recognizes them on sight. The same interface that C extensions use works for Rust, which is how Pydantic and Polars are written in Rust and exposed with a very thin veneer that Python treats like any other module. PyO3 is the crate that defines that interface between the compiled dynamic library, a .so or .dll, and Python's ABI. It provides Rust objects that mirror Python objects, such as a PyInt for reaching a Python integer from Rust, or it can map ordinary Rust types like an i32 to Python integers for you. It also ships macros that you attach to a regular Rust function or class to declare that it should be available to Python, including how its arguments map. Compile that and everything lands in a .so, and then maturin puts the result into a virtual environment and handles the packaging, so from Python you just import it. Michael asked about mixing languages, and Christopher pointed to Polars, which installs as two wheels: a universal wheel containing only Python and a platform-specific wheel containing the compiled Rust library. It does not have to be two wheels; maturin will bundle a project where the performance-critical part is Rust and the rest is Python, which is no different from any other plugin mechanism.

Rust does not guarantee speed: boundaries, Amdahl's Law, and "don't, then measure"

Michael suggested there is low-hanging fruit in profiling your code and discovering that only 20 lines really matter. Christopher agreed but added the catch: every call from Python into Rust crosses a boundary, and crossing it has a cost, so code that bounces back and forth constantly, or objects that cross constantly, can end up slower in Rust than in Python. The pattern that wins is the Polars and Pydantic shape, where you hand over a big chunk of work, such as a JSON payload or a number-crunching job, let Rust finish it, and take the answer back. His general advice on optimization is "don't, and then measure," because no matter how good you are, guessing up front leads to the wrong assumptions, and Michael recalled being spectacularly wrong about what was slow early in his career. Christopher invoked Amdahl's Law, and Michael pushed it to the extreme: if 20 percent of your time is in one spot and you make that spot infinitely fast, the program is at most 20 percent faster, so a heroic GPU rewrite that turns five milliseconds into four is rarely worth the deployment cost. Christopher's version: making code three times harder to read to save half a millisecond in something you call once a year gives you back a month of your life. Michael also teased that Python 3.15's new sampling profiler, which can attach to a running production process for 30 seconds and step away, is coming up on the show with its authors.

Somebody may have already written it: awesome-python-rs and drop-in replacements

For getting started, Christopher's first stop is rust-lang.org, which he called remarkably well documented, with the Rust book right there and easy to follow. For seeing Rust actually used in the Python world rather than in textbook examples, he pointed to awesome-python-rs, a massive curated list of Python tools and libraries with Rust under the hood, which Michael admitted he could happily poke around for half an hour instead of watching a movie. The list includes classic drop-in replacements for speed, such as a cryptography library and a JSON library that swap in for standard-library functionality and are, in Christopher's words, screamingly faster. That reframes the optimization question: before rewriting your slow code in Rust, check whether someone already has, and simply swap your JSON parser. Many of these Python libraries are thin wrappers, sometimes just a few lines of API glue, over existing Rust libraries with thousands of stars and many contributors, because the Rust community itself depends on them. Polars is the model case, a Rust library for Rust programmers with a Python layer on top, so it gets both communities' usage. As Michael put it, you no longer have to trust that somebody's weekend rewrite of JSON parsing is correct.

Is Rust hard? It depends where you come from, and it may improve your Python

Christopher hears constantly that Rust is hard to grasp and did not find it that way, but he was careful not to diminish people who do. His explanation is background, not brains: he was writing C in his early teens and later device drivers and embedded systems, which is the closer-to-the-machine grounding Rust expects. For contrast he described a conversation with Bob Belderbos of Pybites, who came from PHP and Python, found Rust a whole other kind of experience, and yet believes it has made him a better Python developer because he now thinks about memory in ways a pure Python background never required. Michael recognized the same pattern in himself: he never came to Python or JavaScript without already knowing what to do with a double pointer, so the memory model was never a surprise. Both agreed the friction is real for new developers, since the threshold to playing around is higher when you are fighting the compiler, but that what you learn transfers. Christopher also noted the wider moment, having seen news that morning of a major CPU maker moving device drivers to Rust, and Michael revived his old joke that switching to Rust used to guarantee VC funding, which Christopher updated to Rust plus AI.

Interesting Quotes and Stories

"There's a joke in the Rust world that there are no bugs. All your time isn't debugging. All your time is getting it to compile." -- Christopher Trudeau

"They often include something like, maybe you need to do this, and from what I saw they were right 80 or 90 percent of the time." -- Christopher Trudeau, on Rust compiler error messages

"So Rust isn't bug free, but there is a category of bugs that it just doesn't let you create." -- Christopher Trudeau

"While it was an eye-opener that compiling was only the beginning of my suffering when I was learning programming, I think compiling does mean more in Rust than it used to in other languages." -- Michael Kennedy

"He actually thinks it's made him a better Python developer, because now he's thinking about memory and stuff like that a little more than you necessarily would if you've just come from Python." -- Christopher Trudeau, on Bob Belderbos learning Rust

"I remember running ruff on it, and it goes, found these four errors. I'm like, no, you didn't. Did you stop after you found four errors? How can you be finished?" -- Michael Kennedy, on linting 170,000 lines of Talk Python code

"You're never going to get a Python integer into a CPU register." -- Michael Kennedy

"Python is more pointer heavy than any of those languages because literally everything is in the heap. Even a number is a pointer to a thing in the heap." -- Michael Kennedy

"Well, this is how Python got away with not having pointers. It was everything's a pointer, so we don't have to differentiate." -- Christopher Trudeau

"I have three copies of 254, but I only have one copy of two." -- Christopher Trudeau, on CPython's small integer cache

"I think after having coded in Python for almost two decades, I've come down on the side of screw the parser." -- Christopher Trudeau, on brace brackets versus indentation

"I am never, ever going to be on team implicit return. I just can't." -- Michael Kennedy

"Wow, would I love a Python --build thing. Just a thing that I could put on a server, I could give to a person, I could put in Docker, and it doesn't have to have a bunch of other stuff there to make it possible." -- Michael Kennedy

"We do the thing that we normally do. We run arbitrary code from the internet as root on our machine and I'm sure it's fine." -- Michael Kennedy, on curl-to-shell installers

"You know, Chris, just because you're paranoid doesn't mean they're not after you." -- Michael Kennedy, on supply chain security

"The decision that the PSF made that managing packages wasn't really part of the language and that we should have this plethora of third party tools to do that, I think that was a mistake. And I think the Rust people recognized that and decided to bundle this in." -- Christopher Trudeau

"We should all be so lucky. Lucky is having our initial designs become questionable because 35 years later, people are still using our software." -- Christopher Trudeau

"The general advice I give folks when I talk about optimization is don't, and then measure." -- Christopher Trudeau

"As programmers, I think we often get tied up in the, oh, wouldn't it be cool if I made this code three times harder to read and it'll be half a millisecond faster? And how often do you call that? Once a year? Okay, well, there's a month of your life you got back in order to optimize by a millisecond." -- Christopher Trudeau

"My joke used to be that if you switch to Rust, you're probably going to get VC funding." -- Michael Kennedy

"Now it needs Rust plus AI, but I think that's still true." -- Christopher Trudeau

"So yeah, I think we're officially stretching this analogy and now I'm hungry." -- Christopher Trudeau, on the caramel apple model of Rust and Python

Key Definitions and Terms

  • Rust: A compiled systems programming language that produces native machine code and enforces memory safety at compile time through ownership rules, without a garbage collector. It is now the language behind many of Python's fastest tools and libraries.
  • Ferris and Rustaceans: Ferris is the crab mascot of the Rust language, and Rust programmers call themselves Rustaceans. Michael and Christopher opened the episode by getting the crab jokes out of the way.
  • Ownership: Rust's central rule that every value has exactly one owner at a time. Passing a value around the way you would in Python often transfers or violates ownership, which the compiler reports as an error.
  • Borrow checker: The part of the Rust compiler that enforces ownership and borrowing rules. Learning to read its error messages is a big part of getting productive in the language.
  • Stack: The region of memory where function calls live. Each call gets a stack frame holding its return address and parameters, and the frame is popped when the function returns.
  • Heap: The general-purpose region of memory for longer-lived values and anything shared between functions. In CPython every object lives on the heap, which is why every Python variable is effectively a pointer.
  • Small integer cache: A CPython optimization that pre-allocates the integers from about negative five through 255 so every use of a small literal refers to the same object. Larger integers are created fresh, which is why Christopher can have three copies of 254 but only one copy of two.
  • Sized integer types (i8, i32, i128, f32, f64): Rust numeric types that state their width in bits and whether they are integers or floats. They map directly onto what the CPU handles, which is a large part of why Rust is fast and why you must think about overflow.
  • Signed versus unsigned: Whether a number type reserves half its range for negative values. An unsigned byte holds 0 to 255; a signed byte holds a range split across negative and positive numbers, and Rust makes you choose explicitly.
  • Bytecode: The platform-neutral binary form that Python compiles source into and that the interpreter executes. Christopher likened it to a formula stored in an Excel file that Excel runs.
  • Machine code: Instructions a specific CPU executes directly. Rust compiles to machine code for one platform, producing a binary that runs only on that kind of system.
  • REPL: A read-eval-print loop, the interactive prompt Python developers take for granted. Because Rust must compile, its REPL-like tools work by recompiling a whole program on every line.
  • rustup: The Rust toolchain installer and version manager, comparable to pyenv. It installs and updates rustc and cargo.
  • rustc: The Rust compiler itself. You almost never call it directly, because cargo does that for you.
  • cargo: Rust's build tool and package manager, the closest thing to uv in the Rust world. It creates projects, builds and runs them, and manages crates.
  • Cargo.toml: The project manifest for a Rust project, equivalent to pyproject.toml, where dependencies and the target edition are declared.
  • Crate: A Rust package, the equivalent of a Python wheel. Crates are published to and downloaded from crates.io, the Rust equivalent of PyPI.
  • Edition: Rust's mechanism for grouping compatible language behavior on a roughly three-year cycle, separate from its six-week version releases. The compiler can target older editions so existing code keeps building.
  • Debug versus release build: Cargo's two build profiles. Debug builds carry debugging information and are about 30 percent larger; release builds are what you would distribute.
  • fn: The Rust keyword that declares a function, in place of Python's def. Christopher prefers it because it says exactly what it is.
  • Expression versus statement: In Rust almost everything is an expression that produces a value, including a block of code in braces, which is why the last expression in a function can serve as an implicit return.
  • Implicit return: Rust's convention that a function returns the value of its final expression if it has no trailing semicolon. Neither Michael nor Christopher is a fan.
  • elif: Python's else-if keyword. Rust just uses else if, and Christopher admits he never understood why Python needed a separate keyword.
  • C extension: A Python module implemented in a compiled language and loaded by the interpreter. Python was designed for this from the start, and the same mechanism is what Rust uses.
  • Dynamic library (.so or .dll): A compiled library loaded at runtime. A Rust extension for Python is compiled into one of these with the right entry points so Python can import it.
  • ABI: Application binary interface, the low-level contract for how compiled code calls into Python. PyO3 produces libraries that comply with it.
  • PyO3: The Rust crate providing bindings to Python. It maps Rust types to Python objects and supplies macros that expose Rust functions and classes as Python modules, and it also supports embedding Python in a Rust program.
  • Macro: A Rust mechanism that changes how code is compiled. PyO3 uses macros that you attach to a function to generate the Python-facing wrapper.
  • maturin: The tool that builds a PyO3 project into a Python package, installs it into a virtual environment for development, and produces wheels for distribution.
  • Wheel: Python's built-package format. A universal wheel contains only Python; a platform-specific wheel contains compiled code for one operating system and architecture, which is why Polars installs two of them.
  • Amdahl's Law: The rule that speeding up one part of a program is limited by how much of the total time that part takes. If a section is 20 percent of the runtime, even making it infinitely fast yields at most a 20 percent gain.
  • Sampling profiler: A profiler that periodically samples what a running program is doing rather than instrumenting every call. Python 3.15 adds one in the standard library that can attach to a live process, which Michael plans to cover on an upcoming episode.
  • Linter: A tool that checks code for errors and style problems without running it. Ruff is the Rust-built linter that made Michael a believer.
  • Drop-in replacement: A library with the same interface as an existing one, so you can swap it in without changing code. The awesome-python-rs list includes Rust-backed drop-ins for cryptography and JSON parsing.
  • Awesome list: A community-curated GitHub repository that collects notable projects on a topic. awesome-python-rs collects Python tools and libraries built on Rust.
  • Supply chain security: The risk that a dependency you install carries malicious or compromised code. Christopher's caution about unfamiliar crates is a response to this.
  • Hungarian notation: An old naming convention that encodes a variable's type in its name with prefixes. Michael was relieved the older parts of Python's standard library at least avoided it.
  • pyenv: A tool for installing and switching between Python versions, the closest analogy to rustup.
  • uv: Astral's fast Python package and project manager, written in Rust and openly inspired by cargo.

Learning Resources

If this episode made you want to actually write some Rust, or to understand the memory model that Rust makes explicit and Python hides, here are places to go deeper. The courses are the most direct fit for the topics discussed, and the documentation links are the ones Christopher and Michael pointed to on the show.

  • Up and Running with Rust: Christopher's course, and the one that inspired this episode. It takes you from zero Rust through the stack, heap, ownership, and enums, then builds a real compiled extension you can import from Python using PyO3 and maturin, teaching everything by comparison to the Python you already know.
  • Python Memory Management and Tips: Michael's course on how CPython actually manages memory, from reference counting and garbage collection to the allocation details behind the "everything is a pointer" discussion. It is the Python side of the comparison Christopher draws with Rust.
  • Polars for Power Users: Polars came up repeatedly as the model Rust-backed Python library. This course teaches the DataFrame library itself, from lazy evaluation to joins and file handling, so you can see what the Rust core buys you in practice.
  • The Rust Programming Language: The official Rust book, hosted on rust-lang.org, which Christopher called easy to follow and full of good examples. The ownership chapter covers the material at the heart of this episode.
  • Rust by Example: Runnable examples for each language feature, a good companion when you want to see the syntax comparisons from the episode in code.
  • Rust installation: The install page with the rustup shell command that gets you rustc and cargo.
  • The Rust Edition Guide: The official explanation of the edition system Christopher wishes Python had.
  • PyO3 user guide: Documentation for the crate that maps Rust to Python objects and exposes Rust functions as Python modules.
  • maturin: Documentation for the tool that builds PyO3 projects into installable Python packages and wheels.
  • awesome-python-rs: The curated list of Python tools and libraries with Rust under the hood that Christopher recommended for finding real-world code to read.
  • Extending Python with C or C++: The official documentation for the extension mechanism that Rust reuses through PyO3.
  • PEP 799: The proposal behind Python 3.15's new profiling package and sampling profiler that Michael mentioned.

Overall Takeaway

Rust is no longer a language Python developers can ignore, not because you need to write it, but because it is already underneath the tools you run and the libraries you import every day. Christopher's three modes make the landscape legible: tools like ruff that happen to be Rust, libraries like Pydantic and Polars that Python imports through the same door C extensions have always used, and servers like Granian that run Python from inside a Rust process. Once you see that structure, the surprising speed of modern Python tooling stops looking like magic and starts looking like a design choice you can make yourself.

The encouraging news is how much carries over. The syntax reads like typed Python, cargo behaves like uv, Cargo.toml is a pyproject.toml, and crates.io is PyPI. What is genuinely new is the part Python hides: hardware-sized integers, the stack and the heap, and a compiler that insists on knowing who owns every value and rewards you with a category of bugs you can never write. Learning that model pays off even if you never ship a line of Rust, as Bob Belderbos found when it made him a better Python developer. And when you do reach for Rust, take Christopher's advice: do not, and then measure. Check whether someone on the awesome-python-rs list already solved your problem, hand Rust big chunks of work rather than chatty calls, and let a profiler, not intuition, tell you which 20 lines matter.

Up and Running with Rust course: training.talkpython.fm

Rust: rust-lang.org
pydantic: pydantic.dev
ruff: docs.astral.sh
granian: github.com
By example: doc.rust-lang.org
rust-lang.org: rust-lang.org
rustup.rs: rustup.rs
crates.io: crates.io
main.rs: main.rs
PyO3: github.com
https://github.com/ritwiktiwari/awesome-python-rs: github.com
ty: docs.astral.sh
pyrefly: pyrefly.org
uv: github.com
polars: pola.rs

Watch this episode on YouTube: youtube.com
Episode #563 deep-dive: talkpython.fm/563
Episode transcripts: talkpython.fm

Theme Song: Developer Rap
🥁 Served in a Flask 🎸: talkpython.fm/flasksong

---== Don't be a stranger ==---
YouTube: youtube.com/@talkpython

Bluesky: @talkpython.fm
Mastodon: @talkpython@fosstodon.org
X.com: @talkpython

Michael on Bluesky: @mkennedy.codes
Michael on Mastodon: @mkennedy@fosstodon.org
Michael on X.com: @mkennedy

Episode Transcript

Collapse transcript

00:00 Lent the entire CPython code base from scratch.

00:02 It takes 0.3 seconds, three blinks of an eye.

00:06 That is rough, and it's written in Rust.

00:09 So are Pydantic, Polars, uv, and Granian.

00:12 Rust shows up in Python in three ways.

00:15 Tools that happen to be written in Rust, libraries Python itself imports and runs, and servers that themselves run Python inside of Rust.

00:24 This episode is Rust for Python developers.

00:27 And Christopher Trudeau is back on Talk Python to discuss Rust and his latest course up and running with Rust.

00:34 The core rule is that only one thing can own a value or variable at a time.

00:39 Pass it around freely in Python and the garbage collector cleans it up.

00:43 Do that in Rust and you get a compiler error.

00:46 This is Talk Python To Me, episode 563, recorded Wednesday, September 9th, 2026.

01:10 Welcome to Talk Python To Me, the number one Python podcast for developers and data scientists.

01:15 This is your host, Michael Kennedy. I'm a PSF fellow who's been coding for over 25 years.

01:21 Let's connect on social media.

01:22 You'll find me and Talk Python on Mastodon, Bluesky, and X.

01:25 The social links are all in your show notes.

01:28 You can find over 10 years of past episodes at talkpython.fm.

01:32 And if you want to be part of the show, you can join our recording live streams.

01:35 That's right.

01:36 We live stream the raw uncut version of each episode on YouTube.

01:40 Just visit talkpython.fm/youtube to see the schedule of upcoming events.

01:45 Be sure to subscribe there and press the bell so you'll get notified anytime we're recording.

01:49 This episode is brought to you by Sentry.

01:51 You know Sentry for the error monitoring, but they now have logs too.

01:54 And with Sentry, your logs become way more usable, interleaving into your error reports to enhance debugging and understanding.

02:02 Get started today at talkpython.fm/sentry.

02:06 And it's brought to you by the Talk Python in Production Book, an inside look at 10 years of the real-world DevOps behind the Talk Python sites and apps.

02:14 Check it out at talkpython.fm/DevOpsBook.

02:19 Christopher, welcome back to Talk Python To Me. Always nice to hang out with you.

02:23 Yeah, thanks for having me back.

02:24 I feel it's going to be a little old-fashioned, a little rusty.

02:30 Yes, let's just start with the crap jokes and get them out of the way, yes.

02:34 Yeah, oh yeah, this might not actually be the final Ferris joke or whatever, but no, we're going to talk about Rust for Python devs, specifically not for Rust experts,

02:47 But I want to know enough Rust so that things like Pydantic, ty, if I ended up poking around them or some other extension, it would make sense, right?

02:57 Or maybe write a little bit of Rust to speed up some of your Python code.

03:00 It's obviously the most influential way to make Python extensions or core faster pieces, right?

03:07 It seems to be the new way of doing things.

03:09 And in fact, I saw something in the news this morning that one of the major CPU providers is switching to Rust for a lot of their device drivers and things like that.

03:20 It does seem to be having its day.

03:22 Yeah, absolutely.

03:23 My joke used to be that if you switch to Rust, you're probably going to get VC funding.

03:28 That was like three or four years ago.

03:30 You know, that was when Astral and Pydantic and all that stuff happened.

03:34 Now it needs Rust plus AI, but I think that's still true.

03:38 So, yeah.

03:38 Exactly.

03:39 Now it's AI is the cornerstone, but if you could do Rust and AI, we.

03:44 Why not?

03:45 Yep.

03:45 Why not?

03:46 Just bring them all in.

03:47 No, it's a really cool foundation for Python things.

03:51 So we're going to talk about that and dive into it, compare it to Python, give some examples, give some tools, all those things.

03:57 But it's been a while since you've been on.

03:59 Give everyone a quick introduction of who you are and what you've been up to.

04:03 So yeah, I'm a consultant.

04:05 I mostly spend time working with teams either on architecture or technical processes.

04:12 That tends to mean things like agile and lean and automation, CI/CD, all that kind of good stuff.

04:17 And in my spare time, I still do a fair bit of teaching.

04:21 And sometimes that's in person, sometimes that's virtual, and sometimes that's creating online courses for people.

04:28 I spend a fair amount of my time in the Python space.

04:30 I'm co-host of the Real Python podcast.

04:33 So that tends to be where people, if they know my voice, that's from where.

04:36 And lately I've been getting into Rust and figured you and I could chat about that.

04:42 A lot of really cool things you're doing.

04:44 I guess let's talk about getting into Rust.

04:48 First of all, what was your background?

04:51 Did you do C++, C, other compiled languages?

04:55 Because it's a shift, right?

04:57 Well, so this is it, right?

04:59 You hear the rust is a hard language to grasp thing.

05:03 And I don't, I didn't find it that way, but I don't want to diminish people who are saying that, right?

05:08 Like this isn't because I'm so much smarter or anything along those lines.

05:12 It's because I have that background.

05:14 I was writing C when I was 13 or 14 years old.

05:19 There weren't a lot of choices when I started out.

05:22 So I have a grounding and, you know, I wrote device drivers and I wrote embedded systems uh don't haven't done it in a long time but i have that grounding that rust kind of expects you to

05:34 have and it's closer to the machine there's less virtualization going on uh it's a lower level language than something like python uh in fact uh bob builder russ and i were talking about this

05:47 because he's got into rust recently and he came from php and python so from that it's this whole other kind of experience and he was talking about the fact that he actually thinks it's made him a better Python developer because now he's thinking about memory and stuff like that a little more

06:02 than you necessarily would if you've just come from Python. That's really interesting. I hadn't really thought about it because you and I are, I think, around basically the same age, at least

06:13 technologically speaking. And I remember getting the C++ Primer Plus. This is so nice. C++.

06:22 It's so much better.

06:23 Yes.

06:24 I just loved working in C++ and so on.

06:28 So I've never known a world where I came to Python or JavaScript or other languages where I didn't already have that experience of, you know, void star star.

06:39 What do I do with that?

06:40 Exactly.

06:40 These kinds of things.

06:42 But, of course, that makes sense.

06:43 You come from Python and PHP, and then you're like, whoa, why am I doing all this stuff?

06:47 This is crazy.

06:48 Yeah.

06:49 And it's, you know, a big part of it.

06:51 And I think the thing that folks who are coming to it from languages like Python find difficult is that whole memory management thing.

06:58 And Python basically takes care of that for you.

07:00 And so if you've never had to do that before, all of a sudden it's like, I have to do what?

07:05 And why do I have to do that?

07:07 And it can get a little persnickety.

07:11 It's concept of only one thing can own a value at a time.

07:17 it has objects, but the objects belong to somebody. And in Python, you just pass those things around willy nilly and you don't worry about it. And the garbage collector takes care of it.

07:25 And that often turns into a compile error in Rust. And that's on one hand, it's the beauty because it makes sure that certain kinds of bugs don't happen. On the other hand, if you're not used to

07:35 it, you know, there's a, there's a joke in the Rust world that there are no bugs. It's, it's all your time isn't debugging. All your time is getting it to compile. And that's because there's a lot of that, Oh, I'm just going to pass this around and wait, I can't.

07:48 And so, yeah, that there's a lot of upfront work there.

07:51 And I think for a new developer, that could be very frustrating because, you know, you don't, you can't play as easily.

07:59 There's the threshold to getting started with something is higher because you're constantly kind of fighting the compiler.

08:05 The flip side of it is their compile messages are absolutely fantastic.

08:09 They, so when errors happen, they're very, very explicit.

08:13 they often include something like maybe you need to do this.

08:17 And from what I saw, they were right 80 or 90% of the time.

08:22 So once you figure out the language, I mean like the, not the language of Rust, but the vocabulary they use for error messages, it's very much, oh, oh, okay.

08:32 So that's kicking off the borrow checker.

08:33 Now I understand that.

08:34 Okay.

08:34 I'll go fix it.

08:36 So there's a few things you kind of have to learn to get to that, but it is fairly helpful.

08:40 But again, that could just be my background and remembering days of C where the compile error was being triggered from three lines before it was actually talking about where the error was.

08:51 And you kind of had to zone in around roughly where it was reporting it to figure out what had gone wrong.

08:57 So, yeah, there's been some advances in technology since we were tapping out bits and bytes on rocks.

09:03 Yes.

09:04 Exactly.

09:05 Making sand think.

09:07 So I would like to just acknowledge it.

09:09 Six minutes, 57 seconds into the recording.

09:11 Borrow Checker.

09:12 Yeah.

09:13 Borrow Checker's been shouted out.

09:15 Yes.

09:16 Yeah.

09:18 Maybe we should just do the quick version of that.

09:21 We'll probably dig into it a little bit more.

09:22 Before you do, I just want to wax poetic.

09:25 Think back to the days of back in the 90s.

09:29 I remember when I had my C++ Primer Plus book.

09:33 And yes, folks, it was a book that was like the yellow pages.

09:36 There was no, literally the internet did not exist.

09:39 Well, the internet existed.

09:40 There was Gopher, there was Telnet, but the World Wide Web did not exist at this time, like not for four or five more years.

09:46 Anyway, I remember thinking, oh my gosh, this is so hard.

09:50 This is so much work when I'm learning it.

09:51 And finally, finally I got it to compile.

09:54 Like, oh, we're good at compiles.

09:56 Like, no, no, no, no.

09:59 That's just when the actual real hard debugging, problem solving starts.

10:03 But you mentioned that with Rust, that the compiler checks are a little bit stronger.

10:08 They check more things like proper memory management and variable sharing and things like that.

10:13 So I think while it was a eye-opener that compiling was only the beginning of my suffering when I was learning programming, I think compiling does mean more in Rust than it used to in other languages.

10:25 Yeah, there's a whole family of bugs that have to do with memory management.

10:30 And what's worse is they tend to be a tricky set of bugs.

10:33 They're the kinds of things that will crash sometimes.

10:38 So if you go back to C and how it stores a piece of text in memory, it has the, you know, like, let's say we're storing the word Talk Python.

10:48 Well, we take the bytes for Talk Python and then we put a null on the end of it.

10:53 And the compiler, when the code is working with it, it looks for that null.

10:56 And that's how it knows that the string is finished.

10:59 Well, if you accidentally write something longer than that, there'll be no null and it'll keep walking past that into the next chunk of memory.

11:07 If you free the memory up, but you still have a pointer that points into that memory.

11:11 Yep.

11:12 But your computer will happily read that.

11:15 And if you've got two strings in a row, what'll happen is you'll get the first string and then the lack of the null, and then you'll get the next string.

11:23 And you might get a wrong message on the screen, but it won't crash your program.

11:26 But if you get a string and then some memory that is a little more tricky, then all of a sudden you might actually be doing something like causing your program to fall over.

11:35 So rust isn't bug free, but there is a category of bugs that it just doesn't let you create.

11:43 And that makes it harder to compile, but a beauty to work with in the fact that a lot of the things that you might struggle with that are harder to debug are gone.

11:54 Right.

11:54 You know, I thought the nature of Python is the looseness of the type system and the dynamicism of it means you can get moving very, very quickly.

12:05 But if you're not using a type checker, type mismatches are things you discover at runtime.

12:11 All of that is very strict and very well managed in Rust.

12:15 And so those kinds of problems just don't exist.

12:19 That's awesome.

12:20 It also takes it's also mind bending.

12:23 It is.

12:23 In some ways, right?

12:24 It's the way you think the way a lot of the ways you think about solving problems in C++ or C or Python can be kind of the same in Rust. Some of these limitations sort of change the algorithms

12:38 and the data structures that will work in those worlds. Yeah. Yep. Well, and, you know, take

12:42 something as simple as an integer in Python. They're boundless, right? And if you're doing certain kinds of math, that's fantastic. There's no upper limit. Python takes care of all of that for you. It figures it out. I actually saw an article a couple of weeks ago where somebody was

12:56 building a SIMD machine based on integer, based on, doing bitwise operations on massive integers, right? Thousand byte integers, and you can get away with this. And Python just happily

13:08 goes, yeah, that's a really big integer. No problem. Rust is closer to the machine. So it tends to use integers the way your CPU uses integers. So you have to be aware if you're using an eight bit integer that you can't put nine bits in it.

13:22 Things go wrong.

13:23 Now the compiler, most of the time can catch that depends on how you're getting into that situation.

13:28 And so it, it stops you from doing those things.

13:31 But of course now you have to be conscious of it, right?

13:33 You're making a decision when you're designing your program.

13:36 How many bits am I going to store this in?

13:38 And most of the time that's not a problem, but sometimes that might mean you're hitting boundaries that you wouldn't otherwise expect to hit.

13:45 Yeah.

13:45 And even weird things like it's signed or unsigned.

13:48 Like now you can have negative numbers, not even negative one, not allowed.

13:51 Yeah.

13:51 That means 2.17, two, two, five billion.

13:55 And interesting, like a lot of that stuff is in Python, but it's buried further down.

14:01 So you can get at some of those same concepts inside of Python, but if you're just starting out, you don't go digging for those things.

14:08 Right?

14:08 So if you're, you know, if you're playing with the network and you're trying to pack bytes together, Python has signed and unsigned and it has those sides pieces. And all of that is very, very important if you're constructing the perfect

14:21 packet. But if you're just trying to do math on the command line, well, you don't need to think about that kind of thing. Rust doesn't give you the choice. And that's not Rust specific. That's most compiled languages. They don't give you the choice, right? And it's also where the speed comes

14:35 from, right? So that beauty of Python's limitless integer means there has to be machinery inside of that to handle when you make it bigger than what the current chunk of memory is.

14:47 And rust doesn't have that machinery.

14:49 It just says, okay, I'll crash.

14:51 and so it's, it's a trade-off, right?

14:53 So you don't have to care for as much, but one of the reasons Python is slower is because there's the overhead that handles these kinds of things.

15:00 So one of the reasons, you know, the flip side works as well.

15:03 One of the reasons rust is faster is because it's optimizing for exactly what your CPU does.

15:10 And that less overhead means your code runs faster.

15:12 Right.

15:13 You're never going to get a Python integer into a CPU register.

15:17 Right.

15:18 Like it's just, I don't know.

15:20 Maybe.

15:21 I remember when I came to Python, I did C++ and C#, all languages that care about the shape and size of these variables, numbers, and for 15 years.

15:31 And I came to Python, I'm like, I got to be doing something wrong.

15:34 How do I tell it again how big the number is?

15:38 Because what kind, like, is it just, is it a 64 bit?

15:41 I couldn't figure out like, what is, how do I, it's going to be a problem.

15:44 And then I'm like, wait, it just grows.

15:46 That's crazy.

15:46 Yeah.

15:47 Well, I think I started with Python more as a scripting glue kind of thing.

15:51 And most shell languages don't have, like Python, just don't care about those things.

15:56 Right.

15:57 And so when you're using it loosely to glue other things together, I don't think that really kind of ever crossed my mind.

16:02 And I think I got used to the idea by that time I was doing, you know, web servers and things that were bigger, more interesting projects. And I think a lot of this is where are you coming from and how are you using the tool, right? So I think for the first couple of years I was doing

16:14 Python, I was writing, you know, at max 50 or a hundred line scripts to solve some immediate little problem. And it's nice not to have to worry about that kind of thing, right? So all of this really is, you know, what is the tool and how are you using it for what you're trying to accomplish?

16:29 Yeah. And I was coming from scientific programming, like building UIs and other type of tools for scientist type of thing.

16:38 We care about the size of this number because science.

16:41 That's all what your background is.

16:43 This portion of Talk Python To Me is brought to you by Sentry.

16:46 You know Sentry for their great error monitoring.

16:49 But let's talk about logs.

16:50 Logs are messy.

16:52 Trying to grep through them and line them up with traces and dashboards just to understand one issue isn't easy.

16:58 Did you know that Sentry has logs too?

17:00 And your logs just became way more usable.

17:03 Sentry's logs are trace-connected and structured, so you can follow the request flow and filter by what matters.

17:09 And because Sentry surfaces the context right where you're debugging, the trace, relevant logs, the error, and even the session replay all land in one timeline.

17:18 No timestamp matching, no tool hopping.

17:21 From front-end to mobile to back-end, whatever you're debugging, Sentry gives you the context you need so you can fix the problem and move on.

17:27 More than 4.5 million developers use Sentry, including teams at Anthropic and Disney+.

17:33 Get started with Sentry logs and error monitoring today at talkpython.fm/sentry.

17:38 Be sure to use our code, Talk Python26.

17:41 The link is in your podcast player's show notes.

17:43 Thank you to Sentry for supporting the show.

17:46 I do, before we get too much farther jumping into it, I do want to point out that you wrote the Up and Running with Rust course over at Talk Python.

17:53 So thank you for that.

17:54 I really enjoy this course.

17:56 It's both very educational and funny.

17:59 I try.

18:00 Thank you for that.

18:00 The beauty of doing this kind of stuff with a sense of humor is you don't actually have to be a comedian.

18:05 It's not like everything is a joke, but you can stick some humor in once in a while.

18:10 So I do wonder occasionally whether, again, because of the similar generation, half the jokes might have been aimed specifically at you.

18:17 So just because you find it funny doesn't mean other people will.

18:21 I think they will. At least the lightheartedness.

18:23 We'll see what happens.

18:26 We'll come back to that at the end.

18:28 This is kind of not exactly the same.

18:29 It's not just that we're going to turn the course in the podcast, but it's inspired some of our concepts.

18:34 Now, I want to start by talking about Rust.

18:39 Just some examples before we dive into how is it compared to Python.

18:44 We've touched on a little bit of that, but there's a bunch of differences and so on.

18:48 But let's just appreciate some of the things like Pydantic, Ruff.

18:53 Give me your thoughts on the last five years of these tools.

18:56 have kind of supplanted a lot of things that were very well established in Python.

19:01 So there's, there's, there's kind of three ways that Rust intersects with the Python world.

19:06 And one has almost nothing to do with Python.

19:10 It's they've used Rust to build tools that are Python tools.

19:15 The, they could have just as easily done that for any other language, right?

19:19 So when you talk about things like the linters and those kinds of things, they're, they're useful because they're fast.

19:26 they are not, they're not really integrating with Python.

19:30 They're a third party tool that you're using to make your Python better.

19:33 And I think so some of the, some of the popularity in that has come out of the fact that a lot of the tools we've been using historically in the Python world have been written in Python.

19:43 And so they've been very slow.

19:45 And most of the time that doesn't matter.

19:48 You know, there's that, you know, that programming world of, oh, I'll just go get another cup of coffee and it'll be done when it comes back.

19:55 But your world shifts when you start seeing, you know, orders of magnitude, right?

20:02 Like 10% faster, you're not going to notice it when you're starting to talk multiple zeros times faster, this changes things.

20:10 And I think there were a couple of key libraries that started doing this and everyone kind of went, oh, wait a second.

20:16 There's some, there's some value to this.

20:17 And so I think there's been this real spring up of things written in Rust that make Python development easier.

20:24 Yeah, I think the one that was most stark to me was Ruff because it was just unreasonably fast.

20:33 Yes.

20:34 I remember running on the Talk Python training, all the courses, like that app.

20:39 And that app is much bigger than people think from the outside.

20:41 It's 170,000 lines of Python or something, which is not huge, but it's not a toy, right?

20:47 And so I remember running Ruff on it and it goes, found these four hours.

20:50 I'm like, yeah, no, you didn't.

20:52 Wait, wait.

20:54 Did I not tell it to like go into the subject?

20:58 It's like, did you stop after you found four errors?

21:00 I don't understand.

21:01 How can you be finished?

21:02 How can you be finished?

21:03 You like literally parse the entire thing for a hundred rules.

21:07 And it was like, enter answer.

21:09 I'm like, what?

21:10 I just don't understand.

21:11 Yeah.

21:12 Yeah.

21:12 And then there's something different here, you know?

21:17 Yep.

21:17 I also, I tend to be fairly slow to upgrade my machines.

21:21 So I'm often a couple of generations out processor wise, and it's just that much more, right?

21:27 Because like when you're, when you're operating on a slow machine to begin with, and then you're trying to do something like lint a couple hundred thousand lines of code.

21:34 Yeah.

21:35 It makes a huge difference.

21:36 It makes a huge difference.

21:37 It does.

21:37 So one of the categories is rough, which is really tooling.

21:39 And you can kind of forget that it's rust.

21:41 Like it just doesn't even really, it might as well have been written in some.

21:45 It could have been.

21:46 Yeah.

21:46 And I think that's kind of the key to this category, right?

21:49 whether it's written in rust or C or anything else is kind of indifferent.

21:53 It's, it's a tool.

21:55 they, they're particularly with things like linters, you know, the, the, description of the Python language is publicly available.

22:03 There are tools out there for compiling, for compiling language parsers.

22:09 So like you can, you could have taken something, else and use that to take the definition of Python and built a thing that parses Python in any other language. It's just that Rust seems to be, has, has become the thing that is now the way to

22:23 do some of this stuff. Yeah, absolutely. And just give like other numbers, you know, instead of my own personal example that people can't exactly relate to for parsing for linting and pars,

22:33 evaluating this, the entire CPython code base from scratch is a 0.3 seconds. Yeah. That's, that's like enter the three blinks of an eye. Yeah. You know, that's pretty ridiculous. Yeah.

22:45 So that's one category.

22:46 The other category is closer to our hearts with things like Pydantic and so on.

22:51 So like I said, there's kind of three modes.

22:53 The second mode, and I think it's the most common one, is because Py...

22:58 And this isn't really...

22:59 Again, this is one of those things that's not quite Rust-specific.

23:02 Python was designed from the get-go to integrate well with lower-level languages.

23:10 And in fact, there's a good chunk of the Python standard library, which is really just a thin wrapper on top of the C standard library.

23:18 And in fact, the older stuff in the standard library, you can actually see it.

23:21 It's a little creaky in some of the naming and stuff before they kind of got consistent about how to name things.

23:26 And you look at it and if you're a C programmer, you're just like, oh, I know exactly what that is.

23:29 At least they don't use Hungarian notation.

23:32 There is that.

23:33 There is that.

23:34 S, Z.

23:35 What is going on here?

23:37 So Python has been designed to be able to do this.

23:41 And it just turns out that I think a lot of people are coding in rust have found it easier to code than encoding in c that same interface that c

23:50 extensions can use can be used by rust and so as a result libraries like pydantic libraries like polars they have written their library in rust and then with a very very thin veneer there doesn't

24:04 take it doesn't take a lot of effort to expose that up and then python inside of python you can treat that like any other python module so you don't actually have to be conscious of how they

24:14 And as a result of this, you end up with a lot of speed up because you use that same speed that you were talking about with rough.

24:21 But now Python, which tends to be a slower language, can now access this kind of stuff.

24:26 So something like Polars or Pydantic, where you're doing a lot of crunching and you want them to be fast and performative, this marriage between the dynamic library on the hard drive that is a compiled thing as a Python module,

24:41 that integration has been very, very handy.

24:45 And I think this is the place where Rust is starting to shine because it's a cleaner, although it can be a little frustrating, it's a cleaner language than C.

24:59 There's a learning curve, but there are a lot of things it doesn't let you do.

25:02 There's fewer foot guns.

25:04 And as a result, it's a nice marriage between a low-level language and some higher-level concepts, right?

25:09 So it has things like iterators and collections in it.

25:12 And so if you're coming from Python, that's like, oh, how do I deal with that?

25:15 Oh, it's the same kind of for in loop and it's the exact same thing, right?

25:18 So there's enough similarity to more modern languages that this is becoming a nice sort of collection of pieces that worked well together.

25:27 And in the cases of things that need to be really fast, this is a real answer.

25:31 Yeah, absolutely it is.

25:33 And taking your Rust code and exposing it as a Python package with the tools like Pyotr3 maturing that we're going to talk about obviously they they make it super easy it comes down to just

25:44 okay well you need to build more variants of your wheels rather than just a source only one yeah i think i have an analogy for these types of things so we have one third uh category i guess which i

25:54 would put as granian and other things which is a web application server that runs that is built and runs in rust but then your code and python still runs so i have i have an analogy chris tell me what

26:05 think here we've got the caramel dipped apple where it's caramel is python okay so we've got the caramel dipped apple where python is on the outside with like a rusty core

26:17 yep that would be pydantic we have maybe python maybe it's the way anyway we've got Granian and other things where it's like more like a caramel m&m on the outside it's like a

26:30 hard shell of rust and then the side it's like some sort of crunchy nugget on the outside and

26:34 the caramel's inside yeah the protective hard outside is the rust which is granian and those types of things and then we've got the tools which i'm thinking of is just like a solid piece of caramel but that's maybe a little bit backwards i i would go with the tools are like when

26:49 you've got a slices of apples and a bowl of caramel that you can dip it in so it's a separate thing but you can mix and match so yeah i think we're stretching we're officially stretching this

26:59 analogy and now i'm hungry but i know i know we were stretching but with your your slices of apple You've, you've perfected it.

27:05 Okay.

27:06 So yeah, so that third category is within rust code, you can embed the Python interpreter.

27:11 And so from a rust, program, you can now use an access Python.

27:18 So you can kind of use Python as a scripting or, or configuration language within a larger, mechanism and something like granian where you want to actually run Python code for a web framework, that, you know, so that,

27:32 that inverts the relationship we were talking about before. So yeah, so that's our three, right? So it's separate tools, the using Rust as a module inside of Python. And then the third one

27:43 is using Python as a compiled library, using the interpreter as a compiled library inside of the

27:51 Rust object itself. Yeah, I think that sums it up pretty well. Let's talk differences. I think kind of language differences, you know, syntax differences. It feels pretty familiar, honestly.

28:03 Yeah. And I was about to say, you know, to start with differences, it might actually be easier to start with what's not different. The language itself, there are some things, obviously, if you've never, if you've never seen it before, it takes a little, and that's the same with any language,

28:17 but it's not going to be completely out of nowhere. If, if I hand a Python developer some fairly clean Rust, you're probably going to have an idea of what it's doing. The loop mechanisms are the same.

28:27 The if else is similar. There's no L if you actually use if else. I always scratched my head

28:33 with L if in Python. I never understood it. Why you need a new keyword. It's such a verbose language.

28:37 And then it's like, well, no, this we're going to. Yes. Yeah. Why that one? I have a sneaking

28:42 suspicion. It might've made something early in the early days easier to parse, but rather than parsing two keywords, it gives you a keyword. A lot of the built-in mechanisms, like it's got

28:52 tuples and arrays, it's got iterables and collections. So a lot of the declaration looks like typed Python. So because it is a strictly typed language and you have to specify what everything is, you do have things like the arrow that this function returns something of this

29:07 type, right? So you've got that little arrow designator. But if you're used to coding in typed python which i'm not uh then you uh then then it's readable from that perspective it is yeah

29:19 the types are quite quite similar uh as they you know um for the way you define them right if you have like a function or something then you just say like arrow goes to i always read that as goes

29:31 to pool if it like returns a pool the variables are variable name colon type right yeah yeah and

29:38 And I suspect that's probably because Python type libraries was inspired by some of this stuff.

29:43 I think it probably flowed the other direction, but I'm not sure about that.

29:47 So yeah, it's a lot of mixing in this, in the later, the things that got created later and typed later, like TypeScript is similar.

29:55 Yes.

29:56 Python types are similar.

29:58 Swift is similar.

29:59 I think it's the same that everybody stole from C, you know, C is the granddaddy of most of the languages we use.

30:05 And then I think people started adding these kinds of concepts to it.

30:08 And it's like, well, if you've come from that other language, this makes it simple.

30:12 So yeah, there seems to be a sort of family of how this stuff works now.

30:17 Yeah.

30:17 And someone decided all the types go after.

30:19 Yes.

30:20 Right.

30:20 And see, you would say like int function.

30:23 Yeah.

30:23 That, that, that has taken me a little bit to get used to.

30:26 Yes.

30:27 I presume it me it's meant to be making it more readable and you see the essence, like the function name and the variable names, and then the stuff describes it after.

30:37 But yeah, it's always caught me off guard.

30:38 I'm guessing it's because it's optional.

30:40 It's optional in Python, but it's not optional in Rust.

30:44 True.

30:44 Or Swift, right?

30:45 Yeah, true.

30:46 And I'm pretty sure that Swift was inspired by, like much of Swift was inspired by Python as well.

30:53 Swift's an interesting thing to look at as well, like the Playgrounds, the REPL, a lot of the stuff there.

31:00 But okay, let's keep going.

31:01 Some more similarities, all right?

31:03 No, I think we've hit the limit of the similarities.

31:08 So it doesn't take long.

31:10 It's relatively readable in the same fashion, but it doesn't take long before you have to kind of peel the top layer of that onion and then you're going to get into your differences.

31:19 At the heart of it, one of the fundamental concepts is it is a compiled language.

31:24 This is one of those things that I think I always find sometimes frustrates students because you end up with the, well, Python compiles.

31:31 I can see the code right there.

31:33 Python is a interpreted language that interprets a binary file.

31:39 So when Python is compiling, it's creating a binary target.

31:42 That binary target is not platform specific.

31:46 It is just a, you can think of it as a data file the same way, like Excel is a data file, right?

31:50 So when you, when you write a formula in Excel, you don't think of that.

31:53 It's not quite compiling that formula.

31:56 It's storing it in binary.

31:57 And then Excel is running that formula.

31:59 By contrast, Rust actually compiles to machine code for your platform.

32:04 So when I come, unlike a collection of Python bytecode, I can hand you that.

32:10 And I don't have to worry about what platform you're running on because your interpreter is specific for you.

32:14 The bytecode is not.

32:16 If I hand you my binary, if you're on the same kind of platform I am, it'll run.

32:20 But if you're not, it won't.

32:21 And so what Rust is actually doing there is creating a binary, tight binary file that is specific to your platform.

32:28 And you know what?

32:28 I'm jealous.

32:29 I'm jealous from a Rust and Python perspective.

32:32 You can compile it and hear, hey, I'll give you a file.

32:36 You can run it.

32:38 You know what I mean?

32:39 Yes.

32:40 I know there's a lot of reasons and it's not easy, but wow, would I love a Python --build thing and outcomes just, I don't care what's in the inner core, right?

32:53 You know, back to the like caramel M&Ms, but just a thing that I could put on a server, I could give to a person, I could put in Docker, and it doesn't have to have a bunch of other stuff there to make it possible.

33:04 Yeah, it's a pros and cons thing, right?

33:06 So your distribution is way easier, but it's very specific distribution, right?

33:10 So you end up, if you're trying to aim at multiple platforms, you have to compile across all of those platforms, but the distribution of it is basically, here's the execution file, go nuts, and that's it, you're done.

33:22 Or the collection of them, if you've got dynamically loading libraries.

33:25 So that is definitely easier.

33:26 the flip side of it is things like repls aren't technically possible because it needs to compile stuff and in fact there's some hacks out there that are kind of hilarious that are essentially

33:37 repl like things that are in the background are basically recompiling a program every single time you enter a line in the repl exactly so it's actually somewhere in there yeah it's actually

33:49 maintaining this program for you in order to make it look repl like and as fast as rust is i found painful i played with it once in a while and i sort of gave up and just went back to i'll have

34:01 my foo.rs file and i'll do it that way so yeah i could just see the background that there's like there's a fn main curly you know brace brace curly exactly and every line of rubble is jammed and

34:13 then there's a cargo build cargo run yeah that's exactly what it's doing that's exactly what it's

34:18 doing this portion of talk python in me is brought to you by us i'm excited to talk about my first solo book, Talk Python in Production. It's an inside look at how we host all the Talk Python

34:29 sites, APIs, mobile apps, and way more. Here's the thing. I believe most hosting stories sold to developers and data scientists are way overcomplicated and overpriced. You've heard me say you're not Google, you're not Netflix, so you shouldn't run your infrastructure the way they

34:44 do. But if not that, then what? This book is both a blueprint for what I chose for Talk Python and a story arc of 10 years of running my own infrastructure from a complete newbie,

34:56 apprehensive to Linux, to some pretty neat infrastructures code DevOps. It covers Docker, Nginx, Let's Encrypt, self-hosted analytics and monitoring, CDN setup, framework migrations,

35:06 and a whole philosophy that I've termed stack native, keeping things streamlined, powerful, and free of cloud lock-in. And it's more than just your standard tech book. It comes with

35:16 code and figure galleries on GitHub, a discussion forum, and something unique, over an hour of audio readers briefs, short conversations that bookend each chapter to prime your focus or broaden your

35:28 takeaways. Oh, and 0% of this book was written by AI. Every word is mine, written over the course in high months, for better or worse. I've made the first third of the book available for free online.

35:40 After that, you can grab the DRM-free EPUB and Kindle editions, and I'm working on a paperback edition as well. Please check it out at talkpython.fm/devops, or just click book in the

35:50 nav bar on the website. It's a great way to support the podcast, and I hope it changes a bit how you

35:55 think about running your apps in production. Okay, and so I guess, and that kind of, and we were already sort of talking about this, but this leads us to this idea of the strict typing mechanism,

36:05 and that really comes out of this idea of the hardware, right? So your CPU has an idea of what an integer is. Your CPU has an idea of what a float is. There are different sized integers. How much memory is that integer going to be stored in? How much memory is that float going to be stored

36:20 in? So not only is Rust specific about having these things, and you have to declare them when you're using them, but it also has that mapping to what your hardware does. So you have to make

36:32 a decision between a signed integer versus an unsigned integer. So if you've never played with this kind of stuff before, when you stick a number in memory, that number represents just some bytes

36:45 and your CPU is interpreting those bytes to mean something. And if you could have it, you could have it represent a positive number. And in the case of a single byte to it, that's from

36:58 zero to 255. But if you want to also have negative numbers and store it in the same amount of space, well, then now you have to sort of map something from 0 to 255 into the negative space. And so you

37:09 end up with like minus 127 to a positive 127 or 128. Let's not get into that. But essentially, the computer is interpreting those same eight bytes in a different way to represent a mix of

37:23 negative and positive numbers. The downside of that is you can store less. You can only store up to was half the size of a positive number.

37:32 In Python, you don't care about any of this, again, unless you're doing packets, but in Rust and C and other languages like it, you have to actually explicitly decide which of these you are using.

37:42 The upside is in Python, you don't care, but there is so much indirection.

37:48 Yes, there's a lot of overhead.

37:50 Yes.

37:51 And all of that overhead goes away, yeah.

37:53 Not only is it indirection and that overhead goes away, But can you put a bunch of Python, if I have an array of Python numbers, how are they going to land on like L1 cache?

38:07 Yes.

38:07 They're not going, they're all random places out in the heap.

38:11 So, I mean, there's arenas and blocks and all that stuff to try to like get them closer together, but they're still just out there rather than I've got an array of 10 numbers.

38:20 Well, guess what?

38:21 Those numbers are contiguous in memory sort of thing, right?

38:25 And you've kind of hit on something that is also very explicit in Rust.

38:29 Now, you can start Rust programming without fully understanding this, but you're not going to get very far without it.

38:35 It's fairly explicit about what goes on the stack and what goes on the heap.

38:39 So again, if these are new concepts for you, when your program is written, the stack is where function calls happen.

38:46 So when you move from one place in code into another in memory, what happens is the new address, the place you're going to, gets put onto a stack.

38:56 The old address is there before.

38:57 So when your function returns, it pops off the old stuff and then knows, oh, that's now the thing at the top of the stack.

39:03 That's now the address I'm going to run at.

39:05 And so when you add variables into, when you add parameters to your function, those are also getting put on the stack.

39:13 So you end up with this little stack frame, which is the place you're going to be running and the data that goes with that function. By contrast, the heap is sort of a general space, and that is

39:24 where you allocate things from memory. And longer lived things or things that you're passing around between functions tend to end up being created in the heap. And how Rust does memory management, we'll gloss over it for now, we'll get into it a little more later, I think, but how Rust does

39:38 manage memory management differentiates between these two kinds of things and so again this is one of those things you you know you only think about the stack in python when it fails because

39:48 you get the stack trace but otherwise you more or less ignore it whereas here once you start playing around with passing objects around whether or not you're being explicit about it that concept of am

40:00 i in the stack or am i in the heap and who owns it becomes very very important and and this isn't new to Rust. This has been there in compiled languages. This is a fundamental way how modern

40:11 computing machines work, but it's more exposed in Rust than it is in Python. You know, the thing I

40:17 think is such, to me, it was a little ironic is Python, you don't worry about pointers. You don't worry about that. You just work. And then like other languages like C, Rust, C#, you talk

40:29 stack, you talk heap, you talk pointers, you can dereference. Python is more pointer heavy than any of those languages because literally everything is in the heap. There's nothing that's even a

40:38 number is a pointer to a thing in the heap, right? Well, this is how Python got away with not having pointers. It was everything's a pointer, so we don't have to differentiate. Yeah. Yeah, exactly.

40:47 That's like, if everything is a pointer, we can just treat them all like variables, right? And that made the programming simple and you don't have to think about it. But conceptually, Python,

40:56 everything is in the heap. Everything is a pointer. Even the number one, it's a flywheel pattern. I

41:04 And even that's insane, right?

41:06 Like that, yeah.

41:08 I have three copies of 254, but I only have one copy of two.

41:14 Sure.

41:15 That is really.

41:17 Don't stop to think about it because, yeah.

41:20 Yeah.

41:20 For people listening are like, okay, they've gone off a rail.

41:23 Like they're a little, what are they talking about?

41:26 An optimization in CPython is the numbers, I think maybe negative five to 255, some range like that.

41:34 Yeah.

41:34 They're pre-allocated.

41:36 And every time you type a literal number like 72, it's the same number.

41:40 It just all points at the immutable number 72 rather than creating, you know, like whatever the eight byte or four byte chunk of it is on the stack.

41:50 Yeah.

41:50 I appreciate it makes it faster, but it's just funky.

41:52 Yeah, it's weird.

41:53 Yeah, it's something you don't want to think about too much.

41:56 A couple sort of cosmetic things, which again, if you're from Python and Python's your first language might take a little to get used to.

42:04 one is brace brackets so uh like most programming languages space is not important uh and that takes i i remember it taking me a while to get used to that switching to python so i have uh patience and

42:18 sympathy for people who started in python and have to go the other way this is pretty typical of most

42:24 programming languages uh the it makes the parser's life easier um and i think after having coded in Python for almost two decades, I think I've come down on the side of screw the parser.

42:38 So it's a little bit taking a little used to for me to get back to it.

42:43 But yeah, you, you put things in brace brackets to denote them.

42:47 Yeah.

42:47 I mean, look, the job of the parser is to make your life easy.

42:51 Not the other way around.

42:52 So I get, but I have run into situations where some little bit of formatting has been off.

42:59 Yes.

43:00 On my indentation and a reformat the code broke the code because maybe I had three indentations, three spaces instead of four for who knows, maybe I hit the delete button on accident or something weird like that.

43:14 And I said, oh, well, look, this didn't line up right.

43:16 Like I'll just hit like reformat code.

43:18 And it's like, oh, well, that needs to go back to the left.

43:20 And it's like changed actually how it works.

43:23 Yep.

43:23 So copy and paste is problematic in Python.

43:28 Yeah.

43:28 It's really problematic.

43:29 And with the braces, like it could just have no indentation.

43:32 It could be all gnarly.

43:33 It could be minified, whatever.

43:35 You just hit reformat and boom, it's reliably put back together well.

43:40 So I'm going to give Python an 80% plus, 20% minus.

43:45 I agree that it's nice.

43:47 It's not there, but it's not just there is value to it.

43:52 Structural correctness value to it.

43:54 Yep.

43:54 Yep.

43:54 I also, you know, it forces programmers to behave themselves, which if you don't get your spacing right, your code doesn't work.

44:02 It kind of makes the spacing consistent.

44:04 Yes, exactly.

44:05 That was what it was optimized for is like, you're going to make your code readable because you have to write it in a way that its structure and its readability match.

44:14 And that's beautiful.

44:16 But it is a little, it can have problems.

44:19 Yeah.

44:19 And being a veteran of the tabs versus spaces war of the nineties, eliminating that at the, at the syntax level is kind of interesting.

44:29 It really is like, and you know what, there was a gosh, what PyCon was it?

44:33 I think it was one Cleveland, maybe three, four years ago, there was a PyCon where one of the vendors clearly came.

44:41 It was a tool vendor that came from all the, they weren't Python specific, but they made tools for Python people.

44:47 and I would even maybe shout them out, or I'd call them out, but I don't even remember what it was.

44:52 But they were giving away t-shirts that said tabs versus spaces.

44:55 And you had to pick, I'm team tab, I'm team spaces.

44:58 I'm like, what are you doing?

44:59 Does nobody know that this literally is not even a choice in this language?

45:04 Why are you here?

45:06 It's a fun gag, but anyone on not team spaces is not going to run.

45:12 What is wrong with you?

45:14 Yeah. That's a team spaces versus teams. My code won't compile. Yeah.

45:21 Yeah.

45:22 An interesting side effect of this that I kind of like in this language. I don't know if I've seen it elsewhere. So like most languages, it has this rust has this concept of a statement versus

45:32 an expression. Most things are expressions. And in fact, your brace bracket is the definition of a new expression. And as a result of that, the end of the brace bracket can return something. So you

45:44 can do an assignment to a collection of code in a brace bracket. So this ends up being kind of like an inline function. and so that's kind of interesting to me and it, it, compiles down

45:57 beautifully. it's, it's got that, and then it does this weird thing where it's got implicit

46:04 returns. And so I really wish they had not done the implicit return. I am never ever going to be on team implicit return. I just can't. It drives me nuts. and, but the idea of having,

46:16 arbitrary expressions through the brace brackets is kind of elegant. So, so yeah, one point up, one point down, whatever. and then, you know, there's some odd odds and ends, right? It's, it's,

46:27 FN instead of def, which quite frankly, as soon as I saw it was like, yeah, that actually makes an awful lot more sense. That tells me what it is. Def for define, define what? What am I

46:38 defining? FN? It's a function. That makes sense. And then one of the other things that I kind of

46:44 liked a lot is, so they release a lot more frequently in Rust. So it's, there's a new, a new version coming out every six weeks, which when you come from the Python world,

46:55 that sounds insane, right? Like how do you stay on top of this? But they've got this separate concept from versions that they call additions. And an addition is a three-year cycle and things

47:06 stay compatible within the addition. And what's more, not only do they do that, but the compiler is able to compile to older additions. So when you compile the code, you can actually say,

47:18 I want to be using an older addition. And so they have basically this forever concept of backward compatibility. So now it's still a young enough language. I suspect at some point they may

47:30 give up on that. cause this, this to me smells of maintenance hell. It's fine when there's three

47:36 editions. What if there were 35? Yeah. but for the, for the time being, although there's been a

47:41 fair amount of change in the language, in the last few years, you're not screwed by it. And it's not this constant race to stay on top of it. You can just change the edition target and you're

47:53 fine. So I kind of like the idea. I think it would be kind of neat if the Python compiler, maybe, you know, if I was, I guess the changes in Python aren't as bad, so maybe it's not as extreme,

48:07 but I don't know. This just sort of appealed to me. Yeah, it does to me as well. I love the freshness of it. I just got a new version of Rust this morning. I was trying to update my libraries and tools, and it said there's a new version of Rust. Yes. Okay. So I think that might be a good

48:21 good time to maybe talk about like getting started and so on as maybe start by installing yeah uh so

48:30 uh the good news is if you're in the unix world uh some sort of Linux or mac os this is uh this is a breeze you go off to the website you copy and paste the command onto the terminal and you're

48:40 more or less done uh we do the thing that we normally do we run arbitrary code from the internet that's right as root on our machine i'm sure it's fine yeah it's fine uh if you go off to

48:50 So rest up, rustling.org.

48:51 there is right on the front page.

48:53 There is a little shell command that you install.

48:56 This actually installs a tool called rust up rust up is kind of like pie M and that it handles installation updates of the language.

49:03 It install, it installs, rust C, which is the compiler and more importantly, cargo, which is the tool.

49:10 That's kind of like uv that is what you actually use.

49:13 You almost never call rust C directly.

49:15 So rust up handles the version management of all that kind of stuff.

49:19 And once you've got that going, then you use cargo to create a new project.

49:26 Again, very uv-esque here.

49:28 So you would say, you know, if I'm doing hello world, it would be cargo new hello.

49:32 That creates a cargo.toml, which is the equivalent of pyproject.toml.

49:36 It creates a source directory.

49:39 By default, it creates a git repo and a git ignore file, which drives me nuts.

49:43 And I turned that off as soon as I could.

49:45 I want to be in control of that.

49:47 Don't do it for me.

49:48 And it creates a little stub main file, which actually has a function in it.

49:53 So you actually can run cargo new hello and you get a compilable program.

49:58 Then you write your rest and you run cargo run and cargo run builds and runs the code for you.

50:05 Now, because it's a compiled language, the result is a target that goes into the target directory.

50:12 You could run that explicitly, but it's buried like three directories down.

50:17 So rather than do that, you just call run and it does it for you.

50:20 And there are flags you can use it to go from debug mode to release version.

50:25 Your debug tends to be about 30% larger because it includes debug information.

50:32 While the production mode...

50:32 That's par for the course for people who use those things.

50:35 Yeah. And in fact, on Windows, it produces...

50:39 I think in Windows, it's packaged as a separate file.

50:42 The debug info is in a separate file, which is, again, a standard sort of Windows thing to do.

50:47 Yeah, Windows often you can put, I forgot what they're called, but there's like a debug symbols that is a file that you can put like next to a DLL or an exe and it'll pull that in.

50:56 And so it handles all of that kind of good stuff for you.

50:59 And then this is then the thing that you would distribute if you were trying to distribute it.

51:05 There's a command for building on its own and then the command for run both builds it and runs it.

51:10 One of the things I'm still not quite used to is it outputs some information from the build before it actually runs the code.

51:18 So you get two or three lines of info before you actually see the output from your program, which drives me nuts.

51:23 But there is a dash queue to tell it not to do that so that if I'm running it, I don't want to see your compiler stuff.

51:29 I want to actually have it run unless something went wrong.

51:32 So yeah, cargo really is the key to doing all of this kind of stuff.

51:36 Like uv, it also manages what they call crates, which are the Rust equivalent of wheels.

51:43 There is a crates.io is the equivalent of PyPI.

51:49 And you can write libraries and upload them there.

51:51 And like with Python, this is a fairly robust community that's writing and trading code here.

52:01 331,019 crates in stock.

52:04 We look at PyPI.

52:06 think we're at 750 the last time I looked.

52:09 I haven't looked for either.

52:12 889,000, 890,000.

52:14 So there are more, but I don't think that is necessarily the core metric.

52:18 No, and it's also not a fair comparison because proportionately the number in crates would actually seem smaller to a Python developer.

52:29 And what I mean by that is if when you're coming from the batteries included world, yeah, there aren't a lot of batteries in Rust.

52:34 So something as simple as like a random number, that's a crate.

52:39 And they've done this to try and keep the footprint small, which I kind of understand.

52:44 For somebody who's starting out, this can be a little, so like I had this, I'm paranoid, right?

52:51 So I want to know where my code is coming from.

52:54 If I'm in the Python world, I trust the standard library.

52:57 If I stick to the standard library, I know I have a degree of safety.

53:00 Once I step outside of the standard library, I want somebody to tell me they've used it and they trust it.

53:05 And, you know, for certain kinds of libraries, there's enough press that you can kind of get the idea.

53:10 I haven't yet quite figured out how to get that information in the Rust world.

53:15 And because things like random, which you use all the time, are actually crates, you kind of have to do a little bit of the, there's a little more rolling the dice on do I trust this code to use it kind of thing going on there.

53:27 But I suspect that's still my newness to the community.

53:30 Yeah, perhaps. You know, Chris, just because you're paranoid doesn't mean they're not after you.

53:35 Yep, that's right. That's exactly right.

53:38 And with the supply chain stuff, it means, I mean, it's crazy.

53:43 In the world of the internet, they are out to get you. Yes, without a doubt.

53:47 Oh my gosh. And sometimes you hear the pounding on the door. You're like, oh my gosh, go away, please don't do that. Let's just like reflect for a minute. We talked about like cargo crates and all

53:59 all these things, we've seen a big revolution in Python packaging, deployment, flexibility, project management, all of those things. And much of that has actually come from the Rust side. A

54:13 lot of the tools like uv and others are seriously inspired by cargo, the crates, and these types of things. But this was built in a world where PyPI already existed and npm already existed. And they

54:26 could go really good. Ooh, that's not good. Let's do it this way. Right. So there's like this sort of interplay or this circling of these two worlds. Yeah. It's, you know, without,

54:37 I'm not trying to start a flame war, but the decision that the PSF made that, managing packages wasn't really part of the language and that we should have this plethora of third-party

54:50 tools to do that. I think that was a mistake. And I think the Rust people recognize that and decided to bundle this in. it's, it's a lot cleaner and there's a lot less wondering of what's

55:03 going on. and, now in defense of rust, sorry, in defense, I don't know who I'm defending. Nevermind. I'm not sure whatever I'm going to defend. I'm not going to defend. Uh,

55:16 the, I think the target for rust is simpler. And, part of the thing that happened in the python world is because of that dynamicism it creates all these other kinds of complications

55:29 um so yeah it's right my package also requires a fortran compiler exactly yeah right whereas

55:35 because you're compiling these things down you some of that stuff goes away so so yeah it's it's

55:41 it's a challenge i agree but also wheels do exist now yep in the python world created them and they didn't before and that was like a super hard problem because yeah everything needed like all these bespoke tools just to install something interesting. And then they said, no, no, no,

55:55 let's just make wheels. You can just have like, why do we have to make everyone recompile everything from source? So they kind of got there. Another thing I think- They're making progress. Yeah, no, they're making progress. Yeah. Another thing I think is interesting around this is

56:08 you talked about the sparseness of the standard library equivalent of Rust. I feel like Python batteries included the richer standard library. It is that way because PyPI didn't exist.

56:21 The concept of a package manager didn't exist when Python, you know, and honestly, like what was 91?

56:27 Like the web didn't exist.

56:28 Like getting stuff afterwards was really, really hard.

56:32 If it were easier, they may have made different choices.

56:35 Yeah.

56:35 It's, it's a consequence of this language being around since the nineties.

56:38 Right.

56:38 So the decisions up front were, and what, and what it was designed for versus what it's grown into.

56:45 you know, that's, we should all be, as software developers, we should all be so lucky as having our initial designs become questionable because 35 years later, people are still using our software

56:58 all over the planet. Yeah. If people want to criticize mine because it's so popular in 30

57:03 years, I'd be happy as well. Yeah, exactly. All right. We've got a little bit of time left, but it's not a ton. I think let's focus on one more section and that would be, how do I go from

57:15 Rust land to Python land. So there are different libraries for doing this. The most common one out

57:20 there is a crate called Py03. And essentially what this does is provide you with the tools

57:29 to align your Rust code as if they are Python objects. And then there are a couple other tools

57:36 that you can use to actually do the packaging part. So what Py03 does is it defines the interface the compiled object, which is a dynamic library, so a.so file or a.dll, and then does that in

57:51 compliance with Python's ABI. And then there are tools out there that you can use, which will put those inside of a virtual environment so that Python can see them. And then in Python, you can

58:03 load that code that you wrote as if it were a regular Python module written in Python.

58:09 The how Py03 does this is a couple different things.

58:12 One, it has Rust objects that are compatible with the Python objects.

58:17 So as an example, Pyint is a Rust object that represents a Python integer.

58:22 So if you need access inside of your Rust code to the integer inside of the Python space, this acts as a mechanism to get at it.

58:31 It will also map Rust concepts.

58:34 So rather than using pyint, you can just use, say, a int32, and py03 will take care of mapping that up to the Python integer when Python's using it in the Python side of the world.

58:47 The other thing that it does is Rust has a mechanism that is macros for changing how things get compiled.

58:55 And py03 ships with a bunch of macros that essentially you attach to something like a function.

59:01 So if you want the function or a class to be available to Python, you wrap it with one of these macros.

59:06 It's just a regular Rust function, but the macro is what does the mapping and makes it available.

59:13 So with the right use of the macro, you can say things like, you know, this is my function.

59:18 It's got three arguments.

59:19 These arguments need to map to this, et cetera.

59:22 And essentially what happens when you compile it is all of this gets put into a.so.

59:27 And then you use tools like Maturin or others that then put that into a virtual environment and to handle the packaging side of things so that your Python code can use it.

59:38 And from Python's perspective, once that's installed in the right place, you just import foo from bar as you would with any other module and you've got access to it all.

59:48 Interesting.

59:48 Now, it doesn't have to be all or nothing as well.

59:51 For example, remind me how to do this because I forgot how to do it.

59:54 but you can create a project that has some Rust code and some Python code and then build that into a wheel.

01:00:01 But you could say only part of my code is gonna be Rust and the rest of it that's not performance critical, that's all Python all day long.

01:00:09 Yeah, so for example, if you look at, if you pay close attention when you install Polars, you're actually getting two wheels, one of which is a universal wheel, which is because it's universal, it only contains Python code.

01:00:22 And the other of which is it's figured out what platform you're on and gives you the actual compiled Rust version of the Polars library. So they've kind of got these two things going on. Now, I don't know Polars well enough. I've never looked at their source code, so I don't know what they've

01:00:37 got in each one of those packages, but they've built something that is comprised of both of those things. In their case, it's in two separate wheels. It doesn't have to be. And essentially,

01:00:47 you're using a tool like Mature and it takes care of this for you. So if you're after a, if you're after building a library where there's a part of it that has to be very performant, but you want to write most of it in Python because, you know, it's easier to code in,

01:01:03 then there's, you basically do that and Maturin will let you bundle all of that up.

01:01:07 And this is no different than any other plugin mechanism. It's just that these are the tools that Rust provides to build those kinds of plugins. So if you think of tools like Polars or NumPy or any others that do this kind of concept where some of it's written in a lower

01:01:21 level language, I O three just lets you do that.

01:01:23 I think there's a lot of, a lot of low hanging fruit for people to go apply a profiler to their code and say, no, it really only matters at least 20 lines of code here.

01:01:33 Yeah.

01:01:33 What if?

01:01:34 Yeah.

01:01:35 The challenge you have to pay is every time you do this, you're crossing a boundary and there is a cost to crossing that boundary.

01:01:43 So, there, if you're writing the code in such a fashion that you're constantly going back and forth or your objects are constantly going back and there's overhead to that so writing in and rust doesn't guarantee that it will be faster

01:01:56 could make it slower it could make it slower like with everything uh but if you're doing something you know it's something like polar's where you're doing big number crunching uh and you're you know you're calling into the api and then letting it crunch and then it spit another answer out then

01:02:10 yeah you can you can see a significant speed up yeah or pydantic where it comes in as json anyway and it's got to be transformed to something, let that happen in Rust and then talk to it.

01:02:21 So yeah, this is really good.

01:02:23 I'm going to have Pablo and Laszlo on to talk about the new profiler that's in 3.15.

01:02:30 That's really interesting, the profiling module.

01:02:31 One of the things that's fascinating about that, I don't have anything in production in 3.15.

01:02:37 All my stuff's in 3.14 or lower, like older.

01:02:41 Now, one of the things that's cool about the new profiler is you can attach it to stuff running in production, profile it, and then walk away.

01:02:49 You know, like, hey, let's just go, it's running.

01:02:52 A bunch of people are using this app, like it's an API or something.

01:02:55 Let's just hook onto it for 30 seconds, get some data and step back.

01:02:59 And then maybe you could look at, oh, actually, if we could just make this one part faster, that would really be a big deal.

01:03:05 So I think the possibility for this is just getting easier.

01:03:08 Yeah, well, and, you know, the general advice I give folks when I talk about optimization is don't and then measure, right?

01:03:16 So when you're trying to figure it out upfront, it doesn't matter how good you are at this.

01:03:21 You tend to make the wrong assumptions eventually.

01:03:25 And so, yeah, build something, then profile it, and then figure out where you're spending all your time.

01:03:30 Yeah, I've had a couple of experiences.

01:03:32 I won't go into the details of it, but I've told it a time or two way, way back in the day where I was so wrong.

01:03:40 Yep.

01:03:40 So wrong about what was slow and what was fast.

01:03:43 And if I had just pursued my intuition, it would have been months of bad choices.

01:03:47 Yeah.

01:03:48 And there's a concept called Amdahl's Law, which is essentially, I'm going to oversimplify it, but if your code is spending 10% of its time in that place,

01:03:59 speeding that up by 2x is only ever going to get you a 10% gain because your code's spending the other 90.

01:04:07 There's a diminishing return aspect to it as well.

01:04:10 And as programmers, I think we often get tied up in the, oh, wouldn't it be cool if I made this code three times harder to read and it'll be, you know, half a millisecond faster.

01:04:20 And how often do you call that?

01:04:22 Once a year.

01:04:23 Oh, okay.

01:04:23 Well, there's a month of your life you got back in order to optimize by a millisecond, right?

01:04:30 Where you got to find the stuff that is actually causing the problem.

01:04:33 Yeah.

01:04:34 You gave a 50% speed up example.

01:04:36 Like, let's take it to an insane level.

01:04:39 20% of your code, 20% of time you spend in some bit of code.

01:04:43 If you could make it infinitely faster, the best you're going to achieve is your program is going to be 20% faster.

01:04:50 You know, maybe, oh, I was running this on a single CPU thread.

01:04:54 I'm going to actually get a GPU machine with a crazy thing and do a bunch of GPU programming.

01:04:59 And I can parallelize this and I'll get it down to a thousand times faster.

01:05:03 Is that worth a 20% speed up?

01:05:05 If it takes five milliseconds, you've saved one millisecond.

01:05:09 hooray look how much harder your life and how much more expensive deployment is and so on right yeah yeah so it's certainly uh something that people should keep in mind all right well i think

01:05:19 let's let's wrap things up here rust is super interesting i think it's got a place in python and even if you don't want to write rust a lot of these really important libraries are

01:05:31 somewhat backed by rust so you want to read them and maybe contribute to the to the caramely shell or the noogity inner, but you still kind of want to understand the bits. I think maybe a quick

01:05:41 shout out to your course. People should definitely give this a listen or a watch. Just talkpython.fm, click on course at the top. Rust will be, the Rust course will be right at the top of that list.

01:05:52 Yeah, it was fun to build. I hope people enjoy it.

01:05:54 Yeah, I think they will. And more importantly, more broadly, I suppose, people want to get started with Rust. You've inspired them, Chris. They're ready. What do you tell them?

01:06:04 Rustlang.org is pretty much the place to start.

01:06:08 It's remarkably well documented.

01:06:10 There's a lot of good guides and things out there.

01:06:13 The documentation right on that site, they've got the Rust book right there.

01:06:18 It's quite easy to follow.

01:06:20 It has a lot of really, really good examples in it.

01:06:24 So that's definitely a place to go.

01:06:26 The other space, just a bit of a shout out would be, there's a awesome list called Awesome Python RS.

01:06:33 And it's just a massive list of the tools and libraries that use Rust in the Python space.

01:06:39 So if you're looking for, rather than like education book examples, you're looking for places that actually use it and you want to, and you want to troll through some code, that's a great

01:06:50 place to go looking for interesting libraries to take a look at. Yeah. I second that. I'm,

01:06:55 I'm such a sucker for awesome lists. Yes. That could be, you want to watch a movie? I found a new awesome list. I'm just going to poke around this for like the next half hour, if you don't

01:07:03 mind, you know? Yeah. And, you know, there's some very classic examples on this list of like drop-in replacement for speed things, right? So there's a cryptography library and there's a JSON library,

01:07:15 both of which are basically drop-in replacements for stuff from the standard library. And because they're written in Rust, they're screamingly faster. So, you know, that example of looking for the thing that you need to optimize, there's some good ideas in there that you can dig into.

01:07:30 Yeah. And you know, I gave you the example of like, well, we could just rewrite this bit of your slow code and rust. It might already be written as a library.

01:07:38 Someone else may have done it as well. Yes.

01:07:40 Yeah. Just swap, swap your JSON parsing library or whatever. Right.

01:07:43 And, and a lot of the, Python things that are like Python libraries that use rust, a lot of them are actually just thin wrappers to existing rust libraries.

01:07:54 So that somebody is rather than writing something from scratch, they're like, Hey, there's this neat library in Rust that does this thing that I like, and I wish it was in Python.

01:08:03 And they write like four lines of code that are essentially the API wrapper down to make it, expose it as a module.

01:08:10 And now we can take advantage of the fact that there's this whole other community that's trying to do these efficient things.

01:08:16 And we don't have to trust the suitability and correctness of somebody saying, hey, I spent a weekend rewriting the JSON parsing.

01:08:24 Like, ah, brightening.

01:08:26 These are things with thousands of stars and many contributors because the Rust community themselves are using them, right?

01:08:33 Right, right.

01:08:33 And if you just wrap it, you're pretty safe.

01:08:36 Polars is an example, right?

01:08:37 Polars is a Rust library for Rust programmers.

01:08:40 And then there's a Python thing on top of it, right?

01:08:43 So you're getting not just the Python people using it, but the Rust people using it as well.

01:08:48 What is that?

01:08:49 A caramel dipped apple equivalent version or something like that?

01:08:52 Yes.

01:08:53 I don't know.

01:08:53 There's caramel everywhere by the time we're done.

01:08:55 So it's a messy, messy kitchen.

01:09:00 It was delicious.

01:09:01 It was a delicious episode, Chris.

01:09:03 Thank you for being here.

01:09:03 That's all right.

01:09:04 Happy to be here.

01:09:05 Yeah, bye-bye.

01:09:06 This has been another episode of Talk Python To Me.

01:09:09 Thank you to our sponsors.

01:09:10 Be sure to check out what they're offering.

01:09:11 It really helps support the show.

01:09:14 This episode is brought to you by Sentry.

01:09:16 You know Sentry for the error monitoring, but they now have logs too.

01:09:19 And with Sentry, your logs become way more usable, interleaving into your error reports to enhance debugging and understanding.

01:09:27 Get started today at talkpython.fm/sentry.

01:09:31 And it's brought to you by the Talk Python in Production Book, an inside look at 10 years of the real-world DevOps behind the Talk Python sites and apps.

01:09:39 Check it out at talkpython.fm/DevOps book.

01:09:42 If you or your team needs to learn Python, we have over 270 hours of beginner and advanced courses on topics ranging from complete beginners to async code, Flask, Django, HTML, and even LLMs.

01:09:55 Best of all, there's no subscription in sight.

01:09:58 Browse the catalog at talkpython.fm.

01:10:00 And if you're not already subscribed to the show on your favorite podcast player, what are you waiting for?

01:10:05 Just search for Python in your podcast player.

01:10:07 We should be right at the top.

01:10:08 If you enjoyed that geeky rap song, you can download the full track.

01:10:11 The link is actually in your podcast blur show notes.

01:10:14 This is your host, Michael Kennedy.

01:10:16 Thank you so much for listening.

01:10:17 I really appreciate it.

01:10:18 I'll see you next time.

01:10:45 I think is the norm.

01:11:16 Продолжение следует...

Talk Python's Mastodon Michael Kennedy's Mastodon