Chương 01 · Hello Python

Hello Python — triết lý, cài đặt, môi trường biệt lập

Python là một trong những ngôn ngữ đọc dễ nhất — và cũng là ngôn ngữ bị cài đặt sai nhất. Chương này khoá kiến thức nền: lịch sử và triết lý ngôn ngữ, cách cài đặt đúng (pyenv hoặc uv chứ không phải system Python), virtual environment vì sao cần, pip vs uv, pyproject.toml, và Zen of Python.

Độ dài: ~800 dòng Bài tập: 5 Quiz: 7 Prerequisites: terminal cơ bản
🎯 Mục tiêu chương
  • Hiểu lịch sử Python: Guido van Rossum 1991, BDFL, PEP process, vị thế ngôn ngữ hôm nay.
  • Cài Python đúng cách: tránh system Python của macOS/Linux, dùng pyenv hoặc uv.
  • Dùng REPL để thí nghiệm nhanh; viết và chạy file .py đầu tiên.
  • Hiểu vì sao cần virtual environment — không chỉ dùng cho có.
  • Tạo venv với python -m venv, và với uv (tool mới 2024+).
  • Biết pip, requirements.txt, pyproject.toml, PEP 621.
  • Đọc Zen of Python và áp dụng nó như kim chỉ nam viết code.
  • Hiểu Python không compile ra binary, mà sang bytecode trung gian.

1. Python là gì? Lịch sử và triết lý

Python được tạo bởi Guido van Rossum tại CWI (Hà Lan) vào cuối năm 1989, phát hành bản công khai đầu tiên năm 1991. Cái tên không liên quan gì đến loài rắn — Guido lấy cảm hứng từ chương trình hài kịch Anh Monty Python's Flying Circus. Điều đó giải thích vì sao tài liệu Python chính thống hay có ví dụ spam, eggs, foo, bar.

Guido được cộng đồng gọi là BDFL (Benevolent Dictator For Life — "Lãnh đạo độc tài nhân từ trọn đời") — vị trí ông giữ cho đến khi từ chức năm 2018. Sau đó Python được điều hành bởi Steering Council (Hội đồng điều hành) gồm 5 thành viên bầu lại hàng năm.

Phiên bảnNămHighlight
Python 0.91991Bản công khai đầu tiên. Đã có class, exception, function, kiểu list/dict.
Python 2.02000List comprehension, garbage collection, Unicode.
Python 3.02008Break compatibility với Python 2. print thành function, str mặc định Unicode.
Python 3.52015async/await, type hints (PEP 484).
Python 3.62016f-string, type hints cho variable.
Python 3.82019Walrus operator :=, positional-only parameters.
Python 3.102021match/case (pattern matching), better error messages.
Python 3.112022Nhanh hơn 3.10 25%, exception group, tomllib built-in.
Python 3.122023Type parameter syntax (PEP 695), f-string formal grammar, perf.
Python 3.132024JIT thử nghiệm, free-threaded build (no-GIL), REPL mới đẹp.
⚠️ Python 2 đã chết

Python 2 ngừng hỗ trợ từ 1/1/2020. Mọi code mới phải Python 3. Nếu thấy code gọi print "x" (không có ngoặc) hoặc xrange, đó là Python 2 di sản — đừng dùng làm tham khảo. Sub-pillar này dùng Python 3.12+ với type hints từ chương đầu tiên.

1.1. Ai dùng Python?

Python là ngôn ngữ đa dụng. Vài lĩnh vực nó áp đảo:

  • Data Science / ML / AI — pandas, NumPy, PyTorch, TensorFlow, scikit-learn. OpenAI, Anthropic, Google DeepMind đều dùng Python làm ngôn ngữ chính cho research.
  • Web backend — Django (Instagram, Disqus), FastAPI (modern, async). Instagram chạy backend lớn nhất thế giới trên Django.
  • Scripting / Automation — viết script cho DevOps, sysadmin. Ansible viết bằng Python.
  • Khoa học — NASA dùng Python cho phân tích dữ liệu vệ tinh, mô phỏng quỹ đạo. CERN dùng Python phân tích dữ liệu Large Hadron Collider.
  • Tài chính — Jane Street, Bloomberg, các quant fund.
  • Giáo dục — ngôn ngữ #1 dạy lập trình ở đại học (thay thế Java, C++).
🧠 Vị trí Python trong landscape

Nếu JavaScript thống trị browser + web frontend, thì Python thống trị data + AI + scripting. Hai ngôn ngữ này gần như chia đôi thế giới phần mềm hiện đại. Một developer trung bình hôm nay biết cả hai là tiêu chuẩn, không phải bonus.

1.2. The Zen of Python (PEP 20)

Triết lý Python được tóm tắt trong PEP 20 — The Zen of Python bởi Tim Peters. Đây là 19 nguyên tắc thiết kế được "in" mỗi khi gõ import this trong REPL — một easter egg nổi tiếng.

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Readability counts.
There should be one — and preferably only one — obvious way to do it.
Now is better than never.

Đối lập với "JavaScript có 10 cách viết một thứ", Python theo nguyên tắc "chỉ một cách hiển nhiên để làm". Đó là lý do code Python của người này đọc giống người khác — phong cách bị "ép" bởi triết lý ngôn ngữ.

2. Cài Python — đúng cách

