Why I love Python so much

ในโอกาสที่เพจ เขียนงูให้วัวกลัว ครบ 1000 likes ผมเลยคิดได้ว่า เออ อยู่ดีๆ ผมก็มาทำเพจเอามันส์ อยากเขียนอะไรก็เขียน แล้วก็มาสงสัยกับตัวเองบางครั้งว่า ทำไมเราถึงมีความรู้สึกอยากจะทำเพจนี้มากขนาดนี้ ผมเลยมองย้อนกลับมาหาตัวเองว่า ทำไม เราถึงชอบภาษานี้มากขนาดนี้ มันมีเหตุผลอะไร ผมจะพาไปไล่ดูครับว่าทำไมผมถึงรักภาษานี้มากและอาจจะเป็นเหตุผลให้คุณรักภาษานี้เหมือนกันก็ได้ Beautiful is better than ugly 💄 hello world แบบ Python นะครับ ส่วนแรกที่ผมชอบเกี่ยวกับภาษานี้คือ Semantic มันครับ เรื่องนี้ต้องย้อนไปถึง Design Philosophy ของตัวภาษาเลยว่ามันถูกออกแบบมาให้เป็นภาษาที่อ่านได้ง่ายมากๆ โดยใช้ keyword ภาษาอังกฤษ แทนที่จะใช้เครื่องหมายต่างๆ รวมไปถึงใช้ Indentation แทนที่จะใช้ curry bracket ในการกำหนด scope เป็นต้น ด้วยตัวภาษาเองยังเป็นภาษา Multi-paradigm ทำให้รองรับรูปแบบการเขียนโปรแกรมหลายรูปแบบมากตั้งแต่ Imperative, Object Oriented, Functional, Procedural และ Reflective ทำให้เราไม่ถูกจำกัดแนวคิดในการแก้ปัญหาต่างๆ ด้วยภาษานี้ถึงแม้มันจะขัดกับ Zen of Python ข้อ There should be one — and preferably only one — obvious way to do it. ก็เถอะ ...

July 31, 2018 · 2 min

Dedent your multiline string

วันที่ 2 ของ #PythonTricksEveryday นะครับ ไหนๆ ก็เป็นวันสุดท้ายของการทำงานก่อนจะถึงวันหยุดยาว ขอแนะนำด้วย Tricks เล็กๆ ที่จะช่วยให้การทำงานกับ Multiline String เราดีขึ้นครับ สมมติว่าเรามี String ยาวๆ ที่ต้องมี Indent สวยๆ เช่น Email หรือ Code snippet อย่างในภาพ แล้วเราต้องการนำมันไปใช้งานเช่นส่งอีเมล์หรือ Print report อะไรแบบนี้ จะเห็นว่าพอ print ค่าออกมาแล้ว string ที่เราเก็บไว้มี space ติดมาด้วย สิ่งที่เกิดขึ้นคือ Multiline String ของ Python จะนับ tab ที่เราเว้นไว้ทางซ้ายด้วย เหมือนในฟังก์ชั่น process_something() ซึ่งถ้าเราไม่อยากให้มันเยื้องแล้ว Print ออกมาสวยๆ เราก็ต้องทิ้งเยื้องไป เหมือนในฟังก์ชั่น process_something_without_padding() ซึ่งพอเราทำแบบนี้ ผมว่าทุกคนน่าจะรู้สึกทันทีว่า เออมันเวิร์คนะแต่ Indent มั่วไปหมดเลย พ้น definition ของ function ไปอีก ยิ่งถ้าเป็น Method ที่อยู่ใน class ยิ่งไม่อยากจะคิดเลย ...

July 26, 2018 · 1 min

The Power of Any / All

