14 คะแนน โดย GN⁺ 2025-07-22 | 7 ความคิดเห็น | แชร์ทาง WhatsApp
  • เมื่อใช้ uv จะช่วยทำให้ การจัดการ dependency เป็นอัตโนมัติขณะรันสคริปต์ Python
  • โดยไม่ต้องจัดการ virtual environment แยกต่างหาก ระบบจะสร้างและดูแล environment ให้โดยอัตโนมัติในระดับสคริปต์
  • สามารถประกาศแพ็กเกจที่ต้องใช้ได้หลายวิธี เช่น inline metadata หรือออปชันบนบรรทัดคำสั่ง
  • การจัดการ เวอร์ชัน Python และแพ็กเกจก็สามารถประกาศในระดับสคริปต์และปรับให้อัตโนมัติได้เช่นกัน
  • ใช้ ไฟล์ lock และตัวเลือกจำกัดเวอร์ชัน dependency เพื่อเพิ่มความสามารถในการทำซ้ำสภาพแวดล้อมและการบำรุงรักษา

ภาพรวม

  • uv เป็นเครื่องมือที่ช่วยจัดการ package dependency ที่สคริปต์ต้องใช้โดยอัตโนมัติขณะรันสคริปต์ Python
  • ผู้ใช้จึงไม่จำเป็นต้องสร้าง virtual environment หรือ ติดตั้งแพ็กเกจ ด้วยตนเองซึ่งค่อนข้างยุ่งยาก
  • รองรับออปชันการรันหลายแบบ การใช้งาน inline metadata วิธีประกาศ dependency ที่หลากหลาย และฟังก์ชันควบคุมต่างๆ

สภาพแวดล้อม Python และบทบาทของ uv

  • Python แต่ละการติดตั้งจะมี สภาพแวดล้อมเฉพาะของตัวเอง
  • โดยทั่วไปแนะนำให้สร้างและจัดการ virtual environment
  • uv จะจัดการ virtual environment ให้อัตโนมัติ และดูแล dependency ในรูปแบบ declarative
  • สคริปต์ง่ายๆ สามารถรันได้ทันทีด้วย uv run example.py
  • หากใช้ standard library ก็ทำงานได้โดยไม่ต้องตั้งค่าเพิ่มเติม

การส่งอาร์กิวเมนต์และรูปแบบการรับอินพุต

  • สามารถส่ง อาร์กิวเมนต์บรรทัดคำสั่ง ให้กับสคริปต์ได้
  • รองรับการรับโค้ดสคริปต์จาก standard input เพื่อรันโดยตรง รวมถึงรองรับ here-document

สภาพแวดล้อมโปรเจกต์และออปชัน --no-project

  • หากสคริปต์ถูกรันใน โฟลเดอร์โปรเจกต์ (เช่น มี pyproject.toml) dependency ของโปรเจกต์จะถูกติดตั้งด้วย
  • หากไม่ต้องการ สามารถใส่แฟล็ก --no-project ไว้หน้าชื่อสคริปต์เพื่อ ละเว้น สภาพแวดล้อมของโปรเจกต์ได้

การประกาศและจัดการ dependency ของสคริปต์

  • หากต้องใช้แพ็กเกจภายนอก สามารถระบุ dependency ผ่านออปชันบรรทัดคำสั่ง --with แล้วรันได้
  • รองรับเงื่อนไขจำกัดเวอร์ชันเฉพาะ และสามารถระบุหลาย dependency ได้โดยใส่ออปชันซ้ำ
  • สามารถเพิ่ม dependency เพิ่มเติมทับบนสภาพแวดล้อมโปรเจกต์ได้ และหากไม่ต้องการก็ใช้ --no-project เพื่อควบคุมได้

Inline Script Metadata (รูปแบบ PEP 723)

  • ตอนนี้ Python รองรับฟอร์แมตมาตรฐานสำหรับประกาศ dependency หรือเวอร์ชัน Python ไว้ในตัวสคริปต์เอง
  • สามารถสร้างสคริปต์ที่มี inline metadata ได้อย่างง่ายดายด้วย uv init --script
  • สามารถใช้ uv add --script เพื่อเพิ่มและจัดการ dependency ที่สคริปต์ต้องใช้ในรูปแบบ TOML
  • หากมี inline metadata ระบบจะ ไม่สนใจ dependency ของโปรเจกต์ และใช้เฉพาะ dependency ของสคริปต์เท่านั้น