Đây là bước nhiều người làm sai từ đầu, dẫn đến lỗi khó hiểu nhiều tháng sau. Hãy đi chậm.

⚠️ Pitfall lớn — System Python

macOS, Ubuntu, hầu hết Linux distro đều có sẵn Python (/usr/bin/python3). ĐỪNG dùng để phát triển. Lý do:

  • System tooling (Homebrew formula, apt, một số script hệ thống) phụ thuộc vào Python phiên bản đó.
  • Nếu bạn pip install bừa bãi vào system Python, có thể làm hỏng tool hệ thống.
  • Version system Python lock theo OS — không nâng cấp được. macOS 14 vẫn Python 3.9, lạc hậu.
  • Cần sudo để install package → sai mindset (tạo conflict global).

Quy tắc: system Python chỉ dành cho OS. Bạn cài Python riêng cho development.

2.1. macOS / Linux — pyenv (khuyên dùng)

pyenv là tool quản lý nhiều phiên bản Python song song. Tương tự nvm cho Node hoặc fnm. Lý do nên dùng:

  • Một máy có thể cài nhiều Python (3.10, 3.11, 3.12, 3.13) cùng lúc.
  • Mỗi project chọn version riêng qua file .python-version.
  • Không cần sudo. Không đụng system Python.
Terminal — cài pyenv (macOS)
# Cài qua Homebrew
brew install pyenv

# Thêm vào ~/.zshrc (shell zsh mặc định của macOS)
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init -)"' >> ~/.zshrc

# Restart terminal hoặc:
source ~/.zshrc

# Liệt kê tất cả version cài được
pyenv install --list | grep "^  3\." | tail -20

# Cài Python 3.12 (latest patch)
pyenv install 3.12

# Đặt làm default cho toàn user
pyenv global 3.12

# Verify
python --version    # Python 3.12.x
which python        # ~/.pyenv/shims/python (KHÔNG phải /usr/bin/python)

Linux (Ubuntu/Debian) cài pyenv qua script chính thức:

Terminal — pyenv trên Linux
curl https://pyenv.run | bash
# Thêm config vào ~/.bashrc (giống macOS, đổi .zshrc → .bashrc)

2.2. Windows — official installer hoặc pyenv-win

Windows không có "system Python" — bạn phải tự cài. 2 cách:

  • Official installer từ python.org. Cài đặt tick ô "Add Python to PATH". Đơn giản cho người mới.
  • pyenv-win (fork riêng cho Windows) nếu cần quản lý nhiều version. Cài qua PowerShell: Invoke-WebRequest ...
  • WSL2 — nhiều dev Windows hôm nay chạy Linux trên WSL2 rồi cài pyenv như Linux. Trải nghiệm tốt hơn native Windows.

2.3. Cài qua uv — modern alternative (2024+)

uv (do Astral phát hành, cùng team với Ruff) cũng có chức năng cài Python phiên bản bất kỳ, nhanh hơn pyenv rất nhiều (uv viết bằng Rust). Sẽ trở lại uv ở section 7 — nhưng nếu bạn chưa dùng pyenv, có thể bắt đầu thẳng với uv.

Terminal — uv install Python
# Cài uv
curl -LsSf https://astral.sh/uv/install.sh | sh

# uv tự cài Python cho bạn
uv python install 3.12

# Liệt kê Python đã cài
uv python list
💡 Khuyên

Người mới năm 2026: dùng uv nếu OK với tool còn mới. Dùng pyenv nếu muốn tool đã rất ổn định 10+ năm và nhiều tài liệu. Sub-pillar này demo cả hai để bạn tự chọn — xem bảng so sánh và cách chuyển từ pyenv sang uv ở mục 7.2–7.3.

3. REPL — sân chơi đầu tiên

REPL (Read-Eval-Print Loop) là chế độ tương tác. Gõ một biểu thức, nhấn Enter, Python trả về kết quả ngay. Cách nhanh nhất để thí nghiệm syntax mà không cần tạo file.

Terminal — Python REPL
$ python
Python 3.12.1 (main, Dec  7 2023, 21:50:54) [Clang 15.0.0] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 1 + 1
2
>>> name = "Việt"
>>> print(f"Xin chào {name}")
Xin chào Việt
>>> import sys
>>> sys.version_info
sys.version_info(major=3, minor=12, micro=1, releaselevel='final', serial=0)
>>> exit()

Thoát REPL: gõ exit() hoặc nhấn Ctrl + D (macOS/Linux), Ctrl + Z rồi Enter (Windows).

Bonus — IPython, REPL nâng cao

REPL mặc định hơi thô. IPython là REPL Python được "nâng cấp": có syntax highlight, autocomplete, history giữa session, magic command (%timeit, %run, %edit). Cài: pip install ipython. Chạy: ipython. Một khi đã quen, REPL mặc định cảm giác như xe đạp so với xe máy.

4. Hello World — file .py đầu tiên

Tạo file hello.py:

hello.py
print('Xin chào Python')

Chạy:

Terminal
$ python hello.py
Xin chào Python

Đọc command-line argument qua sys.argv:

greet.py
import sys

# sys.argv[0] = đường dẫn file .py
# sys.argv[1:] = các args user truyền
name: str = sys.argv[1] if len(sys.argv) > 1 else 'bạn'
print(f'Xin chào, {name}')
Terminal
$ python greet.py
Xin chào, bạn