วันที่ 1 ของ #PythonTricksEveryday นะครับ วันนี้เปิดด้วยหนึ่งในเทคนิคที่ พอรู้แล้วก็ใช้ได้ตลอดเลย มันคือ built-in function ที่ชื่อว่า all() และ any() ครับ ไปดูสถานการณ์เลยดีกว่า สถานการณ์ที่เรามักจะเจอกันบ่อยๆ คือ เราต้องเขียน if ที่มี condition เยอะมากๆ อย่างในตัวอย่างนี้ก็ 5 conditions ซึ่ง บางทีรูปแบบที่มันอยู่อาจจะอยู่ยากกว่านี้ก็ได้ เช่น เป็น if แยกกันหลายๆ อันหรือ if ซ้อนใน if ให้เราลองพยายาม normalize ให้มันเหลือ if เดียวแล้วให้ความสัมพันธ์ของมันเหลือแค่ and / or พอเรา normalize ความสัมพันธ์ของแต่ละ condition จนเหมือนภาพข้างบนแล้ว สิ่งที่เกิดขึ้นก็คือ Linter ด่าครับ ยาวเกิน 80 บรรทัดอะไรก็ว่าไป ซึ่งเราก็จะต้องตบมันเข้ามาให้ไม่เกิน 80 บรรทัด โค้ดข้างล่างนี้ผมใช้ Black ช่วย Format ให้นะครับหน้าตาก็จะประมาณนี้ ...

July 25, 2018 · 2 min

Mock requests แบบสวยๆ ด้วย responses

สิ่งหนึ่งที่เราเจอไม่ว่าจะช้าหรือเร็วคือ เมื่อเขียน Python ไปซักพักเราต้องยุ่งกับการยิง HTTP request ไปหา service ข้างนอก ซึ่ง Library ที่นิยมที่สุดในการทำสิ่งนี้ใน Python ก็คงหนีไม่พ้น requests นะครับ สมมติเรามีฟังก์ชั่น process_something ที่ทำหน้าที่ยิง requests ไปหา service ข้างนอกแล้วคืนของออกมาเป็น dictionary หน้าตาประมาณนี้ process_something.py ถ้าเขียนแบบสมัยก่อน เราก็จะต้อง patch ตัว requests.get แล้วสร้าง Mock() object มารับ return_value หน้าตาประมาณนี้ ซึ่งพอทำแบบนี้บ่อยๆ เราก็เริ่มเห็น Pattern ซ้ำๆ ครับว่าต้อง Mock status_code นะ json() call นะหรือแม้กระทั่ง content type กับ headers ในบางเคส วิวัฒนาการถัดมาของการ mock requests คือ พอเราเห็น pattern ซ้ำๆ เราก็จับมันมาทำ utils function ครับ ซึ่งหน้าตามันก็จะออกมาประมาณนี้ ...

July 24, 2018 · 2 min

มารู้จัก Data classes กันครับ

เกือบจะไม่ได้มาเขียนต่อกันละสำหรับ Part 2 ของ dataclass ตอนที่หนึ่งอยู่ที่ โพสนี้ นะครับ แต่เพื่อไม่ให้เป็นการเสียเวลาไปมากกว่านี้ เราไปต่อกันที่ Part 2 เลยครับ ตอนที่แล้วเราได้รู้จัก dataclass ได้รู้ถึงเหตุผลว่าทำไมถึงเกิดมันขึ้นมา ตอนนี้เรามาจะมาโฟกัสกันว่า เราจะใช้ dataclass กับโค้ดเรายังไงครับ ตัวอย่างการใช้งาน dataclass อย่างแรกที่เราเห็นเลยคือ เราไม่ต้องเขียน __init__ method กันอีกแล้วครับ ตัว dataclass จะ generate โค้ดส่วนนั้นให้ และอีกอย่างที่เราสังเกตุเห็นเลยคือ dataclass ใช้ประโยชน์จาก Type hint เต็มๆ อย่างที่เราเห็นการประกาศ Attribute ข้างต้นจะมีการประกาศ Type ประกบด้วยทุกตัว ทำให้เราสามารถเข้าใจ Attribute แต่ละตัวได้ทันทีว่าใช้ Type อะไรโดยไม่ต้องเดา อย่างที่สองครับ Representation ตัว dataclass เนี่ยนอกจากจะ generate __init__ ให้เราแล้วอีกตัวที่ทำให้คือ __repr__ ครับ ซึ่งตัว dataclass เนี่ยจะใช้ข้อมูลจาก attribute ที่เรา define ไว้มาสร้างให้ซึ่งช่วยเพิ่มความสะดวกให้เราและทำให้เราเลิกคิดไปได้หนึ่งเรื่อง หน้าตาก็จะประมาณนี้ครับ ...

