14 điểm bởi GN⁺ 2025-07-22 | 7 bình luận | Chia sẻ qua WhatsApp
  • Khi dùng uv, việc quản lý phụ thuộc được tự động hóa khi chạy script Python
  • Không cần quản lý môi trường ảo riêng, môi trường cho từng script sẽ được tự động tạo và duy trì
  • Có thể khai báo các gói cần thiết bằng nhiều cách như inline metadata hoặc tùy chọn dòng lệnh
  • Việc quản lý gói và phiên bản Python cũng có thể được khai báo theo từng script và tự động điều chỉnh
  • Có thể tăng tính tái lập và khả năng bảo trì bằng file lock cùng các tùy chọn giới hạn phiên bản phụ thuộc

Tổng quan

  • uv là công cụ tự động quản lý các phụ thuộc gói mà một script Python cần khi chạy script đó
  • Người dùng không cần tự thực hiện các bước phiền phức như tạo môi trường ảo hay cài đặt gói
  • Công cụ cung cấp nhiều tùy chọn chạy, cách dùng inline metadata, nhiều phương thức khai báo phụ thuộc và các tính năng kiểm soát khác nhau

Môi trường Python và vai trò của uv

  • Python có môi trường riêng biệt cho từng lần cài đặt
  • Thông thường, việc tạo và quản lý môi trường ảo là điều được khuyến nghị
  • uv tự động quản lý môi trường ảo và xử lý phụ thuộc theo cách khai báo
  • Với script đơn giản, có thể chạy ngay bằng uv run example.py
  • Nếu chỉ dùng thư viện chuẩn thì sẽ hoạt động mà không cần cấu hình thêm

Truyền tham số và cách nhập dữ liệu

  • Có thể truyền tham số dòng lệnh cho script
  • Cũng hỗ trợ nhận trực tiếp mã script từ đầu vào chuẩn hoặc dùng tính năng here-document

Môi trường dự án và tùy chọn --no-project

  • Nếu script được chạy trong thư mục dự án (ví dụ nơi có pyproject.toml), các phụ thuộc của dự án cũng sẽ được cài đặt
  • Nếu không cần, có thể đặt cờ --no-project trước tên script để bỏ qua môi trường dự án

Khai báo và quản lý phụ thuộc của script

  • Nếu cần gói bên ngoài, có thể chạy script bằng cách chỉ định phụ thuộc với tùy chọn dòng lệnh --with
  • Cũng hỗ trợ ràng buộc phiên bản cụ thể, và có thể chỉ định nhiều phụ thuộc bằng cách lặp lại tùy chọn này
  • Có thể thêm phụ thuộc bổ sung trong môi trường dự án, và nếu không muốn thì có thể kiểm soát bằng --no-project

Inline Script Metadata (chuẩn PEP 723)

  • Python hiện hỗ trợ định dạng chuẩn để khai báo phụ thuộc hoặc phiên bản Python ngay trong chính script
  • Có thể dễ dàng tạo script chứa inline metadata bằng uv init --script
  • Có thể thêm và quản lý các phụ thuộc cần thiết cho script ở định dạng TOML bằng uv add --script
  • Nếu có inline metadata, phụ thuộc của dự án sẽ bị bỏ qua và chỉ áp dụng phụ thuộc của script

Khai báo và quản lý phiên bản Python

  • Có thể chỉ định phiên bản Python mong muốn trong script hoặc tại thời điểm chạy
  • Nếu phiên bản được chỉ định chưa có, nó sẽ tự động được tải xuống và thiết lập