$ python greet.py Việt
Xin chào, Việt
📝 Note về type hints

Bạn đã thấy name: str = ... — đó là type hint (PEP 484, 2015). Python không ép buộc type runtime — type hint chủ yếu để IDE và type checker (Pylance, mypy) phân tích. Sub-pillar này bật type hint từ chương 1 vì code Python hiện đại đều như vậy. Chi tiết về type hint ở chương 12.

4.1. Chú thích — # và docstring

Python có hai cơ chế ghi chú khác hẳn nhau về bản chất. # là chú thích thật sự — interpreter bỏ qua hoàn toàn, không tồn tại lúc chạy. Docstring là một chuỗi ký tự đặt ở vị trí đặc biệt — nó là dữ liệu thật, được lưu vào __doc__ và đọc được lúc chạy.

chu_thich.py
# Chú thích một dòng — mọi thứ sau dấu # đều bị bỏ qua

x = 42  # chú thích cuối dòng: cách code ÍT NHẤT 2 dấu cách (PEP 8)

# Python KHÔNG có cú pháp chú thích nhiều dòng như /* ... */ của JS.
# Muốn nhiều dòng thì đặt # ở mỗi dòng.
# Trong editor: bôi đen rồi Cmd+/ (macOS) hoặc Ctrl+/ (Windows/Linux).

"""
Chuỗi ba nháy KHÔNG phải chú thích — nó là một chuỗi thật sự,
chỉ là không được gán cho biến nào nên bị bỏ đi ngay.
Dùng nó làm "chú thích" thì code vẫn chạy, nhưng đây là cách dùng sai.
"""
docstring.py
"""Module docstring — dòng ĐẦU TIÊN của file, mô tả cả module."""

def tinh_bmi(can_nang: float, chieu_cao: float) -> float:
    """Tính chỉ số khối cơ thể (BMI).

    Args:
        can_nang: Cân nặng tính bằng kilogram.
        chieu_cao: Chiều cao tính bằng mét.

    Returns:
        Chỉ số BMI = cân nặng / chiều cao².

    Raises:
        ValueError: Nếu chiều cao nhỏ hơn hoặc bằng 0.
    """
    if chieu_cao <= 0:
        raise ValueError("chiều cao phải lớn hơn 0")
    return can_nang / chieu_cao ** 2


# Docstring đọc được LÚC CHẠY — khác hẳn chú thích #
print(tinh_bmi.__doc__)      # in ra toàn bộ docstring
help(tinh_bmi)              # hiển thị đẹp trong REPL
Chú thích #Docstring """..."""
Tồn tại lúc chạyKhông — bị loại khi biên dịchCó — lưu trong __doc__
Vị tríBất kỳ đâuDòng đầu tiên của module / hàm / class
Trả lời câu hỏiTại sao code làm thế nàyCái gì — dùng ra sao, nhận gì, trả gì
Người đọcNgười sửa code nàyNgười gọi code này
Công cụ đọc đượcKhônghelp(), IDE tooltip, Sphinx, pydoc
ChuẩnPEP 8PEP 257
💡 Chú thích tốt giải thích tại sao, không phải cái gì
tot_va_te.py
# ❌ Vô dụng — code đã nói y hệt rồi
i = i + 1   # tăng i lên 1

# ✅ Có giá trị — giải thích lý do mà code không nói được
time.sleep(0.3)   # API bên đối tác giới hạn 3 request/giây

# ✅ Cảnh báo cho người sau
# KHÔNG đổi sang set: thứ tự ở đây quyết định thứ tự hiển thị cho user.
danh_muc = ["moi", "pho_bien", "gia_re"]

# ✅ Đánh dấu việc còn nợ — IDE và linter nhận diện được TODO/FIXME
# TODO(anh): thay bằng cache Redis khi lượng truy cập vượt 1000/phút

Nếu bạn phải viết chú thích để giải thích code làm gì, thường đó là dấu hiệu nên đặt lại tên biến/hàm cho rõ hơn. Code tự nói được là tốt nhất; chú thích dành cho những gì code không thể nói: lý do, ràng buộc bên ngoài, đánh đổi đã cân nhắc.

🔁 Đối chiếu với JS & Dart

JS: // một dòng, /* ... */ nhiều dòng, /** ... */ JSDoc cho tài liệu — JSDoc chỉ là chú thích, công cụ phải phân tích văn bản mới đọc được.
Dart: //, /* */, và /// cho tài liệu — dartdoc đọc ///.
Python: chỉ có #, không có cú pháp chú thích khối. Đổi lại, docstring là đối tượng thật trong bộ nhớ — help(ham) hoạt động ngay trong REPL mà không cần công cụ ngoài. Đây là điểm Python mạnh hơn cả hai.

5. Virtual environment — vì sao cần?

Đây là khái niệm sống còn của Python ecosystem. Hiểu nó trước khi cài bất kỳ package nào.

Default, khi bạn gõ pip install requests, package requests được cài vào Python interpreter hiện tại. Tức là tất cả project Python trên máy bạn đều thấy requests phiên bản đó.

Bài toán nảy sinh:

🔥 Gotcha — Package conflict

Project A dùng requests==2.0 (2014, API cũ).
Project B dùng requests==2.31 (2023, API mới).
Nếu cài cả hai vào cùng global Python → chỉ giữ được 1 version. Project còn lại vỡ.