July 16, 2018 · 2 min

#100DaysOfPyCon2018 Day6: Big-O: How Code Slows as Data Grows

Talk ผมดูวนอยู่สองสามรอบ เพราะต้องการเก็บทุกเม็ดทุกหน่วยจริงๆ คือ ผมไม่เคยเจอ Talk ที่ดูแล้วตื่นตาตื่นใจขนาดนี้มานานมาก ตอนนี้ยกให้เป็น Talk อันดับหนึ่งในใจของ PyCon ปีนี้เลย ผมคิดว่า Talk นี้จะไม่สรุป Key Takeaway เพราะอยากให้คนที่มารู้จัก Talk นี้จากผมได้รับสารเต็มๆ จาก Ned Batchelder โดยการดู Talk นี้ครับ แต่ถ้าไม่มีเวลาดูจริงๆ แนะนำให้ไปอ่าน เวอร์ชั่น Text ที่เจ้าตัวเองถอดเขียนไว้ เป็นบทความที่ผม Recommend เลยครับ ทำให้ผมกลับมาคิดเรื่อง Algorithmic Analysis หลังจากหลงลืมมันไปนานมาก ลิ้งข้างล่างนี้ครับ Big-O: How Code Slows as Data Grows Big-O notation can be intimidating, but it doesn’t have to be. A common-sense approach will give you a good working technique for analyzing the time complexity of your code. — Ned Batchelder, about ...

May 23, 2018 · 1 min

#100DaysOfPyCon2018 Day5: Oops! I Committed My Password To GitHub!