การประกาศและจัดการเวอร์ชัน Python

  • สามารถระบุ เวอร์ชัน Python ที่ต้องการได้ทั้งในสคริปต์หรือขณะสั่งรัน
  • หากยังไม่มีเวอร์ชันที่ระบุ ระบบจะดาวน์โหลดและตั้งค่าให้อัตโนมัติ

การเขียนสคริปต์ที่รันได้โดยตรงด้วย shebang

  • สามารถใช้ shebang (#!...) เพื่อสร้างไฟล์รันได้โดยตรงในรูปแบบ uv run --script
  • ในกรณีนี้ก็ยังสามารถประกาศ dependency และเวอร์ชัน Python ไว้ที่ด้านบนของสคริปต์ได้เช่นกัน

การรองรับ package index และการยืนยันตัวตน

  • สามารถใช้ custom package index ได้ผ่านออปชัน --index
  • ข้อมูล index สามารถรวมไว้ใน metadata ได้เช่นกัน
  • หากต้องมีการยืนยันตัวตน สามารถดูเอกสารเพิ่มเติมแยกต่างหากได้

การล็อก dependency และเพิ่มความสามารถในการทำซ้ำสภาพแวดล้อม

  • สามารถสร้างและจัดการไฟล์ lock ในระดับสคริปต์ ได้ด้วย uv lock --script
  • หลังจากนั้นเมื่อรันหรือเพิ่ม dependency ระบบจะนำไฟล์ lock กลับมาใช้ซ้ำและอัปเดตเมื่อจำเป็น
  • มีออปชัน exclude-newer (ยกเว้นรีลีสหลังจากวันที่กำหนด) เพื่อช่วยให้ทำซ้ำเวอร์ชันได้แม่นยำ
  • ระบุวันที่ด้วย timestamp รูปแบบ RFC 3339

ความยืดหยุ่นของเวอร์ชัน Python

  • ในแต่ละการรันสามารถระบุให้ใช้ เวอร์ชัน Python ใดก็ได้ ผ่านออปชันบรรทัดคำสั่ง
  • ตัวอย่าง: uv run --python 3.10 example.py

การรองรับ Windows

  • สคริปต์ที่ใช้นามสกุล .pyw จะถูกรันด้วย pythonw บน Windows
  • สคริปต์แบบ GUI ก็สามารถรันพร้อม dependency ได้เช่นกัน

เอกสารอ้างอิง

  • หากต้องการดูวิธีใช้คำสั่งโดยละเอียดเพิ่มเติม สามารถดูเอกสารอ้างอิง CLI และคู่มือการรัน/ติดตั้งเครื่องมือได้

บทสรุป

  • uv เป็นเครื่องมือที่ช่วยจัดการสภาพแวดล้อมการรัน dependency เวอร์ชัน package index และความสามารถในการทำซ้ำสภาพแวดล้อมของสคริปต์ Python ได้อย่างอัตโนมัติและสะดวก ช่วยเพิ่มทั้ง ประสิทธิภาพการทำงาน และ ความน่าเชื่อถือ ไปพร้อมกัน

7 ความคิดเห็น

 
ihabis02 2025-07-24

ผมก็ลองย้ายจาก pip ไปใช้ uv เหมือนกัน แล้วก็รู้สึกว่าความเร็วที่เร็วมากนี่อย่างเดียวก็คุ้มพอให้ย้ายแล้วจริงๆ

 
idunno 2025-07-23

เห็นโพสต์นี้บ่อยเลยเพิ่งได้ลองใช้ครั้งแรกเมื่อวาน... เร็วมากจริง ๆ เลย โอ้โห..

 
ytuniverse 2025-07-23

เหมือนจะเห็นโพสต์เกี่ยวกับ uv ที่นี่มาแล้วเกิน 5 โพสต์เลยนะ;;;

 
pmc7777 2025-07-23

ฟังก์ชันอื่น ๆ ยังไม่ต้องพูดถึง แค่เรื่องความเร็วอย่างเดียวก็มีเหตุผลมากพอให้ใช้งานแล้ว
ถ้าจะให้กลับไปใช้ pip อีก บอกเลยว่าไม่มีทางทำได้แล้ว

ตอนนี้ผมใช้ flake.nix มาแทนการจัดการ system package ของ conda อยู่ และนอกจากงานที่ต้องทำร่วมกันหรือโปรเจกต์เดิมที่ดูแลต่อด้วย conda+pip แล้ว โดยส่วนตัวคิดว่าจากนี้ไปคงจะใช้ uv+nix เป็นหลัก

 
ndrgrd 2025-07-22

ช่วงหลังผมเปลี่ยนการรัน Python เกือบทั้งหมดมาใช้ uv ซึ่งมันเร็วมาก
แม้ว่าจะมีฟีเจอร์ขั้นสูงบางอย่างที่ยังเข้ากันได้ไม่สมบูรณ์ แต่ในกรณีส่วนใหญ่ก็ทำงานได้แทบจะเหมือนกัน

 
GN⁺ 2025-07-22
ความเห็นจาก Hacker News
  • ได้ลองใช้ฟีเจอร์ "การประกาศ dependency ของสคริปต์" แล้วรู้สึกว่ามีประโยชน์มาก
    ตามที่แนะนำไว้ในคู่มืออย่างเป็นทางการ เราสามารถระบุ dependency เป็นคอมเมนต์ไว้ด้านบนสุดของโค้ด Python ได้แบบนี้

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

    บันทึกไฟล์นี้เป็น script.py แล้วรันด้วย uv run script.py dependency ที่ระบุไว้จะถูกติดตั้งลงใน virtual environment ชั่วคราวแบบเหมือนเสกขึ้นมา และสามารถรันได้ทันที
    นี่คือการ implement PEP 723 ของ Python และ Claude 4 ก็รู้จักเทคนิคนี้ด้วย ดังนั้นถ้า prompt ว่า “เขียน Python script ที่มี inline script dependencies” มันก็จะสร้างออกมาได้ถูกต้อง
    ตัวอย่างเช่น สามารถขอให้เขียนโค้ดที่ใช้ httpx กับ click เพื่อดาวน์โหลดไฟล์ขนาดใหญ่พร้อมแสดง progress bar ได้
    ก่อนยุค Claude 4 ฟีเจอร์ลักษณะนี้ต้องใช้โปรเจกต์ที่ปรับแต่งเองพร้อมคำอธิบายเพิ่มเติม แต่ตอนนี้ไม่จำเป็นแล้ว
    ดูตัวอย่างการใช้งานแบบละเอียดเพิ่มเติมได้

    • โหมด shebang ก็มีประโยชน์มากจริงๆ
      ถ้าเพิ่ม shebang ไว้บรรทัดแรกของสคริปต์แบบนี้ ก็จะสามารถรันเหมือน ./script.sh ได้

      #!/usr/bin/env -S uv run --script
      # /// script
      # dependencies = [
      #  "requests<3",
      #  "rich",
      # ]
      # ///
      import requests, rich
      # ... script
      
    • อยากให้รูปแบบมันเหมือนกับไฟล์ requirements
      ถ้าเป็นแบบนั้น สำหรับผู้ใช้ที่ไม่มี uv ก็จะสามารถใส่คอมเมนต์ง่ายๆ เพิ่มไว้เพื่อบอก one-liner สำหรับติดตั้งด้วย pip แบบเดียวกันได้
      เช่นอาจใช้แนวทางอย่าง pip install -r <(head myscript.py)

    • จริงๆ แล้ว PEP723 ตอนนี้ไม่ได้รองรับแค่ uv ที่กำลังมาแรง แต่ pipx และ hatch ก็รองรับด้วย
      และเครื่องมืออย่าง pip-tools ก็อยู่ใน roadmap ที่จะรองรับเช่นกัน
      (ดูissue ที่เกี่ยวข้อง)

    • ตอนเห็นครั้งแรก เคยคิดว่าเป็นอีโมจิรูปหัวใจอยู่ข้าง requests

    • คิดว่าวิธีนี้เจ๋งมาก
      แต่สักวันหนึ่งก็หวังว่าจะถูกรับเข้าไปเป็น syntax ของภาษาโดยตรง ไม่ใช่ magic comment
      คอมเมนต์แบบนี้ดูรกไปนิด
      แน่นอนว่าในมุมของเครื่องมือ magic comment นั้น parse ง่ายกว่า และก็เข้าใจว่าฝั่ง Python core เองไม่ได้มีความรู้เรื่อง packaging มากนัก รวมถึงมีข้อพิจารณาเชิงโครงสร้างอื่นๆ แต่ก็ยังหวังว่าสักวันจะมี syntax ในภาษาโดยตรง

  • เห็นด้วยกับแนวทางนี้มาก
    แม้ Python จะไม่ได้บังคับว่าต้องมีไฟล์ requirements.txt แต่ถ้าดูแลไม่ดี ก็มักเกิดปัญหาที่อะไรบางอย่างพังเพราะการจัดการไม่ดีได้บ่อย ซึ่งน่าเสียดาย
    ดูทวีตที่เกี่ยวข้อง

  • อยากแชร์กับดักที่เคยเจอจากวิธีนี้
    เคยเอาไปใช้กับสคริปต์สำหรับรีสตาร์ตเราเตอร์ตอนอินเทอร์เน็ตหลุด แต่เพราะกระบวนการติดตั้ง dependency ต้องพึ่งการเชื่อมต่ออินเทอร์เน็ต พอเน็ตใช้งานไม่ได้ สคริปต์เองก็รันไม่ได้ไปด้วย
    โชคดีที่เจอก่อนเลยแก้ด้วยการติดตั้ง dependency ไว้ล่วงหน้า แต่ก็อยากเตือนว่าอย่าพลาดแบบผม และไม่แนะนำให้ใช้ในสภาพแวดล้อมแบบ airgapped จริงๆ (สภาพแวดล้อมที่ตัดขาดเครือข่ายโดยสมบูรณ์)
    ต่อให้มี uv cache ก็ยังอาจเกิด cache miss ได้

    • ถ้าใช้ตัวเลือก uv run --offline ก็จะใช้ dependency ที่ cache ไว้ได้ โดยไม่ต้องเช็กเวอร์ชันใหม่ก่อนรัน
      ฟีเจอร์เดียวกันนี้ใช้กับ uvx ได้ด้วย (uvx --offline ...)

    • เข้าใจว่าโครงสร้างมันเป็นแบบที่ ถ้าจะใช้ dependency หรือ venv อย่างน้อยต้องรันตอนมีอินเทอร์เน็ตสักหนึ่งครั้งก่อน หลังจากนั้นถึงจะใช้งานแบบออฟไลน์ได้

  • ช่วงนี้รู้สึกว่าฟีเจอร์หลายอย่างใน ecosystem ของ Python เริ่มทำงานเข้ากันได้ดีขึ้นเรื่อยๆ
    ตอนนี้กำลังเริ่มทำเครื่องมือรายงาน/วินิจฉัยที่ reproducible และเหมาะให้ทีมอื่นใช้งานต่อ โดยใช้ Marimo ร่วมกับ uv script dependencies

  • ฟีเจอร์นี้ของ uv คือสิ่งที่ชอบที่สุด และเป็นเหตุผลที่ย้ายมาใช้ uv
    มีสคริปต์ git-hooks หลายตัวที่แต่ละตัวมี dependency ของตัวเอง และไม่อยากติดตั้งพวกนั้นลงใน main venv
    แค่เพิ่ม #!/usr/bin/env -S uv run --script --python 3.13 บรรทัดเดียว ก็แค่บอกทีม dev ให้ brew install uv แล้วก็ใช้งานจากในสคริปต์ได้เลย โดยไม่ต้องสร้าง venv แยก

    • มีใครพอรู้ไหมว่าทำไมต้องใช้แฟลก -S
      บนสภาพแวดล้อม BSD ของผม /usr/bin/env -S uv run --python 3.11 python กับ /usr/bin/env uv run --python 3.11 python ต่างก็เปิด Python shell เหมือนกัน เลยรู้สึกว่าได้ผลไม่ต่างกัน
      อ่านคู่มือของ env แล้วก็ยังไม่เข้าใจชัดเจน ถ้าใครมีข้อมูลที่เป็นประโยชน์ก็อยากฟัง
      (-S ในที่นี้ทำหน้าที่แยกอาร์กิวเมนต์ตามช่องว่าง)

    • เดิมทีเพราะ UV เลยวางแผนจะย้ายงาน migration ขนาดใหญ่ของ Python ไปทำด้วย golang แต่ตอนนี้ UV ช่วยลดขอบเขตการย้ายได้มาก
      โดยเฉพาะงานเล็กๆ ในรูปแบบสคริปต์ ไม่จำเป็นต้องย้ายอีกต่อไป

    • มั่นใจว่านี่คือฟีเจอร์ระดับ ‘killer feature’ จริงๆ

  • ถ้ามี Pytorch อยู่ใน dependency วิธีนี้อาจมีข้อจำกัดอยู่บ้าง
    แม้ Uv จะมีการรองรับแบบบูรณาการสำหรับ Pytorch ที่ดีมาก แต่แค่จาก header ของสคริปต์อย่างเดียว ยังไม่มีวิธีเลือก wheel index ที่เหมาะที่สุดได้อย่างชัดเจน (เช่น CPU, CUDA, ROCm)

  • อยากให้ VS Code มองเห็น venv ที่ uv สร้างอัตโนมัติได้ง่ายกว่านี้
    ตอนนี้ Python extension แสดงเส้นแดงกับ import ของ third-party ทั้งหมด
    วิธีแก้ชั่วคราวคือต้องไปหา path ของ venv ในไดเรกทอรี Cache ของ uv แล้วลงทะเบียนเอง แต่ถ้า venv ถูกสร้างใหม่บ่อยๆ ก็ต้องทำซ้ำเรื่อยๆ ซึ่งยุ่งยากมาก

    • ใช้คำสั่ง uv python find --script "${filePath}" เพื่อหา path ของ env ได้
      ตอนนี้กำลังพัฒนาส่วนขยายสำหรับ VS Code ที่จะตรวจจับและเปิดใช้งานฟีเจอร์นี้ให้อัตโนมัติ
  • ชอบฟีเจอร์นี้ของ UV มาก
    แม้แต่ jupyter notebook ก็รันแบบ one-liner ได้โดยไม่ต้องติดตั้งแยก ดังนี้

    uv run --with jupyter jupyter notebook
    

    ทุกอย่างจะถูกติดตั้งลงใน virtual environment ชั่วคราว แล้วหลังจากนั้นก็ถูกจัดเก็บออกไปอย่างสะอาด
    ถ้ารันภายในโปรเจกต์ มันจะตรวจจับ dependency ของโปรเจกต์นั้นให้อัตโนมัติด้วย

    • แต่อันที่จริงมันไม่ได้ถูกจัดเก็บออกไปแบบ ‘สะอาด’ ทั้งหมด เพราะโฟลเดอร์ cache ของ uv อาจโตขึ้นเรื่อยๆ ได้

    • ผมเองก็ใช้บ่อยในรูปแบบ uv run --with ipython --with boto3 ipython และช่วยประหยัดเวลาได้มากจริงๆ

  • ไม่นานมานี้เจอ issue เล็กๆ เกี่ยวกับ uv run
    ถ้ารันสคริปต์จากนอกโฟลเดอร์โปรเจกต์ มันจะค้นหา pyproject.toml จาก current working directory ไม่ใช่จากตำแหน่งของไฟล์สคริปต์จริง
    เพราะฉะนั้นสคริปต์ที่เก็บ dependency ไว้ใน pyproject.toml อาจทำงานไม่ถูกต้อง หากรันจากภายนอกในลักษณะ uv run path/to/my/script.py
    ปัญหานี้แก้ได้ด้วยการใช้ inline dependencies เสมอ หรือใช้พารามิเตอร์ --project แต่ก็ต้องพิมพ์ path ของสคริปต์ซ้ำสองครั้ง ทำให้ไม่สะดวก
    ตัว uv เองยอดเยี่ยมมาก แต่พฤติกรรมเล็กๆ ตรงนี้ค่อนข้างน่าหงุดหงิด

  • ใช้งาน uv-specific shebang และวิธีใส่ dependency ในสคริปต์อยู่แล้ว และพอใจมาก
    ยิ่งไปกว่านั้นยังประทับใจกับการที่สามารถสร้าง lock file สำหรับสคริปต์เดียวได้ด้วยคำสั่ง uv lock --script example.py
    Python packaging ดำเนินมากว่า 20 ปีแล้ว แต่ก็น่าทึ่งที่ประสบการณ์ที่เป็นธรรมชาติแบบนี้เพิ่งมาถึงตอนนี้

    • อยากรู้ว่าการสร้าง lock สำหรับสคริปต์เดี่ยวมี use case แบบไหนบ้าง
      ในองค์กรของเรา ยังใช้ lockfile dependency สำหรับสแกนด้วย trivy fs uv.lock เพื่อช่วยป้องกันไม่ให้รันโค้ดที่มี CVE ที่รู้จักอยู่ด้วย