Dependency hell phức tạp hơn nữa khi package A cần numpy<1.20 nhưng package B cần numpy>=1.25 — không thể cài đồng thời.

Virtual environment (venv) là thư mục biệt lập chứa một bản Python interpreter riêng + một thư mục site-packages riêng. Mỗi project có venv riêng → package không conflict.

🧠 Mental model

Venv giống "căn hộ riêng" cho mỗi project. Cùng tòa nhà (Python interpreter version), nhưng đồ đạc (package) mỗi căn riêng. Project A xếp đồ kiểu A, project B kiểu B — không ai đụng ai.

Tương đương ở thế giới khác: node_modules/ của Node — mỗi project tự có. Khác ở chỗ Node mặc định local, còn Python mặc định global → bạn phải chủ động tạo venv.

6. Tạo venv với python -m venv

Python 3.3+ có module venv built-in. Lệnh tạo:

Terminal
# Tạo project mới
mkdir my-app && cd my-app

# Tạo venv tên .venv (convention)
python -m venv .venv

# Activate (macOS/Linux)
source .venv/bin/activate

# Activate (Windows PowerShell)
.venv\Scripts\Activate.ps1

# Sau khi activate, prompt sẽ có (.venv) ở đầu:
# (.venv) $ which python
# /Users/you/my-app/.venv/bin/python  (KHÔNG còn là pyenv shim)

# Cài package — chỉ vào venv này
pip install requests

# Deactivate khi xong
deactivate

Cấu trúc venv tạo ra:

.venv/ structure
.venv/
├── bin/                    # Windows: Scripts/
│   ├── activate            # shell script set PATH + prompt
│   ├── python              # symlink hoặc copy interpreter
│   ├── pip
│   └── ...
├── lib/
│   └── python3.12/
│       └── site-packages/  # package cài vào venv này nằm ở đây
└── pyvenv.cfg              # config trỏ tới base Python
⚠️ Đừng commit .venv/

Venv chứa hàng nghìn file binary phụ thuộc OS — không portable, không nên đẩy lên git. Luôn thêm vào .gitignore:

.venv/
__pycache__/
*.pyc
.python-version

Cộng tác viên chỉ cần requirements.txt hoặc pyproject.toml để tự tái tạo venv riêng.

6.1. File .python-version — auto-switch

Nếu bạn dùng pyenv, có thể tạo file .python-version ở gốc project. pyenv tự switch Python khi bạn cd vào.

Terminal
# Tại gốc project
pyenv local 3.12       # tạo .python-version chứa "3.12"

# Verify
cat .python-version    # 3.12.x
python --version       # auto pick 3.12 khi ở folder này

7. uv — tool modern (2024+)

uv là tool quản lý Python + package thế hệ mới, do Astral (team Ruff) phát triển, viết bằng Rust. Mục tiêu: thay thế tất cả các tool cũ (pyenv, virtualenv, pip, pip-tools, poetry, pipx) bằng một binary duy nhất, nhanh hơn 10-100 lần.

uv làm được gì?

  • Cài Python (như pyenv): uv python install 3.12
  • Tạo venv (như virtualenv): uv venv
  • Cài package (như pip): uv pip install requests
  • Quản lý project end-to-end (như poetry): uv init, uv add, uv run
  • Chạy tool standalone (như pipx): uv tool install ruff

7.1. uv init — khởi tạo project mới

Terminal — uv project workflow
# Tạo project mới
uv init my-app
cd my-app

# Cấu trúc sinh ra:
#   my-app/
#   ├── .python-version
#   ├── README.md
#   ├── hello.py
#   └── pyproject.toml

# Thêm dependency
uv add requests

# uv tự: tạo .venv/, resolve dep, cài, ghi vào pyproject.toml + uv.lock

# Chạy file (uv tự activate venv ngầm)
uv run hello.py

# Thêm dev-only dep
uv add --dev ruff pytest
💡 Khuyên cho project mới năm 2026

Dùng uv trừ khi có lý do cụ thể không. Nhanh, tích hợp, lock file deterministic, không phải nhớ activate venv. Kể cả nếu team chưa dùng uv, output pyproject.toml của uv vẫn tương thích với pip.

7.2. pyenv hay uv — chọn cái nào?

Hai tool không loại trừ nhau, nhưng phạm vi khác hẳn: pyenv chỉ quản lý phiên bản Python, còn uv quản lý cả Python lẫn venv, package, lock file. Dùng pyenv thì vẫn cần thêm pip + venv (hoặc poetry); dùng uv thì một binary là đủ.

Tiêu chípyenvuv
Cài nhiều bản PythonCó — biên dịch từ source, mất vài phút mỗi bảnCó — tải bản dựng sẵn, vài giây
Cơ chế chọn bản PythonShim trong ~/.pyenv/shims + sửa PATH trong ~/.zshrcĐọc .python-version / requires-python khi chạy uv run, không cần shim
Tạo virtualenvKhông — dùng python -m venv hoặc pluginuv venv, hoặc tự tạo khi uv add/uv run
Cài packageKhông — dùng pipuv add / uv pip install, nhanh hơn pip 10–100 lần
Lock fileKhônguv.lock — cài lại y hệt trên máy khác
Tool CLI toàn cục (ruff, httpie…)Không — cần pipxuv tool install, uvx
Lệnh python toàn cụcpyenv global 3.12uv python install 3.12 --default
Độ chín10+ năm, tài liệu cũ hầu hết dùng pyenvMới (2024+), phát triển rất nhanh, đã thành mặc định của nhiều team
💡 Quy tắc chọn
  • Project mới, học cá nhân → uv. Một tool, ít cấu hình shell, ít chỗ hỏng.
  • Project cũ của team đang dùng pyenv + pip/poetry → theo team. uv vẫn đọc được .python-version nên chuyển dần được.
  • Không cần giữ cả hai lâu dài: hai cơ chế chọn Python cùng tồn tại dễ làm which python trả về thứ bạn không ngờ.

