ผมคิดว่า ผู้อ่านคงคุ้นเคยกับการใช้ bash (ใน UNIX) หรือไม่ก็ powershell (ใน Windows) ซึ่งทั่วไปคือการเรียกใช้โปรแกรมพร้อมกับ parameter สักตัวสองตัว

เราทำแบบนั้นกับ Python script ได้เหมือนกันฮะ

ทีนี้ สถานการณ์ที่เราจะทำแบบนั้นมันเป็นไปได้หลายกรณี เช่น

เราเขียนโปรแกรมง่ายๆ สักตัวแล้วต้องการเอาไปต่อกับอีกระบบนึง โดยการเรียกและส่ง parameter ระหว่างกัน

หรือเราต้องการผลลัพท์จาก Python script ที่เรามีอยู่แล้วแหละ แต่ parameter จะมาจาก environment variables แล้วเราต้องการให้มันใช้งานใน CI/CD process

เริ่มซับซ้อนเนอะฮะ งั้นเราค่อยๆ คุยกันในบล็อคนี้ ทีละขั้นนะฮะ


solution พื้นฐานสุด

ก่อนอื่นเลย parameter ตอนที่เราเรียกแบบ bash command line เนี่ย มันจะมองเป็น list of string ฮะ ซึ่งจะเรียกได้ผ่านตัวแปร sys.argv แบบนี้

ลองโยน parameter ไปหน่อยซิ

python3 src/argv/argv01_simple.py 1 2

"1 2" จะถูกโยนเข้าไปที่ sys.argv แล้วให้ method get_params() แงะมันออกมาใส่ตัวแปร a, b แล้วเราจะได้ผลลัพท์หน้าตาแบบนี้

ถ้าไม่มีแค่สองตัวแบบข้างบน แต่มาหลายตัว เราก็ทำแบบนี้ได้ฮะ

ใช้ sum แทน ก็จะได้ผลลัพท์แบบนี้แทน

ประเด็นจริงๆ ไม่ได้อยู่ที่รับมากี่ตัว แต่จะเป็นเรื่องของ flag มากกว่า แบบถ้าเราต้องการให้สามารถรับ "flags" ได้ เช่น

python3 my-script.py 1 2 3 --flag1 ABC --flag2 XYZ

เราคงต้องเขียน funtion มาเช็คว่าค่าไหนเป็น flag ไหนบ้าง ซับซ้อนไปอีก


ลากมาเข้าเรื่องได้แล้วล่ะฮะ เพราะบล็อคนี้ เราจะมารู้จักกับ...

argparse module

argparse เป็น module จัดการ parameter กับ flag ที่เล่าๆ ไว้ข้างต้น รวมถึงช่วยทำ help และ error handling แบบเบื้องต้นให้ด้วยนะ ตัวเอกสารทางการของ argparse อยู่ลิงก?ข้างล่างนี้แล้วฮะ

argparse — Parser for command-line options, arguments and sub-commands
Source code: Lib/argparse.py Tutorial: This page contains the API reference information. For a more gentle introduction to Python command-line parsing, have a look at the argparse tutorial. The arg...

มาลองของจริงกันเลยดีกว่าเนอะ

บวกเลขสองตัวง่ายๆ

หัวใจหลักมันอยู่ตรงนี้ฮะ

parser = argparse.ArgumentParser()
parser.add_argument(...)
parsed_params = parser.parse_args(sys.argv[1:])

เราส่งค่า sys.argv[1:] ไป เหมือนกับข้างบนนั่นแหละ จากนั้นเราสร้าง parser ขึ้นมาแล้ว .add_argument() เพื่อกำหนดเงื่อนไขของแต่ละ parameter

จากตัวอย่าง มันมีสามค่าหลักๆ ได้แก่

  1. string ของแต่ละ parameter
  2. type กรณีนี้เป็น str แปลว่าเราจะรับค่า parameter นี้มาเป็น string นั่นเอง
  3. helpเป็น help message ไว้แสดงผลตอนใช้ -h flag ตัวอย่างเช่น

พอ argparse แยก parameters เสร็จ เราก็สามารถ access ด้วย syntax obj.name ได้ฮะ

ผลลัพท์โปรแกรมจะประมาณนี้นะ

บวกเลขจาก list

ที่บรรทัด 9 จะเห็นว่ามี nargs="+" ตรงนี้แหละฮะ ที่เราสามารถกำหนดให้ parameter ชื่อนี้เป็น list ได้ เครื่องหมายบวกแปลว่าจะมีค่าตั้งแต่หนึ่งค่าขึ้นไปนะ โปรแกรมนี้จะให้ผลลัพท์ราวนี้ฮะ

บวกเลขจาก list แล้วมี choice ด้วย

เราสามารถกำหนดให้มี flag หลายค่าเพื่อเก็บเป็น parameter ตัวเดียวกันได้ เช่น ดูที่บรรทัด 17-18 กำหนดให้เป็น flag -o และ --ops โดยชื่อแรกที่ขึ้นต้นด้วย -- จะเป็นชื่อ flag ให้เราเรียกใช้ในโปรแกรมฮะ อย่างตัวอย่างนี้ก็จะเป็นชื่อ ops นั่นเองฮะ

choices ให้เรากำหนดตัวเลือกที่จะรับค่าได้ ถ้าตอน run จริงป้อนค่าอื่น ก็จะฟ้อง error ฮะ

จากตัวอย่างเนี่ย ถ้าเราลอง add ก็จะได้ผลรวมบวกทุกเลข

แล้วถ้าเป็น mult ก็จะได้ผลรวมคูณของทุกเลขเหมือนกันฮะ

ทำ web scraper ใส่ file พร้อม overwriting handler

ตัวอย่างสุดท้าย คือ download website เก็บลง file โดยมีเงื่อนไขว่า ถ้ามี file อยู่แล้วและไม่กำหนดให้เขียนทับ (overwrite) ให้ฟ้อง error นะ

เราจะกำหนด flag --overwrite หรือ -w พร้อมกำกับไว้ว่า action="store_true" ตรงนี้หมายถึง ถ้าป้อน flag นี้เข้ามา จะทำให้ parameter overwrite มีค่าเป็น true ทันที แต่ถ้าไม่ป้อน ก็จะมีค่าเป็น false

ทีนี้ ลองให้มี file ชื่อที่ว่าอยู่ก่อนแล้ว และเราไม่ป้อน  -w จะเจอกับ error ฮะ

พอป้อน -w โปรแกรมก็จะเขียนทับ file ทันที


อันนี้เป็น repo ของผมเองฮะ มีทั้ง script ข้างบน พร้อมตัวอย่าง command ให้ลองเล่นกันได้ฮะ

GitHub - bluebirz/sample-argparse
Contribute to bluebirz/sample-argparse development by creating an account on GitHub.

ด้วยความยืดหยุ่นของ argparse ทำให้เราสามารถออกแบบโปรแกรมของเราได้หลาดหลายมากๆ ฮะ