What is Python, and why do developers pick it over languages that are older, faster, or far stricter about types? The honest answer is that Python optimises for the cost of writing code rather than the cost of running it, and it wins hardest in the projects where the bottleneck is the person at the keyboard. Below: what the language actually is, how it executes, the trade-offs hiding behind the hype, and how to judge whether it fits the problem in front of you.
What is Python, in plain terms?
Python is a high-level, general-purpose, dynamically typed programming language first released in 1991 by Guido van Rossum. Its original design brief was unusually opinionated: code should read as a near-literal statement of intent, and the language should stay small enough that a newcomer could hold the whole thing in their head. That is why Python has no semicolons, no braces, and no public static void main ceremony.
Six properties define the everyday experience of writing Python:
- Indentation is syntax. A block of code is defined by its indentation, not by braces or keywords. Four spaces per level is the convention that nearly every tool expects.
- Dynamic typing. Values carry a type at runtime; variables are names bound to objects. You can move fast because nothing is checked before the program runs.
- Everything is an object. Numbers, functions, and even classes are objects with attributes and methods. That uniformity is why libraries compose so cleanly.
- Batteries included. The standard library ships a JSON parser, a CSV reader, a date library, a queue, an email client, and an HTTP client, all without installing anything.
- Automatic memory management. You rarely free anything by hand; unreachable objects are collected for you.
- Cross-platform and open source. The same source runs on Windows, macOS, and Linux, and the language is stewarded by the Python Software Foundation.
import sys
print('Python', sys.version.split()[0])
print('Implementation:', sys.implementation.name)
# Every value in Python is an object, and every object advertises its type.
values = [42, 3.14, 'forty-two', True, None, [1, 2, 3]]
for value in values:
print(f'{value!r:>14} -> {type(value).__name__}')
That last loop is a small preview of the language's style: iterate, format, print. There is no type declaration, no loop counter to maintain by hand, and no separator string to get wrong. The !r conversion asks for the repr of the value rather than its plain text, which is why the string appears with quotes around it.
Is Python compiled or interpreted?
Both, and the honest description is more useful than either label. When CPython (the reference implementation that most people install) starts, your source file is parsed and compiled to an intermediate bytecode, and that bytecode runs on a virtual machine inside the interpreter. The compiled form is cached as a .pyc file inside a __pycache__ folder next to your source, so the translation cost is paid only when the file changes.
This has three practical consequences. Start-up is slightly slower than launching a native binary, because translation happens at least once. Deleting __pycache__ is always safe, because it is a cache and not a source of truth. And shipping a program to a machine with no Python means installing the runtime or bundling it with a tool like PyInstaller, which produces a much larger executable than you started with.
The bytecode is also worth looking at while you are learning. Disassembling a small function shows the steps Python actually plans to take, which is a faster route to understanding a bug than guessing.
import dis
def add(a, b):
return a + b
for step in dis.get_instructions(add):
print(f'{step.opname:<20} {step.argrepr}')
The listing is short because the function is short: a resume marker, two loads, an add, and a return. Seeing that LOAD_FAST and BINARY_OP sit behind a line that reads like arithmetic is a useful reminder that Python's readable syntax is a translation layer, not a machine-level plan.
What makes Python programs so short?
The brevity comes from removing ceremony, not from clever syntax. Several features let you express a whole idea in one line that other languages need four or five to spell out. Multiple assignment, sequence unpacking, and dictionary unpacking are the ones you will meet first.
# Swap two values without a temporary variable.
left, right = 'first', 'second'
left, right = right, left
print(left, right)
# Unpack a sequence into named pieces; *middle collects the rest.
head, *middle, tail = [10, 20, 30, 40, 50]
print('head:', head, '| middle:', middle, '| tail:', tail)
# Merge mappings with ** instead of repeated key assignment.
defaults = {'retries': 3, 'timeout': 30}
overrides = {'timeout': 10}
settings = {**defaults, **overrides}
print(settings)
None of this is novelty for its own sake. The pattern repeats throughout the standard library and the popular third-party packages: a function that accepts an options mapping, merges it over sensible defaults, and hands back a single dictionary that the rest of the program can read without defensive checks.
Where does Python win, and where does it cost you?
Python's advantage concentrates where the ratio of thinking time to running time is high. Its weakness concentrates in the opposite case.
| Area | Why Python fits | Where it strains |
|---|---|---|
| Data analysis and machine learning | The ecosystem is the reason: array maths, data frames, plotting and model training all speak one language | Inference in production often moves to a compiled runtime anyway |
| Web APIs and backends | Async frameworks, type hints, small deployment footprints | Raw request throughput trails compiled servers |
| Automation and operations | Shell scripts become readable programs with error handling and tests | Unattended long-running jobs need more operational care |
| Teaching and scripting | Low ceremony keeps the lesson on the concept | Learners can carry sloppy habits forward unchecked |
| Embedded and hard real-time work | Almost never the right tool | No deterministic latency, no memory guarantees |
Two costs deserve emphasis because they surprise people arriving from compiled languages. A Python-level loop is dramatically slower than the equivalent loop in C or Rust, because every step of the iteration is executed by the interpreter. When that matters, the fix is not cleverer Python but moving the hot work into a vectorised library or a compiled extension. And because types are checked at runtime, mistakes surface when the bad line executes rather than when the program starts; type hints, a checker such as mypy, and a test suite close that gap.
There is also a deployment tax. Your program needs a Python interpreter on the target machine, and while packaging interpreters has improved, the tax has not gone away.
Where does Python sit in the 2026 toolchain?
The old "Python 2 or Python 3?" question is gone. Python 2 reached the end of its life in 2020, and 3.x is the only line you will meet. Three releases matter today: 3.12 landed in October 2023, 3.13 in October 2024, and 3.14 in October 2025, so by 2026 the 3.14 series is the newest stable branch while 3.12 and 3.13 remain heavily deployed. Everything in this tutorial runs unchanged on all three.
The recent releases have mostly made Python safer to build on rather than more exotic. Type parameter syntax means generic classes no longer need a separate typing import. F-strings can now contain the same quote character that delimits them, and can span multiple lines. Error messages name the offending value more often. An experimental free-threaded build removes the global interpreter lock, which matters for CPU-bound threading but is opt-in and not the default. Meanwhile the tooling around the language has matured: fast installers, a standard lockfile format, and type checkers that run inside ordinary editors.
None of that changes the fundamental bargain. Python asks you to trade a slice of runtime speed for a large increase in developer velocity, and it is a good trade whenever you are the bottleneck.
Your turn: probe the interpreter you already have
You can learn a lot about your setup in five minutes, and it is worth doing before the next lesson builds on it.
- Open a terminal. On Windows run
python --version(orpy --versionif you installed the launcher), on macOS and Linux runpython3 --version. Note the exact number: that is the version everything in this tutorial assumes. - Create a file called
orientation.pywith the first code block from this page in it, then run it withpython orientation.py. - Extend the script so it also prints the sum of the integers from 1 to 100 computed twice: once with a loop and once with
sum(range(1, 101)). Both must print 5050. - Deliberately break it: put the string
'5'where the code expects the number 5 in the arithmetic line, run it again, and read the error message from the bottom up. That message is your next lesson's subject.
What to remember
- Python is dynamically typed, indentation-based and garbage-collected, with a standard library that covers most of what a small program needs.
- CPython compiles to bytecode and caches it; "interpreted" is a simplification, but a useful one for predicting start-up cost.
- Short code comes from fewer language features doing more work, not from terse syntax.
- Python wins where reading and writing dominate; it loses where raw speed and compile-time guarantees dominate.
- The version numbers that matter in 2026 are 3.12, 3.13 and 3.14. Everything here runs on all three.