Key takeaway คนที่เคย commit password ลง Git มีอยู่ 2 ประเภท ประเภทแรกคือเผลอพลาดจริงๆ อีกประเภทคือบอกว่า commit สิแต่ไม่เป็นไรเพราะ… ซึ่งเพราะนี่มีหลายคนที่บอกว่า เพราะมันเป็น private repo แต่เราไม่ควรมองอย่างงั้นเพราะว่า Private Repo มันไม่ได้ encrypt เพราะฉะนั้นคนที่อยู่ GitHub ก็ยังดูข้อมูลเราได้อยู่ รวมถึงถ้าวันนึงคนในทีมออกจากบริษัทไป คนๆ นั้นก็ยังมี password นั้นอยู่ อีกเหตุผลคือ ไม่เป็นไรเพราะ password เราใช้ใน internal service แนวคิดนี้มาจากการจำกัดบริเวณความเสียหาย ซึ่งก็ยังไม่ตอบโจทย์อยู่ดี วิธีการ (ไม่) แก้ password ที่เผลอ commit ไปคือ สร้าง commit ใหม่ที่จะลบ password ถ้าเราใช้ git เป็นประจำเราจะรู้ว่าเราสามารถดู history ได้ซึ่งวิธีนี้ก็ไม่ได้แก้ปัญหาอะไร อีกวิธีที่บางคนคิดว่าแก้ปัญหาคือ rebase commit แต่มันไม่ได้แก้ปัญหาถึงแม้ว่า history จะเปลี่ยนไป แต่ git เก็บทุกอย่างแล้ว commit นี้ยังอยู่ใน ref log แต่เป็น orphant อยู่จนกว่าจะโดน garbage collect ไป รวมถึงถ้าในเคสที่คนที่ลาออกไปก่อนที่เราจะ rebase สุดท้ายเค้ายังมี password อยู่ดี เพราะมันไม่ได้แก้ทุกเครื่อง วิธีแก้ที่ดีสุดคือ Revoke password ซะ นี่เป็นสิ่งแรกที่เราควรทำเมื่อรู้ตัวว่า password เราเผลอ commit ไปแล้ว สิ่งต่อมาที่ควรทำคือ เราควรจะเก็บ password / secret ไว้ใน environment variable ซึ่งวิธีการ access มันใน Python เราสามารถใช้ module os.environ ในการเรียกได้ โดย module นี้จะเก็บ environment variable ทั้งหมดที่ OS ป้อนให้ process เราในรูปแบบ Dictionary วิธีการเก็บ password ใน environment variable เราสามารถเก็บผ่าน .profile หรือ .bashrc สำหรับทุกโปรเจ็ค แต่ถ้าเป็นโปรเจ็คเดี่ยวๆ จะแนะนำ .env มากกว่า และสำคัญที่สุดคือ อย่าพิมพ์ password ใน shell เพราะ shell เก็บ history ทุกอย่างที่พิมพ์ และไฟล์ .env ก็อย่า commit ลง git แต่ให้เขียน .gitignore กันไว้จะดีที่สุด Python มี Package ชื่อ python-dotenv เอาไว้ใช้สำหรับ load environment variable โดยเฉพาะ ซึ่งแค่แปะฟังก์ชั่น load_dotenv() ก่อนจะใช้ค่าใน env ก็ใช้ได้แล้วสะดวกมาก ไม่ต้องมานั่ง export env เอง ก่อนรัน app ถ้า environment variable ยังไม่ปลอดภัยพอ เรายังมีตัวเลือกอีกมากเช่น Vault (Hashicorp) / Parameter Store (AWS) / Secret Object (K8S) / Vault (Ansible) ซึ่งพวกนี้นอกจากจะเก็บ secret ให้เราแล้วยัง encrypt ให้ด้วย DO and DON’T อย่าเขียน password / token ไว้ใน code จงเรียก Password / token จาก environment variable หรือ secret store จง Revoke ตัว secret เราที่เผลอเปิดเผยไปแล้ว อย่าใช้ service ที่ไม่มี option ในการ revoke access token อย่าใช้ password เดียวกันหลาย service อย่าใช้ credential เดียวกันทุก Users Original Post on: https://yothinix.medium.com/100daysofpycon2018-day5-oops-i-committed-my-password-to-github-300fd7704a34

May 20, 2018 · 2 min

#100DaysOfPyCon2018 Day4: Visual Testing with PyCharm and pytest