7.3. Chuyển từ pyenv sang uv

🔥 Gotcha — alias python=python3 che mất mọi thứ

Nhiều hướng dẫn cũ bảo thêm alias python=python3 vào ~/.zshrc cho tiện. Trong zsh, alias được ưu tiên hơn PATH, nên sau khi cài pyenv bạn sẽ thấy:

❯ which python
python: aliased to python3

python không đi qua shim của pyenv (hay qua ~/.local/bin của uv) nữa, mà đi theo python3 đầu tiên tìm thấy trong PATH — có thể là Homebrew hoặc system Python. Cách sửa: xóa/comment alias đó, rồi unalias python; hash -r trong terminal đang mở. Kiểm tra bằng type -a python — lệnh này liệt kê cả alias lẫn mọi file thực thi trên PATH, theo đúng thứ tự shell sẽ chọn.

Quy trình chuyển hẳn sang uv trên macOS:

Terminal — gỡ pyenv, dùng uv
# 1. Cài uv (nếu chưa có) — chọn MỘT cách
curl -LsSf https://astral.sh/uv/install.sh | sh    # cài vào ~/.local/bin
brew install uv                                    # hoặc qua Homebrew

# 2. Cài bản Python bạn cần và đặt làm python mặc định
uv python install 3.12 --default    # tạo python, python3 trong ~/.local/bin

# 3. Xóa cấu hình pyenv trong ~/.zshrc — 3 dòng này:
#   export PYENV_ROOT="$HOME/.pyenv"
#   [[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
#   eval "$(pyenv init -)"

# 4. Gỡ pyenv và các bản Python nó đã cài
brew uninstall pyenv
rm -rf ~/.pyenv                     # xóa luôn mọi Python + package cài qua pyenv

# 5. Mở terminal mới và kiểm tra
type -a python      # ~/.local/bin/python đứng đầu
python --version    # Python 3.12.x
⚠️ Trước khi rm -rf ~/.pyenv

Venv của project nào được tạo từ Python của pyenv sẽ hỏng sau khi xóa, vì .venv/bin/python chỉ là symlink trỏ vào ~/.pyenv/versions/.... Venv không đáng giữ: xóa .venv/ rồi chạy uv sync (nếu có pyproject.toml) hoặc uv venv && uv pip install -r requirements.txt để tạo lại. Đây cũng là lý do không bao giờ commit .venv/ — nó luôn tạo lại được từ manifest.

8. pip cơ bản và PyPI

pip là package installer mặc định của Python (đi kèm Python từ 3.4). PyPI (pypi.org — Python Package Index) là registry chính thức, có hơn 500,000+ package.

Terminal — pip basics
# Cài package vào venv hiện tại
pip install requests
pip install "requests>=2.31,<3"     # pin range version

# Cài nhiều package từ file
pip install -r requirements.txt

# Liệt kê package đã cài
pip list
pip show requests                # info chi tiết một package

# Sinh requirements.txt từ venv hiện tại
pip freeze > requirements.txt

# Gỡ package
pip uninstall requests

# Upgrade pip itself
python -m pip install --upgrade pip

File requirements.txt mẫu:

requirements.txt
requests>=2.31,<3
httpx==0.27.0
pydantic>=2.0
# dev tools (tách file requirements-dev.txt sẽ đẹp hơn)
pytest>=8.0
ruff>=0.4
📝 python -m pip vs pip

Nếu máy bạn có nhiều Python (do pyenv), gõ pip install ... đôi khi gọi nhầm pip của Python khác. Khuyên: dùng python -m pip install ... để chắc chắn pip thuộc Python interpreter hiện tại. Đặc biệt quan trọng khi không activate venv.

9. pyproject.toml — manifest hiện đại

pyproject.toml là format manifest chuẩn của Python, định nghĩa trong PEP 518 (2016) và PEP 621 (2020). Tương đương package.json của Node, pubspec.yaml của Dart.

Mẫu cơ bản (uv init sinh sẵn):

pyproject.toml
[project]
name = "my-app"
version = "0.1.0"
description = "Dự án Python đầu tiên"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
    "requests>=2.31",
    "pydantic>=2.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=8.0",
    "ruff>=0.4",
]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
FieldVai trò
nameTên project. Nếu publish PyPI phải unique.
versionSemVer.
requires-pythonPython version tối thiểu. Tool resolver dùng để check.
dependenciesPackage runtime. Tương đương dependencies của npm.
optional-dependenciesGroup dep cho dev/test/docs. Cài qua pip install -e .[dev].
build-systemBackend dùng để build wheel khi publish.
↔️ So với npm

