Side-by-side, interactive cheatsheets for Python programmers
comparing Python to other languages. Every example runs live in your browser — no setup, no installation.
Choose your own path by reordering languages
Python's closest peer and philosophical foil. Both are readable, dynamic, and expressive, but Ruby's blocks, open classes, and "there's more than one way" ethos give you a richer object model — the language that gave the world Rails and proved convention-over-configuration could be beautiful.
do…end syntax; more powerful than Python's single-expression lambdasnil all have methods; there's no primitive/object split:name vs "name" — a distinction Python's str type doesn't makePython's favorite upgrade path. When you've hit a performance wall or need concurrency without the GIL, Go delivers static types, native goroutines, and 10× throughput — with a learning curve much shorter than Rust or C++.
threading and asyncio with one unified modelThe language of the browser, JavaScript is the one runtime every Python web developer eventually meets on the front end.
[] and {} are truthy in JavaScript but falsy in Pythonnull and undefined — where Python has only None=== vs. ==: the strict equality you should reach for, and the coercing one you should avoidmap, filter, reduce) in place of list comprehensionsthis instead of an explicit selfasync/await with no explicit asyncio.run()The language CPython is written in. Every list, dict and str you use is a C struct with a refcount on the front — so C is less a foreign language than the floor underneath the one you already know.
& and * make explicit what a name binding already ismalloc/free instead of reference counting, with leaks and use-after-free as the pricelist, dict or str — a string is a pointer to bytes ending in zero, and strlen is O(n)errno instead of exceptions; nothing forces the caller to checkctypes actually do, including releasing the GIL for real parallelismRoughly what a Python developer wishes Java were — and then null becomes a type error. Inference, top-level functions, expressions instead of statements, data classes, and no ceremony to speak of. So this page is not about boilerplate: it is about what a type system buys once the boilerplate is gone.
String and String? are different types, and the compiler refuses the call your annotation only ever documenteddata class is @dataclass with copy(), destructuring and generated equality — and == is structural while === is identity, the reverse of Python's namingwhen over a sealed type is checked for exhaustiveness at compile time, which is the one thing match cannot doawait at the call site and no event loop to pass around, and structured concurrency cancels the children for youpip and an activated environmentPython's expressiveness, but with memory safety, concurrency without the GIL, and performance without a rewrite. Rust eliminates entire classes of bugs at compile time while keeping code readable.
Option and Result make None and errors explicit in the type system — no more AttributeError: 'NoneType' object has no attribute at runtimematch — more powerful than Python's match, and the compiler enforces you handle every caseA struct is a copy, and that is the whole first hour. Python has nothing like value semantics — every name is a reference, which is exactly why def f(items=[]) misbehaves. Add optionals as a type rather than a value that can turn up anywhere, and most of the surprise on this page is accounted for.
struct — and Array, Dictionary, Set, String — copies on assignment, so no aliasing, no defensive copy, and no mutable-default-argument bugString and String? are different types; if let, guard let and ?? are the ceremony that buys the guaranteesome against any is the distinction that trips people upweak and unowned are your jobasync/await is spelled the same and runs on a real thread pool: genuinely parallel, with actor isolation checked by the compiler"👨👩👧".count is 1 where Python counts code points and says 5Python's familiar syntax meets compile-time type safety. TypeScript catches whole classes of bugs before they run — the same errors that only surface at runtime in Python.
Optional-equivalent T | null — the same expressiveness as Python's type hints, but verified by the compilerinterface and structural typing — like Python's Protocol, but built into the language and checked everywhere<T> — the same concept as Python's TypeVar, with cleaner syntax and broader tooling support`Hello, ${name}!` vs f"Hello, {name}!"The static language that meets you halfway. LINQ is the comprehension you already write, yield return is yield, and async/await is spelled exactly the same. What is genuinely new is that types are checked before the program exists, that a struct copies when you assign it, and that two threads really do run at once.
Where/Select/GroupBy/Aggregate, deferred exactly like a generator expression — but re-runnable, where a generator is spent after one passyield return compiles to the same kind of state machine yield does, so your generators translate almost line for linestruct, or reading one out of a list, hands you a copy — the correctness surprise that costs newcomers the most timevar means inferred, never anythingasync/await looks identical and promises more: no GIL, so Tasks and AsParallel() use every corestring? marks what may be null and the compiler warns when you forget to check — plus ?., ?? and ??= for the null dance@dataclass with value equality and with expressions built in, and switch expressions are a match the compiler checks for exhaustivenessEverything you defer to run time, decided before the program starts. A type hint is a comment Java turns into a contract: the wrong argument is a build failure rather than a TypeError at 3am, there is no top level to write a script in, and the compiler asks you to say what Python let you leave implicit — the element type, the exception, the interface.
List<String> changes what compiles, where list[str] changes nothing unless you separately run mypypublic static void main(String[] args)multiprocessing — and every piece of shared mutable state becomes yours to guardrecord is @dataclass(frozen=True) built into the language, and sealed interfaces plus switch patterns give match the exhaustiveness check it lacks== compares identity so strings need .equals, an int wraps silently at 2³¹ where a Python integer just grows, a missing key returns null instead of raising KeyError, and there is no comprehension, no keyword argument and no REPL habitPython syntax you already know, plus the performance you've always wanted. Mojo extends Python's familiar syntax with strict typing, value semantics, and SIMD — letting you write Python-style code that compiles to metal.
def functions work exactly like Python's — mutable arguments, implicit typing, no ceremonyfn functions are strict and typed — declared argument mutability, explicit return types, zero runtime overheadvar declares a new variable; Mojo's type inference means you rarely need to spell the type outstruct types have value semantics — no garbage collector, no hidden allocations, fully predictable performancePython.import_module() — call any Python library directlyTwo dynamic languages that both grew optional typing, and only one of them means it. def greet(name: str) accepts 42 and fails later, somewhere else; function greet(string $name) throws at the call, and declare(strict_types=1) stops the engine coercing on the way in. This is the rare page where your own tooling is the looser of the two.
mypyarray does the work of list, dict and tuple — and it is copied on assignment, so the mutable-default-argument bug is unreachableuse (...) clause namesarray_map and array_filter with callbacks, in the opposite order from each other, and array_filter keeps the keysmatch, readonly, constructor promotion, named arguments and ?->; Composer is the part of the ecosystem a Python developer enviesThe scientific language that compiles to fast machine code, Julia gives Python developers NumPy-style array math and C-like speed without leaving a high-level, dynamic language.
1:3 is 1, 2, 3)sqrt.(values), numbers .* 2) instead of NumPy or loops^ for exponentiation, and div(a, b) for floor divisionend rather than indentationBool — no truthy/falsy valuesWhere Python's data-science world meets the language built by statisticians. R is vector-first and data-frame-native — much of what NumPy and pandas add to Python is simply how R already works.
42 is a length-1 vector and arithmetic is vectorised by default, so loops and comprehensions are rarely neededx[1] is the first element and 1:5 is 1, 2, 3, 4, 5<- for assignment and c() to build vectors, instead of = and list literalsdata.frame is part of base R — the original inspiration for pandas, available with no importNA for missing values, separate from NULL — first-class missingness rather than NaN/Noneapply family (sapply, lapply, vapply) in place of loops and method chains