จริงๆ ดูจบตั้งแต่เมื่อเช้าแล้ว แต่คิดหนักมากว่าจะสรุปดีมั้ย เพราะทุกอย่างที่อยู่ใน Talk นี้คือรู้อยู่แล้ว ใช้อยู่ทุกวันอยู่แล้วไง แต่หลังจากคิดไปคิดเลยขอวางตัวเองออกไป แล้วคิดว่าไม่รู้อะไรเลยแล้วลองสรุปดีกว่า Key takeaway TDD crash course: Test ➡ Design & Develop วิธีที่เค้าเปรียบเทียบค่อนข้างจะน่าสนใจทีเดียว เค้าบอกว่าสมัยเรียนเวลาอ่าน text book มันใหญ่มาก บทนึงก็ยาว แต่เกือบทุกเล่มท้ายบทจะมีแบบทดสอบว่าเราเข้าใจรึเปล่า เค้าลดเวลาในการทำความเข้าใจทั้งบทด้วยการ อ่านคำถามท้ายบทก่อน แล้วค่อยไปหาอ่านเนื้อหา วิธีนี้ทำให้เข้าใจเนื้อหาได้เร็วทันทีแล้วไม่ต้องเสียเวลาอ่านน้ำ ถ้าเปรียบกับการเขียนโปรแกรมก็คงไม่ต่างอะไรกับเราไม่ต้องหลงทุ่งเขียนไปเรื่อย แต่ตั้งคำถามกับตัวเองว่าเรากำลังแก้ปัญหาอะไร แล้วพยายามแก้ปัญหานั้น Pytest สามารถรันเทสเป็นซับเซตได้ทั้งระดับ Directory, module หรือแม้กระทั้ง test case หรือใช้ marker, expression กำหนดว่าจะรันเทสไหน รวมถึงเพิ่ม option ให้รันแล้ว exit เลยเมื่อเทส failed หรือ รันเทสที่ failed ล่าสุดก่อน ฯลฯ Visual Testing vs CLI ต้องบอกว่าบางคนไม่ถูกกับ CLI จริงๆ เค้าเลยพยายามหาทางให้ทีมรันเทสให้ได้ง่ายขึ้นเลยมาจบที่ใช้ PyCharm ให้เรียก Pytest อีกที ซึ่งนอกจากจะใช้ครอบ Pytest ให้รันง่ายขึ้นแล้ว (ผ่าน gutter) ยังสามารถ debug test/code ไปพร้อมๆ กับรันเทสผ่าน breakpoint และ debugger ที่ติดมากับ PyCharm ได้ด้วย เราสามารถเทสฟังก์ชั่นเดิมแต่ใช้ input set ต่างกันได้ผ่าน pytest.mark.parameterize วิธีนี้ทำให้โค้ดเทสสะอาดขึ้นมาก เพราะเรา define แค่ parameter ตัวเทสก็เขียนเหมือนเดิมอยู่แล้ว ถ้าอยากศึกษาเพิ่มเติมเกี่ยวกับ PyTest ผมแนะนำหนังสือ Python Testing with pytest ครับ คนเขียนก็คนเดียวกับที่พูด Talk นี่แหละครับ นอกจากหนังสือนี้ทำให้รู้จักใช้ความสามารถต่างๆ ของ PyTest มากขึ้นแล้ว หนังสือเล่มนี้ทำให้ผมหลงรัก namedTuple ซึ่งเป็น data structure ที่คนมองข้ามมากตัวนึงเลยครับ Python Testing with pytest Python Testing with pytest, 2nd Edition 2nd edition is now in Beta, and purchasable as an eBook. All 16 chapters, plus 2 appendices, are in the Beta, available as an eBook. Copy editing and indexing are complete. The physical book is the next step. Final version expected Feb 2022 (or March, maybe)… — Python Testing ...

May 18, 2018 · 1 min

#100DaysOfPyCon2018 Day3: Dataclasses: The code generator to end all code generators