pyproject.toml ≈ package.json nhưng dùng TOML thay JSON. Cú pháp TOML dễ đọc hơn JSON (cho phép comment, ít dấu ngoặc). Nhược điểm: không có "scripts" tích hợp như npm — phải dùng tool ngoài (just, uv run, hoặc define entry point trong [project.scripts]).

10. PEP 8 và Zen of Python — kim chỉ nam

PEP = Python Enhancement Proposal. Là tài liệu chính thức đề xuất tính năng / quy chuẩn cho ngôn ngữ. Hai PEP quan trọng nhất cho người mới:

  • PEP 8 — Style Guide for Python Code. Định nghĩa quy ước: 4 space indent (không tab), snake_case cho biến/function, PascalCase cho class, dòng ≤ 79 (hoặc 88-100) ký tự, 2 dòng trống giữa hàm top-level, v.v.
  • PEP 20 — The Zen of Python. Đã trích ở section 1.3. Đọc bằng import this.

Thử ngay trong REPL:

Python REPL
>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is right to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of them!

Bạn không cần thuộc lòng PEP 8 — dùng tool format tự động như ruff hoặc black để máy ép code theo chuẩn. Sub-pillar này dùng ruff (cũng của Astral, Rust, nhanh).

11. IDE setup — VS Code hoặc PyCharm

2 lựa chọn chính:

VS Code + Python extension (khuyên cho người mới)

Miễn phí, nhẹ, multi-language. Cài extension "Python" của Microsoft → tự kèm Pylance (language server siêu nhanh, type-aware) và debugger. Settings nên bật:

  • "python.analysis.typeCheckingMode": "strict" — Pylance check type hint nghiêm khắc.
  • "editor.formatOnSave": true + cài extension Ruff để auto format.
  • Chọn interpreter đúng: Command Palette → "Python: Select Interpreter" → chọn .venv/bin/python.

PyCharm Community / Pro

IDE riêng cho Python của JetBrains. Community miễn phí, đủ cho học. Pro có thêm support web framework, database, remote dev (trả phí). Nặng hơn VS Code nhưng tích hợp sâu hơn (vd: debugger graphic, refactoring tool mạnh).

12. Python có "compile" không?

Câu trả lời ngắn: Có, nhưng không phải kiểu bạn đang nghĩ.

Python không compile sang executable (binary chạy độc lập) như C, Go, hoặc Dart AOT. Bạn không thể ./hello như C. Bạn phải gõ python hello.py — cần Python interpreter có mặt.

Tuy nhiên, ngầm trong runtime, Python có compile sang bytecode (.pyc) trung gian, được Python Virtual Machine (PVM) thực thi. Bytecode được cache trong thư mục __pycache__/:

Terminal — quan sát __pycache__
# Sau khi import một module Python lần đầu
$ python -c "import mymodule"

# __pycache__ xuất hiện cạnh file .py
$ ls __pycache__/
mymodule.cpython-312.pyc

# Đây là bytecode cache cho Python 3.12
# Lần import sau Python skip parse + compile lại, dùng cache
↔️ So với Dart, Go, C

C / Go: compile AOT (Ahead-of-Time) → executable binary chạy độc lập, không cần runtime hỗ trợ (Go có runtime nhỏ bundled).
Dart: hai chế độ — JIT (dev) và AOT (production, compile Flutter app sang native).
Java: compile sang JVM bytecode, JVM JIT lúc chạy.
Python: compile ngầm sang Python bytecode khi import, PVM thực thi. KHÔNG có AOT chính thống (có tool ngoài như PyInstaller, Nuitka nhưng không thuộc CPython core).
JavaScript: JIT trong V8/SpiderMonkey, không cần file bytecode trên đĩa.

🧠 Mental model

Hỏi: "Python là ngôn ngữ thông dịch (interpreted) hay biên dịch (compiled)?" Câu trả lời chính xác: compiled-to-bytecode, interpreted-by-VM. Giống Java. Không phải "ngôn ngữ thông dịch thuần" như BASIC cổ xưa, cũng không phải "ngôn ngữ biên dịch" như C.

__pycache__/ — có commit không?

Không. Bytecode tự sinh, phụ thuộc Python version (3.11 .pyc khác 3.12 .pyc). Thêm vào .gitignore:

.gitignore
__pycache__/
*.pyc
*.pyo
.venv/
.python-version
.ruff_cache/
.mypy_cache/

13. Cheat sheet chương 1

Tình huốngLệnh / cách làm
Cài Python (macOS, pyenv)brew install pyenv && pyenv install 3.12
Cài Python (uv way)uv python install 3.12
Mở REPLpython · thoát exit() hoặc Ctrl+D
Chạy filepython file.py
Tạo venv built-inpython -m venv .venv && source .venv/bin/activate
Tạo venv (uv)uv venv (auto-detect Python version)
Cài package (pip)pip install requests
Cài package (uv)uv add requests
Sinh requirements.txtpip freeze > requirements.txt
Init project hiện đạiuv init my-app
Đọc Zen of Pythonpython -c "import this"
Đọc args CLIsys.argv[1:]

Bài tập

Bài 1 — Cài Python 3.12 qua pyenv

Cài pyenv (hoặc uv nếu Windows), rồi cài Python 3.12. Verify:

  • python --version → in Python 3.12.x
  • which python (macOS/Linux) → trỏ tới shim của pyenv, KHÔNG phải /usr/bin/python
  • Mở REPL, gõ import sys; sys.version_info — screenshot kết quả.