Viết script có thể chạy trực tiếp bằng shebang

  • Có thể dùng shebang (#!...) để tạo tệp thực thi trực tiếp theo cách uv run --script
  • Khi đó, việc khai báo phụ thuộc và phiên bản Python cũng có thể đặt ở đầu script

Hỗ trợ chỉ mục gói và xác thực

  • Có thể dùng chỉ mục gói tùy chỉnh với tùy chọn --index
  • Thông tin index cũng được đưa vào metadata
  • Nếu cần xác thực, có thể tham khảo tài liệu riêng

Khóa phụ thuộc (Lock) và tăng khả năng tái lập

  • Có thể tạo và quản lý file lock ở cấp độ script bằng uv lock --script
  • Sau đó khi chạy hoặc thêm phụ thuộc, file lock sẽ được tái sử dụng và cập nhật khi cần
  • Có cung cấp tùy chọn exclude-newer để đảm bảo khả năng tái lập phiên bản bằng cách loại trừ các bản phát hành sau một ngày cụ thể
  • Ngày được chỉ định bằng dấu thời gian RFC 3339

Tính linh hoạt của phiên bản Python

  • Ở mỗi lần chạy, có thể chỉ định dùng bất kỳ phiên bản Python nào bằng tùy chọn dòng lệnh
  • Ví dụ: uv run --python 3.10 example.py

Hỗ trợ Windows

  • Các script có phần mở rộng .pyw sẽ được chạy bằng pythonw trên Windows
  • Các script giao diện GUI cũng có thể chạy cùng với phụ thuộc

Tài liệu tham khảo

  • Có thể tham khảo tài liệu CLI và hướng dẫn chạy/cài đặt công cụ để biết cách dùng lệnh chi tiết hơn

Kết luận

  • uv là công cụ giúp tự động và đơn giản hóa việc quản lý môi trường chạy, phụ thuộc, phiên bản, chỉ mục gói và khả năng tái lập của script Python, từ đó đồng thời nâng cao năng suấtđộ tin cậy

7 bình luận

 
ihabis02 2025-07-24

Tôi cũng đã chuyển từ pip sang uv, và đúng là chỉ riêng tốc độ cực nhanh thôi cũng đã đủ đáng để chuyển rồi.

 
idunno 2025-07-23

Bài này xuất hiện khá thường xuyên nên hôm qua tôi mới thử dùng lần đầu.. thật sự rất nhanh. Trời ơi..

 
ytuniverse 2025-07-23

Có vẻ tôi đã thấy hơn 5 bài viết liên quan đến uv ở đây rồi;;;

 
pmc7777 2025-07-23

Bỏ qua các tính năng khác, chỉ riêng tốc độ thôi cũng đã là lý do đủ để dùng.
Nếu bảo quay lại dùng pip thì gần như là tôi không thể chịu nổi nữa.

Tôi đang thay phần quản lý gói hệ thống của conda bằng flake.nix, và ngoài các dự án cộng tác hoặc những dự án hiện có vốn được bảo trì bằng conda+pip, về mặt cá nhân có lẽ từ nay tôi sẽ dùng uv+nix.

 
ndrgrd 2025-07-22

Gần đây tôi đã thay thế hầu hết việc chạy Python bằng uv, và nó thực sự rất nhanh.
Dù có một vài tính năng nâng cao chưa tương thích hoàn toàn, nhưng trong đa số trường hợp nó hoạt động gần như giống hệt.

 
GN⁺ 2025-07-22
Ý kiến trên Hacker News
  • Đã trải nghiệm và thấy tính năng "khai báo phụ thuộc cho script" thực sự rất hữu ích
    Như được giới thiệu trong tài liệu hướng dẫn chính thức, có thể khai báo các phụ thuộc bằng chú thích ở đầu mã Python như sau

    # /// script
    # dependencies = [
    #  "requests<3",
    #  "rich",
    # ]
    # ///
    import requests, rich
    # ... script
    

    Lưu tệp này thành script.py rồi chạy bằng uv run script.py, các phụ thuộc đã khai báo sẽ được cài vào một môi trường ảo tạm thời như có phép màu và có thể chạy ngay lập tức
    Đây là một triển khai của PEP 723 trong Python, và Claude 4 cũng biết mẹo này, nên nếu prompt kiểu “hãy viết một script Python có phụ thuộc inline” thì nó sẽ tạo đúng
    Ví dụ có thể yêu cầu viết mã dùng httpx và click để tải xuống tệp lớn và hiển thị thanh tiến trình
    Trước thời Claude 4, để làm kiểu này cần một dự án tùy chỉnh và hướng dẫn riêng, nhưng giờ thì không còn như vậy nữa
    Cũng có thể tham khảo các trường hợp sử dụng chi tiết

    • Cũng cảm thấy chế độ shebang thực sự rất hữu ích
      Nếu thêm shebang ở dòng đầu của script như dưới đây thì có thể chạy kiểu ./script.sh

      #!/usr/bin/env -S uv run --script
      # /// script
      # dependencies = [
      #  "requests<3",
      #  "rich",
      # ]
      # ///
      import requests, rich
      # ... script
      
    • Mong là nó có thể dùng cùng định dạng với file requirements
      Nếu vậy thì với người dùng không có uv, cũng có thể cung cấp một chú thích đơn giản kèm one-liner để cài tương tự bằng pip
      Chẳng hạn có vẻ có thể tiếp cận theo kiểu pip install -r <(head myscript.py)

    • Thực tế thì PEP723 hiện không chỉ được uv, vốn đang rất được chú ý gần đây, hỗ trợ mà còn được pipx và hatch hỗ trợ
      Ngoài ra pip-tools v.v. cũng đã có trong roadmap hỗ trợ
      (xem issue liên quan)

    • Lần đầu nhìn thấy, đã từng tưởng bên cạnh requests là emoji trái tim

    • Tôi nghĩ cách này thực sự rất hay
      Nhưng mong rằng một ngày nào đó nó sẽ được đưa vào cú pháp ngôn ngữ tích hợp sẵn thay vì là magic comment
      Comment trông hơi lộn xộn
      Tất nhiên tôi cũng hiểu rằng với góc nhìn công cụ thì magic comment dễ parse hơn, và còn có những cân nhắc mang tính cấu trúc như Python core không có nhiều kiến thức về packaging, nhưng vẫn hy vọng một ngày nào đó sẽ có cú pháp tích hợp sẵn

  • Tôi đồng cảm với cách làm này
    Python không bắt buộc phải có file requirements.txt, nhưng thật đáng tiếc là nếu quản lý lỏng lẻo thì thường xuyên phát sinh sự bất tiện khi chức năng bị hỏng
    Xem tweet liên quan

  • Muốn chia sẻ một cái bẫy tôi gặp phải với cách này
    Tôi đã dùng nó cho một script khởi động lại router khi mất Internet, nhưng vì thao tác cài phụ thuộc phụ thuộc vào kết nối Internet nên khi mạng không hoạt động, bản thân script cũng không thể chạy
    Tôi đã phát hiện sớm và giải quyết bằng cách cài sẵn phụ thuộc, nhưng khuyên mọi người đừng mắc sai lầm như tôi và đừng dùng nó trong môi trường airgapped thực sự (môi trường bị cô lập mạng hoàn toàn)
    Ngay cả khi có cache của uv, vẫn có thể bị cache miss

    • Khi dùng tùy chọn uv run --offline, có thể tận dụng các phụ thuộc đã được cache để chạy mà không cần kiểm tra phiên bản mới
      Tính năng tương tự cũng hoạt động với uvx (uvx --offline ...)

    • Tôi hiểu là nếu có dùng phụ thuộc hoặc venv thì ít nhất phải chạy một lần khi có Internet, rồi sau đó mới có thể dùng offline

  • Gần đây tôi có cảm giác nhiều tính năng trong hệ sinh thái Python đang ngày càng ăn khớp với nhau tốt hơn
    Với sự kết hợp của Marimo và phụ thuộc script của uv, tôi bắt đầu tạo các công cụ báo cáo/chẩn đoán có tính tái lập, phù hợp để các nhóm khác sử dụng

  • Đây là tính năng tôi thích nhất của uv, đến mức vì nó mà tôi chuyển sang dùng uv
    Nhiều script git-hooks có phụ thuộc riêng, và tôi không muốn cài chúng vào venv chính
    Chỉ cần thêm một dòng #!/usr/bin/env -S uv run --script --python 3.13, rồi với dev chỉ cần hướng dẫn brew install uv, và có thể dùng trực tiếp trong script mà không cần tạo venv riêng

    • Có ai biết vì sao cần cờ -S không
      Trên môi trường BSD của tôi, cả /usr/bin/env -S uv run --python 3.11 python/usr/bin/env uv run --python 3.11 python đều chạy Python shell nên tôi cảm thấy kết quả như nhau
      Tôi cũng không diễn giải rõ được từ trang manual của env, nên nếu ai có thông tin hữu ích thì rất muốn nghe
      (-S ở đây có vai trò tách đối số theo khoảng trắng)

    • Nhờ UV mà kế hoạch ban đầu chuyển một đợt migrate Python quy mô lớn sang golang của chúng tôi đã có thể thu hẹp lại
      Đặc biệt là các tác vụ dạng script nhỏ thì không còn cần phải chuyển nữa

    • Tôi thực sự tin đây là một tính năng ‘killer’

  • Nếu trong phụ thuộc có Pytorch thì cách này có thể hơi bị hạn chế
    Uv cung cấp hỗ trợ tích hợp khá tốt cho Pytorch, nhưng chỉ với header của script thì hơi tiếc là không có cách rõ ràng để chọn wheel index phù hợp nhất (CPU, CUDA, ROCm, v.v.)

  • Mong là VS Code có thể dễ dàng nhận diện venv do uv tự động tạo ra
    Hiện tại Python extension đang gạch đỏ toàn bộ import từ bên thứ ba
    Giải pháp tạm thời là tìm thủ công đường dẫn venv trong thư mục Cache của uv rồi đăng ký, nhưng nếu venv thường xuyên bị tạo lại thì lại phải lặp lại, khá phiền

    • Có thể tìm đường dẫn env bằng lệnh uv python find --script "${filePath}"
      Tôi đang phát triển một extension để VS Code tự động phát hiện và kích hoạt tính năng đó
  • Tôi cực kỳ thích tính năng này của UV
    Ngay cả jupyter notebook cũng có thể chạy bằng one-liner như sau mà không cần cài riêng

    uv run --with jupyter jupyter notebook
    

    Mọi thứ được cài vào môi trường ảo tạm thời, rồi sau đó được dọn dẹp sạch sẽ
    Nếu chạy trong một dự án thì nó cũng tự động nhận diện các phụ thuộc của dự án đó

    • Tuy vậy, cũng không hẳn là được dọn dẹp ‘sạch hoàn toàn’, vì thư mục cache của uv có thể tiếp tục phình to

    • Tôi cũng thường xuyên dùng theo kiểu uv run --with ipython --with boto3 ipython, và nó thực sự giúp tiết kiệm rất nhiều thời gian

  • Gần đây tôi phát hiện một vấn đề nhỏ liên quan đến uv run
    Nếu chạy script từ bên ngoài thư mục dự án, nó sẽ tìm pyproject.toml trong thư mục làm việc hiện tại thay vì vị trí thực của tệp script
    Vì vậy script lưu phụ thuộc trong pyproject.toml có thể không hoạt động đúng nếu chạy từ bên ngoài theo kiểu uv run path/to/my/script.py
    Hiện tượng này có thể giải quyết bằng cách luôn dùng phụ thuộc inline hoặc dùng tham số --project, nhưng như vậy phải nhập đường dẫn script hai lần nên khá bất tiện
    Bản thân uv thì rất tuyệt, nhưng đặc điểm nhỏ này lại gây khó chịu đáng kể

  • Tôi đã dùng khá hài lòng cách shebang dành riêng cho uv và phụ thuộc trong script
    Thêm vào đó, việc có thể tạo cả file lock dành riêng cho một script duy nhất bằng lệnh uv lock --script example.py lại càng gây ấn tượng
    Python packaging đã kéo dài hơn 20 năm mà giờ trải nghiệm tự nhiên như thế này mới xuất hiện, thật đáng ngạc nhiên

    • Tôi tò mò về các trường hợp sử dụng của việc tạo lock cho một script đơn lẻ
      Trong tổ chức của chúng tôi, chúng tôi còn dùng phụ thuộc trong lockfile để quét bằng trivy fs uv.lock, nhằm ngăn việc chạy mã có CVE đã biết