Key takeaways Sphinx ก็เอามาใช้ทำ Presentation ได้ แถมได้ document ที่อ่านง่ายกลับไปดูทีหลังได้ด้วย Code generator: tools that write code for you based on specification dataclasses มี learning curve ต่ำมาก ถ้ามองสามารถมองได้สองมุมคือ data holder เหมือน namedTuple หรือเป็น boilerplate เอาไว้เขียน class ประวัติศาสตร์แบบย่อๆ เริ่มต้นเรามี dict, tuple, hand-written class หลังจากนั้น namedTuple 🎉✨ ก็เกิดขึ้นแล้วตามมาด้วย types.SimpleNamespace ทำให้เราสร้าง data structure ได้ง่ายขึ้น (access ได้ง่ายขึ้นด้วย) ในอีกมุมนึง ORMs ก็กำเนิดขึ้นด้วยจาก Django, SQLAlchemy, PeeWee ซึ่งใช้ class เป็นเทคนิคในการสร้าง data structure หลังจากนั้นมี traitlets เกิดขึ้นเป็น package ไว้ใช้ทำ data validation โดยใช้ class attribute เป็นตัวกำหนด พอ Python 3.6 ออกก็เกิด Type Annotation, Variable Annotation ช่วยให้เราสามารถ define type ของ attribute ของ class ได้เลย ท้ายที่สุดเรามี library ชื่อ attrs เป็นแรงบันดาลใจในการสร้าง dataclass สามารถมองง่ายๆ ได้ว่าเป็น “Mutable namedtuples with defaults” Dataclass เบสิกเลยเขียนคล้าย namedTuple มาก ต่างกันแค่ dataclass ใช้ decorator dataclass แต่ NamedTuple ต้อง inheritance ออกมาจาก NamedTuple class ความสามารถของ Dataclass สร้าง repl ให้เราโดยอัตโนมัติจาก attribute definition เลย ใช้ replace() ในการ mutable attribute ได้ เช่น replace(c, hue=120) ถ้าเป็น namedTuple ต้องใช้ c._replace(hue=120) เพื่อป้องกัน namespace collision ใช้ asdict() หรือ astuple() ให้คืนค่าออกมาเป็น dict หรือ tuple ได้เลย ข้อสังเกตุของ asdict() คือ dataclass จะคืน Dict ออกมาให้เลยในขณะที่ namedTuple จะคืน OrderedDict เพราะเป็น implementation เก่า มี method __annotations__ เอาไว้ดู type annotation ของ attributes ได้ ข้อเสียของ dataclass คือ unpack ของได้ยากกว่า namedTuple (เพราะ implementation ข้างล่างสุดเป็น Dict) ทำให้ก่อน unpack ต้องแปลงเป็น tuple ก่อน ในเรื่องของ Performance / Resource ตัว dataclass จะมีขนาดใหญ่กว่า namedTuple แต่แลกมาด้วยความเร็วในการ access object ที่เร็วกว่า Dataclass สร้าง docstring, __repr__, __eq__ ให้เราโดยอัตโนมัติจาก attribute ที่เรา define ไว้แต่ไม่สร้าง __hash__ ให้นะ ถ้าเราใส่ option frozen = True ใน dataclass decorator จะเป็นการบอกว่า dataclass นี้เป็น immutable หรือถ้ามองง่ายๆ คือให้มันทำตัวเป็น namedTuple ใส่ option order = True ได้ด้วยแต่ผมฟังแล้วไม่ค่อยเข้าใจชัดเจนว่าตกลงมัน order ของอะไรกันแน่ Customize Fields Specification นอกจากจะกำหนดพฤติกรรมของ dataclass ได้จาก decorator แล้วเรายังสามารถใช้ฟังก์ชั่น field() ในการกำหนดพฤติกรรมของแต่ละ attribute ได้ด้วย ตัวอย่างข้างบนเป็น use case คล้ายๆ ของจริงที่ต้องการสร้าง data structure ของ employee ขึ้นมา แล้วเก็บข้อมูลต่างๆ ในนี้ใช้ความสามารถของ field() หลากหลายมาก ...

May 17, 2018 · 2 min

#100DaysOfPyCon2018 Day1: Pipenv: The Future of Python Dependency Management

Key takeaway: — กว่าจะมาเป็น pip ที่เราใช้กันทุกวันนี้ก็ผ่านอะไรมาเยอะมากตั้งแต่ยุค build tarball มายุค easy_install มาถึงยุค pip + virtualenv มันยาวนานมาก เพิ่งรู้ว่า easy_install ไม่มี easy uninstall แล้วสมัยนั้นมันลบกันยังไง — ข้อเสียของยุค pip + requirements.txt คือเราลง package เดียวกันคนละ version ไม่ได้ (Ruby ทำได้) แล้ววิธีที่แนะนำคือ pip freeze > requirements.txt ก็มีปัญหาคือมาดูทีหลังจะงงว่า อันไหนคือ package ที่เราต้องการจริงๆ และ pip-tools พยายามแก้ปัญหานี้แล้วโดยใช้ requirements.in กับ requirements.txt แต่มันก็ยังหลายไฟล์อยู่ — Virtualenv ปัญหาใหญ่สุดคือเข้าใจยากมากสำหรับคนที่เพิ่งใช้ เพราะ concept นี้ใกล้เคียงกับ unix ที่แยก home environment แต่ก้มีคนทำ virtualenv-wrapper (เกิดทันเว้ย) มาแก้ปัญหาในจุดนี้ — Pipfile ทำให้เราแยก group ของ package ที่ลงได้ packages กับ dev packages ...

May 16, 2018 · 1 min