Gợi ý

macOS: brew install pyenv. Thêm 3 dòng config vào ~/.zshrc như section 2.1. Restart terminal. pyenv install 3.12. pyenv global 3.12.

Nếu which python vẫn ra /usr/bin/python, là pyenv chưa được nạp PATH — kiểm tra lại config zshrc.

Bài 2 — Venv built-in + requests

Trong thư mục mới, tạo venv built-in, activate, cài requests. Viết file fetch.py gửi GET đến https://httpbin.org/get và in JSON response.

Test: python fetch.py phải in dict có field "url", "origin".

Đáp án
# Setup
mkdir fetch-demo && cd fetch-demo
python -m venv .venv
source .venv/bin/activate
pip install requests
# fetch.py
import requests

response = requests.get("https://httpbin.org/get")
print(response.json())

Nếu lỗi ModuleNotFoundError: requests → bạn quên activate venv, hoặc activate sai shell. Check which python phải trỏ tới .venv/bin/python.

Bài 3 — uv init + greet.py

Cài uv nếu chưa có. Tạo project mới với uv init greeter. Viết file greet.py đọc tên từ sys.argv, in greeting kiểu "Xin chào, [tên]". Nếu không có arg → default "bạn".

Chạy qua: uv run greet.py và uv run greet.py Việt.

Đáp án
# greet.py
import sys

name: str = sys.argv[1] if len(sys.argv) > 1 else "bạn"
print(f"Xin chào, {name}")

uv run tự tạo venv ngầm + cài dep từ pyproject.toml + chạy script. Không cần activate thủ công.

Bài 4 — Đọc pyproject.toml của 3 package nổi tiếng

Mở trang PyPI của 3 package: requests, httpx, pytest. Mỗi package, vào repo GitHub, mở pyproject.toml (nếu không có thì setup.cfg). Ghi note:

  • name + version hiện tại
  • requires-python tối thiểu là gì
  • 3-5 dependencies chính
  • Build backend dùng gì (hatchling, setuptools, poetry-core...)

So sánh: 3 package có cùng style cấu trúc pyproject.toml không? Khác chỗ nào?

Gợi ý đọc

Links: github.com/psf/requests, github.com/encode/httpx, github.com/pytest-dev/pytest.

Bạn sẽ thấy: requests dùng setuptools (legacy), httpx dùng hatchling (modern), pytest dùng setuptools. Đây là transition tự nhiên — không phải mọi project Python đều cùng style ở 2026.

Bài 5 — Zen of Python: pick 3 nguyên tắc

Mở REPL Python, chạy import this. Đọc 19 nguyên tắc. Chọn 3 nguyên tắc bạn cảm thấy có ý nghĩa nhất với mình. Với mỗi nguyên tắc, viết 1-2 câu giải thích vì sao:

  • Bạn hiểu nguyên tắc đó nghĩa là gì?
  • Bạn đã từng vi phạm nó trong code cũ của mình không? Ví dụ.
  • Áp dụng nguyên tắc đó sẽ thay đổi cách bạn viết code thế nào?
Ví dụ gợi ý

"Explicit is better than implicit" — Khi viết code, nên rõ ràng ý đồ thay vì dựa vào ngầm hiểu. Ví dụ: thay vì x = func() mà không biết func trả gì, nên dùng type hint: x: User = get_current_user().

"Readability counts" — Code đọc nhiều hơn viết. Biến tên rõ ràng (user_age không phải ua), function ngắn, comment chỗ phức tạp.

"There should be one obvious way to do it" — Đối lập với Perl/JS "TIMTOWTDI". Trong Python, nếu thấy 2 cách viết, thường có 1 cách "Pythonic" hơn. Đó là cách nên chọn.

Quiz

Q1

macOS / Ubuntu đều có sẵn Python. Tại sao không dùng để phát triển?

Xem đáp án
✓ Đáp án

System Python được OS và một số tool hệ thống phụ thuộc vào. Nếu bạn cài/gỡ package lung tung qua pip install (đặc biệt với sudo) có thể phá hỏng tool đó — kết quả khó debug, có khi vỡ luôn Homebrew hoặc apt.

Ngoài ra, system Python version bị OS lock — vd macOS 14 vẫn Python 3.9 (lạc hậu, không có match/case, không có exception group...). Bạn không nâng cấp được mà không nâng cấp OS.

Giải pháp: cài Python riêng cho dev qua pyenv hoặc uv — biệt lập, nâng cấp dễ.

Q2

Virtual environment (venv) giải quyết bài toán gì?

Xem đáp án
✓ Đáp án

Package conflict giữa nhiều project.

Default, pip install cài vào global site-packages của Python — tất cả project chia sẻ. Nếu project A cần requests==2.0, project B cần requests==2.31 → cài cả hai chỉ giữ được 1 version, project còn lại vỡ.

Venv tạo thư mục biệt lập (vd .venv/) với site-packages riêng. Mỗi project có "vũ trụ" package riêng, không đụng nhau. Đồng thời không đụng system Python.

Q3

pip và uv khác nhau ở những điểm nào?

Xem đáp án
✓ Đáp án

