April 11, 2012

Python: จัดการตัวแปรจาก CLI ด้วย argparse

การสร้าง CLI สำหรับ script ที่รับตัวแปรตอนเรียกโปรแกรมนั้น แม้จะใช้ sys.argv เพื่อดึงส่วน argument ได้ แต่เมื่อต้องทำงานที่ซับซ้อนแล้ว module ที่จะช่วยให้งานนี้เป็นระเบียบเรียบร้อยคือ argparse

ตัวอย่างเช่น โปรแกรม sq.py ที่จะทำการยกกำลังสองเลขที่รับเข้ามา

เมื่อเรียกโปรแกรมนี้ผ่านทาง CLI จะได้ผลลัพท์ดังนี้

สังเกตกว่า num มีประเภทตัวแปรเป็น string ก่อนที่จะนำไปใช้คำนวณต้องแปลงค่าให้เป็น int ก่อน ซึ่งเราสามารถบอกประเภทให้ตัว parser แต่แรกเลยก็ได้ โดยแก้ไขบรรทัดที่ 4 เป็น



จากตัวอย่างที่แล้ว ตัวแปร num คือตัวแปรแบบ positional argument ซึ่งหมายความว่า ต้องป้อนตัวแปรเหล่านี้ให้ครบ

ลองดูโปรแกรม acal.py ที่รับตัวเลข 3 ตัว แล้วหาผลรวม

นอกจากกำหนดจำนวน argument ด้วยตัวเลขแล้ว ยังสามารถใช้ wildcard ?, +, * เพื่อบอกจำนวนก็ย่อมได้ เช่นปรับปรุงโปรแกรมข้างต้นให้รับ argument ได้ไม่จำกัดโดยเปลี่ยนบรรทัดที่ 4 เป็น



สำหรับตัวแปรอีกประเภทคือ optional argument เช่น -h โดยมีวิธีเขียนที่แตกต่างออกไปเล็กน้อย

คราวนี้มาปรับปรุง acal.py ให้รับ optional argument เพื่อให้สามารถเลือก max หรือ min แทนการ sum ได้

และยังมี optional argument แบบที่สามารถรับ argument ต่อท้ายอีกได้ด้วย ลองดูตัวอย่างการเปิดไฟล์สำหรับเขียนโดยเพิ่มคำสั่งนี้เข้าไปหลังบรรทัดที่ 8

เนื่องจากการเปิดไฟล์ด้วย open เพื่อเขียนต้องบอก option 'w' ด้วย แต่เพราะ type รับตัวแปรเดียว ตรงนี้ให้ใช้ argparse.FileType('w') แทน (หรือจะใชประยุกต์ใช้ lambda f: open(f, 'w') ก็ย่อมได้)

จุดสังเกตอีกอย่างที่เพิ่มขึ้นมาคือ metavar ซึ่งเป็นการบ่งว่า optional argument นี้รับตัวแปรเพิ่มได้ แต่ถ้าเอาไปใส่ให้กับ positional argument จะกลายเป็นแค่การบอกชื่อย่อเท่านั้น

หลังจากเปิดไฟล์กันได้แล้ว ถึงตอนนี้ก็ต้องจัดการกับการแสดงผลที่บรรทัด 11 ใหม่หมด



คราวนี้ก็ลองเขียน help เต็มรูปแบบให้กับ acal.py กันดูครับ

April 3, 2012

PHP: แทรก/ดึงข้อมูลออกจากอาร์เรย์ที่เรียงลำดับ

ใน PHP ตัวแปรชุดแบบอาร์เรย์นั้นจะถูก implement ด้วย hash table ทั้งหมด นี่อาจเป็นข้อดีในแง่ความสะดวก แต่ถ้าหากเราลองทำอะไรอย่างนี้
จะพบว่าตัวที่ถูก unset ไปนั้น กลายเป็นรูโหว่ๆ อยู่กลางอาร์เรย์ โดยที่ index ของ element ใน array ไม่เลื่อนลงมาถมช่องโหว่ให้เต็ม ทางแก้นอกจากเลี่ยงไปใช้การวนแบบ foreach แทนแล้ว ในสถานการณ์ที่เลข index มีความสำคัญ (ต้องเลื่อนไปถมให้เต็ม) ก็มี array_splice สำหรับงานนี้ครับ


สำหรับ argument ที่ให้กับ array_splice จะมีอยู่ทั้งหมด 4 ตัว โดยบังคับใส่อย่างน้อย 2 ตัวได้แก่อาร์เรย์ที่จะเปลี่ยนแปลง และตำแหน่งเริ่มต้นที่จะลบตัวแปรในอาร์เรย์ทิ้ง

argument ตัวที่ 3 จะเป็นการบอกจำนวนของตัวแปรในอาร์เรย์ที่จะลบทิ้งตั้งแต่จุดเริ่มต้นที่ได้บอกไว้ (ถ้าไม่ใส่ก็คือลบทั้งหมด) ซึ่งถ้าตัวเลขนี้เป็นลบ มันจะเป็นการบอกจำนวนของตัวแปรที่เหลือจากการลบนี้แทน

ส่วน argument ตัวสุดท้ายคืออาร์เรย์ที่จะนำเข้ามาแทรกลงในตำแหน่งที่ลบไป และเนื่องจากเราไม่สามารถข้าม argument ตัวที่ 3 ได้ ดังนั้นถ้าต้องการลบอาร์เรย์ต้นฉบับทิ้งจนสุดแล้วค่อยต่อท้ายด้วยอาร์เรย์ใหม่ ให้ใส่ argument ตัวที่ 3 เป็น count เพื่อให้มั่นใจว่าลบตัวแปรทิ้งจนหมดก็ได้

อย่างไรก็ตาม แม้ว่าเราจะสามารถใช้เครื่องมือเหล่านี้เพื่อสร้างอาร์เรย์ที่รักษาการเรียงลำดับตัวเลขไว้ได้ แต่โดยพื้นฐานของมันแล้ว มันไม่ได้ implement มาเพื่องานเช่นนี้โดยเฉพาะ ถ้าต้องการทำงานเช่นนี้โดยที่ยังคงประสิทธิภาพไว้อยู่ อาจพิจรณาการ implement แบบ linked list แทนครับ