3 khác biệt chính:

  • Tốc độ: uv viết bằng Rust, nhanh hơn pip 10-100 lần (đặc biệt khi resolve dependency graph lớn). pip viết bằng Python, tốc độ giới hạn bởi GIL + I/O sync.
  • Scope: pip chỉ cài/gỡ package. uv làm hết: cài Python version (như pyenv), tạo venv (như virtualenv), quản lý project (như poetry), chạy tool standalone (như pipx).
  • Lock file: pip không có lock file built-in (phải dùng pip-tools hoặc pip freeze). uv tự sinh uv.lock deterministic, giống package-lock.json.

Cả hai đọc/ghi cùng pyproject.toml chuẩn → có thể switch giữa pip và uv mà không đập project.

Q4

File .python-version ở gốc project có vai trò gì?

Xem đáp án
✓ Đáp án

File text chứa 1 dòng version Python (vd 3.12.1). Được sinh bởi pyenv local 3.12 hoặc uv init.

Khi bạn cd vào thư mục đó, pyenv (hoặc uv) đọc file này và tự switch sang Python version chỉ định cho session đó. Bạn không phải nhớ activate hay gõ pyenv use ....

Nên commit file này lên git → cộng tác viên clone về cũng dùng đúng Python version.

Q5

Python có "compile" không? Trả lời chính xác.

Xem đáp án
✓ Đáp án

Có, nhưng không sang executable binary. Python compile ngầm sang bytecode (.pyc) khi import module, cache vào thư mục __pycache__/. Bytecode được thực thi bởi Python Virtual Machine (PVM).

Khác C/Go: không tạo ra binary chạy độc lập. Bạn vẫn cần Python interpreter (CPython) cài trên máy mới chạy được file .py.

Khái niệm chính xác: Python là ngôn ngữ compiled-to-bytecode, interpreted-by-VM. Tương tự Java (compile sang JVM bytecode), khác C (compile sang machine code), khác BASIC cổ (thuần interpret line-by-line).

Q6

Khi nào nên dùng python -m pip install ... thay vì pip install ...?

Xem đáp án
✓ Đáp án

Khi máy có nhiều Python interpreter cùng lúc (do pyenv, uv, hoặc Homebrew). Gõ pip trần có thể gọi pip của Python khác với python bạn đang gõ — tạo confusion: tưởng đã cài package mà import vào không thấy.

python -m pip install ... chắc chắn dùng pip thuộc chính Python interpreter hiện tại. Đây là cách Python team khuyên dùng (PEP 8 không nhắc, nhưng docs chính thức có).

Khi đã activate venv rồi thì 2 cách tương đương — vì PATH đã trỏ pip vào venv. Nhưng giữ thói quen python -m pip là an toàn hơn.

Q7

Có nên commit thư mục .venv/ lên git không? Lý do?

Xem đáp án
✓ Đáp án

Không. 3 lý do:

  • .venv/ chứa binary phụ thuộc OS — venv tạo trên macOS không chạy được trên Windows hay Linux. Đẩy lên git là vô nghĩa.
  • Size lớn — venv với numpy + pandas có thể vài trăm MB. Git repo sẽ phình ra rất nhanh.
  • Không reproducible — venv là output của pip install, không phải source. Source là pyproject.toml hoặc requirements.txt.

Cách đúng: commit pyproject.toml (declaration) + uv.lock hoặc requirements.txt (resolved version). Cộng tác viên clone về tự chạy uv sync hoặc pip install -r requirements.txt để tái tạo venv riêng.

Tổng kết

Sau chương 1, bạn nên đã nắm:

  • Python landscape: ngôn ngữ 35 tuổi, BDFL → Steering Council, thống trị data/AI/scripting.
  • Cài đúng cách: KHÔNG dùng system Python; dùng pyenv hoặc uv.
  • REPL: sân chơi nhanh nhất để thí nghiệm syntax; biết IPython như upgrade.
  • Virtual environment: cô lập package từng project — không phải tùy chọn, mà là bắt buộc.
  • pip vs uv: pip mặc định, uv hiện đại nhanh hơn. pyproject.toml là manifest chuẩn.
  • Zen of Python: 19 nguyên tắc dẫn dắt cách viết code. Đọc, hiểu, ngấm dần.
  • Compile mode: bytecode trong __pycache__, không tạo executable AOT.
🧠 Câu hỏi tự kiểm tra

Khi mở terminal mới và gõ python --version, bạn có biết Python đó nằm ở đâu (which python) và thuộc cơ chế quản lý nào (system / pyenv / uv / Homebrew)? Nếu trả lời được, bạn đã qua được pitfall lớn nhất của người mới Python. Nếu không, quay lại section 2.

Kết nối tới các chương khác

Mọi chương sau giả định bạn đã có Python 3.12+ chạy được và biết venv. Cụ thể:

  • Chương 2 (Variables, Types & Operators) — bắt đầu syntax thực sự: biến, kiểu, toán tử. Type hint sẽ được dùng từ ví dụ đầu tiên.
  • Chương 4 (Functions) — đào sâu sys.argv, *args, **kwargs.
  • Chương 12 (Typing & Static Analysis) — toàn bộ hệ thống type hint, Pylance strict mode, Protocol, Generic.
  • Trụ cột CLI — pyenv, venv là cấp độ tool CLI. Nếu chưa quen terminal/shell, đọc trụ cột CLI trước.
  • Trụ cột DevOps — Python application thường được package qua Docker (multistage build với python:3.12-slim). Chương DevOps có example với Python.