วันอังคารที่ 3 กุมภาพันธ์ พ.ศ. 2569

ถ้าเรามีเวลาใช้ชีวิตแค่วันเดียว

     วันนี้คิดเล่นๆระหว่างนั่งรถไปทำงาน ถ้าเรามีเวลาใช้ชีวิตแค่วันเดียว เป็นตัวเราจริงๆแค่วันเดียว ตั้งแต่ตื่นนอน ไปจนนอนหลับตอนกลางคืนจะเป็นยังไง


     ถ้าในตอนเช้าเราตื่นขึ้นมา ในร่างกายนี้ พร้อมกับความรู้และความทรงจำของร่างกายนี้ โดยมีภาระกิจ และหน้าที่ที่ต้องรับผิดชอบ ก็คืองานหรืออะไรที่เราต้องทำในแต่ละวันนั่นแหละ

เมื่อจบวัน สิ่งที่เราทำในวันนี้ก็จะส่งต่อความทรงผ่านร่างกายนี้ไปในวันพรุ่งนี้อีกที เหมือนกับที่เราได้รับมา


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


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

    - เราจะเลิกผลัดวันประกันพรุ่งมั้ยนะ เพราะเรามีเวลาแค่วันเดียว 

    - เราจะรับผิดชอบงานมั้ยนะ หรือเอาเวลาไปใช้ชีวิต เพราะเรามีเวลาแค่วันเดียว

    - เราจะสนใจคนรอบตัวมากขึ้นมั้ยนะ หรือน้อยลง เพราะยังไงเราก็มีเวลาแค่วันเดียว

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

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

    ผมไปฟังบทสัมพาสนึง เค้าบอกว่า สมองเราให้ค่ากับอนาคตน้อย ยิ่งไกล ยิ่งน้อยลง งั้นผมก็ทำแค่เพื่อวันนี้กับวันพรุ่งนี้แล้วกัน


ผมเลิกสนใจแต่อนาคต จนลืมปัจจุบัน และคงไม่ทำอะไรที่มันบ้าพอขนาดจะทำให้ตัวเราในวันพรุ่งนี้เดือดร้อน

อย่างน้อยถ้าวันนี้เป็นวันสุดท้ายจริงๆ ถ้าพรุ่งนี้ไม่ได้ตื่นขึ้นมา ผมก็จะได้ไม่เสียใจ เพราะเราได้ทำในสิ่งที่เราอยากทำแล้ว และก็ไม่ทำอะไรบ้าจนเกินไป เพราะถ้าพรุ่งนี้เราอาจจะยังตื่นขึ้นมาอยู่ก็ได้ 


อย่าลืมใช้ชีวิตในส่วนของตัวเองวันนี้ พยายามช่วยแก้ปัญหาที่ตัวเราเมื่อวานสร้างไว้ แล้วก็มีน้ำใจและสงสารตัวเองในวันพรุ่งนี้ด้วย



เขียนอะไรไม่รู้ ไร้สาระ

เปลี่ยน Repo Ubuntu เป็นของ KU (ม.เกษตร)

     วันนี้เจอเคส Ubuntu 24.04 ออกเน็ตต่างประเทศไม่ได้ เลยติดตั้งอะไรไม่ได้เลย 


ถ้าออกต่างประเทศไม่ได้ก็ เปลี่ยนมาใช้ repo ในไทย ไปใช้ของ ม.เกษตร แทนก็ได้

เมื่อก่อนก็มีข้อดีอยู่นะ วิ่งในประเทศก็จะเร็วกว่า แต่ปัจจุบันเน็ตแรงมาก เลยบอกว่าเป็นข้อดีไม่ได้


เริ่ม 


เคลีย configure repo เก่าใน ubuntu ก่อน

sudo mkdir -p /etc/apt/ubuntu-disabled

sudo mv /etc/apt/sources.list.d/* /etc/apt/ubuntu-disabled/


แล้วมาเขียน file configure ใหม่ แล้วแต่ใครถนัด vi หรือ nano

sudo nano /etc/apt/sources.list.d/ubuntu.sources

or

sudo vi /etc/apt/sources.list.d/ubuntu.sources


Copy พวกนี้ไปใส่ ในไฟล์

Types: deb

URIs: http://mirror1.ku.ac.th/ubuntu/

Suites: noble noble-updates noble-backports noble-security

Components: main restricted universe multiverse

Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg


เซฟแล้วออกมาได้เลย


ตรงนี้จะมาเคลีย cache หรือค่าต่างๆที่เครื่องจำไว้

sudo apt clean

sudo rm -rf /var/lib/apt/lists/*


แล้วก็ให้เครื่องเราไปอ่านของใหม่ 

sudo apt update


ถ้าไม่เจอ error สวยงามอย่างนี้ก็เป็นอันจบ



อันนี้เป็นเครื่อง LAB เลยไม่มีประเด็น แต่อีกเครื่องที่เจอปัญหา 

     ผมเคย apt install ไปแล้วไม่ผ่าน ก็ต้องซ่อมหน่อย หลังจากผมลองลง net-tools ไปแล้วฟ้องมาว่าให้ลอง apt --fix-broken install ผมก็ copy มาวางเลย enter ไป รอเสร็จแล้วลง net-tools ใหม่เป็นอันจบงาน

    เพิ่มเติมอีกหน่อย อันนี้จะได้แค่ repo ของ ubuntu นะครับแต่ตัวอื่นก็ยังใช้ไม่ได้นะ service อื่นๆที่ใช้ repo ของตัวเองที่ไม่ใช่ ubuntu ก็ยังเป็นประเด็นอยู่ เช่น ถ้าอยากได้ nginx version ใหม่ที่ต้อง download จาก nginx เอง (ของ ubuntu ก็มีนะแต่เก่ากว่า) หรือพวก zabbix หรืออื่นๆก็จะยังคงต้องวิ่งไปที่ repo ของตัวเองอยู่


ไว้มาต่อพวก proxy, local repo อีกที

     มีข้อดีเยอะกว่า เช่น เครื่อง server เราออกเน็ตไม่ได้เลย ขอแค่เครื่องที่เราใช้เป็น proxy ออกเน็ตได้ ไปต่างประเทศได้ เครื่องอื่นที่ชี้มาก็ใช้ได้เหมือนกัน


วันพฤหัสบดีที่ 10 เมษายน พ.ศ. 2568

Python Virtual Environment Part1 Overview

 

Virtual Environment คืออะไร?

เวลาเราเขียนโปรแกรม (โดยเฉพาะภาษา Python) เรามักจะต้องใช้ไลบรารีหรือเครื่องมือจากคนอื่นมาช่วย เช่น requests, numpy, django อะไรแบบนี้ ซึ่งแต่ละโปรเจกต์อาจจะใช้ไลบรารีต่างเวอร์ชันกัน เช่น โปรเจกต์ A ใช้ Django 3 แต่โปรเจกต์ B ใช้ Django 4 ถ้าเราติดตั้งรวมกันในเครื่องเดียว มันจะตีกันได้ง่ายๆ เลย

Virtual Environment หรือเรียกสั้นๆ ว่า venv คือพื้นที่แยกเฉพาะของแต่ละโปรเจกต์ ที่เราสามารถติดตั้งไลบรารีที่ต้องใช้ได้แบบไม่เกี่ยวกับของระบบหรือโปรเจกต์อื่น ทำให้แต่ละโปรเจกต์มี "โลกส่วนตัว" ของมัน


ทำไมต้องใช้ Virtual Environment?

  • กันปัญหาความเข้ากันไม่ได้ของไลบรารี

    เช่น โปรเจกต์เก่าใช้เวอร์ชันเก่า โปรเจกต์ใหม่ใช้เวอร์ชันใหม่ ถ้าไม่มี venv จะมั่วไปหมดเลย

  • ง่ายต่อการจัดการ

    เรารู้เลยว่าโปรเจกต์นี้ต้องการไลบรารีอะไรบ้าง แค่ดูไฟล์ requirements.txt แล้วติดตั้งใน venv ได้เลย

  • ย้ายเครื่องก็ง่าย

    ถ้าเราจะส่งโปรเจกต์ให้คนอื่นแค่บอกให้สร้าง venv แล้วติดตั้งตาม requirements.txt ทุกอย่างก็พร้อมรัน

     

🔝 venv ที่ได้รับความนิยม

1. venv (builtin)

เป็นเครื่องมือสร้าง virtual environment ที่ติดมากับ Python ตั้งแต่เวอร์ชัน 3.3 ขึ้นไป

✅ ข้อดี:

  • ติดมากับ Python ไม่ต้องติดตั้งเพิ่ม

  • ใช้งานง่าย คำสั่งไม่ซับซ้อน (python -m venv env)

  • รองรับการใช้งานทั่วไปได้ดี

❌ ข้อเสีย:

  • ไม่มีระบบจัดการ dependency แบบ lock file (เช่น Pipfile.lock หรือ poetry.lock)

  • ต้องใช้ pip แยกต่างหากในการจัดการแพ็กเกจ

🎯 ทำไมถึงได้รับความนิยม:

  • เพราะมัน “ติดมากับ Python” เลยไม่ต้องคิดเยอะ ใช้ได้เลย เหมาะกับมือใหม่หรือคนที่อยากควบคุมแบบเรียบง่าย


2. virtualenv

เป็นเครื่องมือรุ่นก่อนที่ venv จะถูกเพิ่มเข้า Python

✅ ข้อดี:

  • ใช้ได้กับ Python ได้หลายเวอร์ชัน รวมถึง Python 2.x

  • ทำงานเร็วกว่า venv เล็กน้อย

  • มีฟีเจอร์เสริมบางอย่างมากกว่า venv

❌ ข้อเสีย:

  • ต้องติดตั้งแยก (pip install virtualenv)

  • ถ้าคนไม่รู้จัก อาจสับสนกับ venv

🎯 ทำไมยังมีคนใช้:

  • ยังใช้ในโปรเจกต์เก่า หรือในระบบที่ต้องรองรับ Python 2.x

  • บางคนคุ้นมือจากยุคก่อน venv จะมี


3. Pipenv

เป็นเครื่องมือที่รวมทั้ง virtual environment และการจัดการ dependency แบบมี lock file

✅ ข้อดี:

  • จัดการ environment + package ได้ในคำสั่งเดียว (pipenv install)

  • มี Pipfile และ Pipfile.lock สำหรับจัดการ dependency อย่างชัดเจน

  • แยก dev dependencies ได้

❌ ข้อเสีย:

  • บางครั้งทำงานช้า

  • มีบั๊กหรือปัญหากับ Python เวอร์ชันใหม่ๆ บ้าง

  • โครงการ Python เองหยุดแนะนำ (แม้ยังใช้ได้)

🎯 ความนิยมลดลง:

  • เคยเป็นทางเลือกหลักช่วงหนึ่ง แต่หลายคนหันไปใช้ poetry หรือ venv + requirements.txt แทน


4. Poetry

เครื่องมือรุ่นใหม่ที่มาแรงมากสำหรับ Python packaging + dependency management

✅ ข้อดี:

  • ใช้ไฟล์ pyproject.toml ซึ่งเป็นมาตรฐานใหม่

  • จัดการ dependency และ environment ได้ในตัว

  • สร้าง package เพื่อแจกจ่ายได้ง่าย

  • ทำงานเร็ว และมีระบบ lock ที่ดี

❌ ข้อเสีย:

  • ต้องเรียนรู้เพิ่ม (แต่ไม่ยาก)

  • ไม่ติดมากับ Python ต้องติดตั้งเพิ่ม

🎯 ทำไมเริ่มได้รับความนิยม:

  • เป็นเครื่องมือ “ครบจบในตัวเดียว” สำหรับคนที่ต้องการความเป็นระเบียบและวางแผนพัฒนาโปรเจกต์ระยะยาว

  • โดดเด่นในสาย open source และ professional dev



5. Anaconda / Miniconda

✅ ข้อดี:

  • มีระบบจัดการ environment ในตัว (conda env create)

  • ใช้ package manager ของตัวเองชื่อ conda ที่จัดการ dependency ได้แม่นยำมากกว่าการใช้ pip อย่างเดียว

  • มีไลบรารีสาย data science ติดมาพร้อม เช่น numpy, pandas, scikit-learn, jupyter ฯลฯ

  • เหมาะกับงานที่ต้องการติดตั้งแพ็กเกจที่ซับซ้อนหรือ compile ยาก เช่น opencv, tensorflow ในบางระบบ

❌ ข้อเสีย:

  • ตัว Anaconda ใหญ่พอสมควร (กินพื้นที่เยอะมาก)

  • อัปเดตช้ากว่า pip บางทีเวอร์ชันใหม่ๆ มาไม่ทัน

  • ไม่ใช่มาตรฐานตรงๆ ของ Python packaging (ไม่ใช้ pyproject.toml)

  • บางครั้ง conda กับ pip ใน environment เดียวกันอาจตีกันได้

🎯 ทำไมถึงได้รับความนิยม:

  • ในกลุ่มสาย Data Science, AI, ML, วิจัย ใช้เยอะมาก เพราะใช้ง่ายและติดตั้งแพ็กเกจยากๆ ได้สบาย

  • Miniconda เป็นเวอร์ชันเล็กกว่า เลือกติดตั้งเฉพาะที่ต้องใช้ได้ (แนะนำสำหรับคนที่ไม่อยากได้ของแถมเยอะ)


เปรียบเทียบเครื่องมือจัดการ Virtual Environment สำหรับ Python

เครื่องมือติดกับ Pythonใช้งานง่ายมีระบบ lockรายละเอียดความนิยม
venvจุดเด่น : เบา เร็ว ใช้ได้ทันที
เหมาะกับสายงาน : ทั่วไป, dev มือใหม่
⭐⭐⭐⭐⭐
virtualenv
จุดเด่น : รองรับหลายเวอร์ชัน รวมถึง Python 2
เหมาะกับสายงาน : โปรเจกต์เก่า, ระบบยืดหยุ่น
⭐⭐⭐⭐
Pipenv⚠️จุดเด่น : จัดการ env + package พร้อมกัน
เหมาะกับสายงาน : โปรเจกต์ระดับกลาง
⭐⭐
Poetry⚠️
จุดเด่น : ครบเครื่อง จัดการ dependency + build package ได้
เหมาะกับสายงาน : dev จริงจัง, สาย production
⭐⭐⭐⭐
Anaconda✅ (conda)
จุดเด่น : ใช้กับแพ็กเกจสาย data science ได้ดี ติดตั้งง่าย
เหมาะกับสายงาน : data science, ML, งานวิจัย
⭐⭐⭐⭐⭐

วันอังคารที่ 8 เมษายน พ.ศ. 2568

Python Mutable arguments

     อันนี้เป็นส่วนเสริมของบทความเรื่อง Python PEP 8 นะครับ 

    จะมีข้อนึงบอกว่า ควรหลีกเลี่ยงการใช้ Mutable Default Arguments งั้นเราก็ต้องรู้จัก Mutable Arguments ก่อน แล้วมันสร้างปัญหาให้กับเราได้ยังไง แต่ก่อนจะไปรู้จัก Mutable Arguments มารู้จักกับ Immutable Arguments กันก่อนเพื่อให้เข้าใจง่ายขึ้น


Immutable Arguments หรือ Immutable Data Types คือ 

  • ประเภทของข้อมูลที่ไม่สามารถเปลี่ยนค่าได้ หลังจากที่ถูกสร้างขึ้น
  • หากต้องการเปลี่ยนค่า Python จะสร้าง object ใหม่ แล้วให้ตัวแปรอ้างอิงไปที่ object ใหม่นั้นแทน

  • การเปลี่ยนค่าของ Immutable Object จะไม่ส่งผลกระทบต่อ object เดิม

  • ตัวอย่างของตัวแปรประเภท Immutable ก็จะมี int, float, bool, str, tuple 

    ถ้าบอกอย่างนี้ อาจจะงง เพราะเวลาเราใช้ตัวแปรพวกนี้ เราก็เปลี่ยนค่าได้หนิ ซึ่งในมุมของคนเขียนใช่ครับ ตามนั้นเลย แต่ในมุมของการทำงานของภาษา มันจะไม่ได้เป็นการเปลี่ยนค่า แต่จะเป็นการจอง memory ใหม่ เก็บค่าใหม่เข้าไป แล้วตัวแปรนั้นก็เปลี่ยนมาชี้ที่ memory address ใหม่ 

    ถ้าอธิบายให้เข้าใจง่ายๆก็เหมือนตัวแปรเป็นชื่อกล่อง ซึ่งกล่องนี้เก็บของอยู่คือค่าที่เรากำหนดไว้ เวลาเราเปลี่ยนค่า มันไม่ได้เป็นการใช้กล่องเดิมแล้วเปลี่ยนของทีอยู่ข้างใน แต่เป็นการทิ้งกล่องเดิมไปเลย แล้วเอากล่องใหม่มาติดป้ายชื่ออันเดิม ไม่รู้ว่าจะช่วยให้เข้าใจหรือจะงงกว่าเดิมนะอันนี้ แต่ก็ประมาณนี้

   ซึ่งตัวแปรประเภทนี้ เวลาเขียนมันก็จะเป็นอิสระจากกันเลย ไม่ว่าจะเป็นการส่งค่าเข้าไปใน function หรือเอาตัวแปรนี้ไปกำหนดค่าให้ตัวแปรอื่น มันก็จะแยกกันทำงานอย่างชัดเจน ของใครของมัน

ยกตัวอย่างเช่น
เราเขียนโปรแกรม กำหนดค่าตัวแปร

a = 2
b = a

แล้วอยู่ดีๆเราเกิดไปเปลี่ยนค่าตัวแปร b เช่น

b += 5

หลังจากนั้นเราลองเช็กค่าของตัวแปรทั้งสองดู

a =2
b = 7

ซึ่งอย่างนี้ก็ปกติอย่างที่ควรจะเป็น เพราะเป็นตัวแปรคนละตัวกัน แต่ พวก Mutable ไม่ได้เป็นแบบนี้


Mutable Arguments หรือ Mutable Data Types คือ 
  • ประเภทของข้อมูลที่สามารถเปลี่ยนแปลงค่าได้ โดยที่ object ยังคงเป็นตัวเดิม
  • สามารถเปลี่ยนแปลงค่าได้โดย ไม่ต้องสร้าง object ใหม่

  • การเปลี่ยนค่า Mutable Object จะมีผลต่อ object เดิม และส่งผลให้ค่าที่อ้างอิงไปยัง object นั้นเปลี่ยนไปด้วย

  • ตัวอย่างตัวแปลประเภท Mutable คือ list, dict, set แล้วก็ bytearray

เวลาเราเอาตัวแปรประเภท Mutable นี้ไปกำหนดค่าให้ตัวแปรอื่น มันไม่ได้เป็นการสร้าง object ใหม่ หมายถึงจอง memory address ใหม่น่ะ แต่มันเป็นการบอกให้ตัวแปรใหม่ ชี้ไปที่ memory address เดียวกันเลย เพราะฉนัน เวลาแก้ตัวที่ 2 ตัวแรกเปลี่ยนด้วย ลองดู

a = [1,2,3]
b = a
b[0] = 5

แล้วมาเช็กค่า จะได้เป็น
a = [5, 2, 3]
b = [5, 2, 3]

ผมก็ไม่เข้าใจ มันจะมีตัวแปรแบบนี้เพื่อ????????????

เค้าว่ามันมีประโยชน์นะ คือ

ใช้เมื่อ...
ต้องการจำสถานะในฟังก์ชันโดยไม่สร้าง classเช่น counter, logger, cache
ต้องการหลีกเลี่ยง global variablesทำให้โค้ดเป็น modular มากขึ้น
ต้องการ performance optimizationเช่น การ cache ค่าในการคำนวณซ้ำ ๆ

แต่ผมไม่ได้ใช้อ่านะ มาดูวิธีป้องกันดีกว่า

📌กลุ่มแรกเป็นปัญหาที่เกี่ยวกับการใช้ Mutable Arguments กับ ตัวแปรทั่วไป

    หากข้อมูลเราไม่ซับซ้อน เป็นข้อมูล level เดียว 

สามารถกำหนดค่าให้กับตัวแปรโดยใช้คำสั่งสร้าง object นั้นๆขึ้นมาใหม่ เช่น list() dict() set()

b = set(a)
b = list(a)
b = dict(a)

หรือใช้ .copy ก็ได้ ซึ่งวิธีนี้ใช้ได้กับตัวแปรทั้ง 3 แบบเลย ทั้ง list set dict เลย

b = a.copy()

ในกรณีที่เป็น list สามารถทำแบบนี้ได้อีกวิธี
b = a[:] จะเป็นการ copy ทั้งหมดมา

    แต่หากข้อมูลเราซับซ้อน มีหลายชั้น เช่น list ซ้อน list , dict ซ้อน dict หรือ เป็น json เลย ให้ใช้วิธีนี้

import copy

b = copy.deepcopy(a)

สรุปกลุ่มแรกนะครับ

Shallow Copy (ได้เฉพาะ object ชั้นนอก)

ประเภทวิธี copy ที่ใช้ได้
lista.copy() / list(a) / a[:]
dicta.copy() / dict(a)
seta.copy() / set(a)

 Deep Copy (copy ทุกชั้นแบบแยกขาด)

ต้องใช้:

import copy deep = copy.deepcopy(a)


📌กลุ่ม 2 เป็นปัญหาที่เกี่ยวกับการใช้ Mutable Arguments กับ function

 กรณีที่ 1: ใช้ Mutable Default Argument ในฟังก์ชัน


def add_item(item, item_list=[]): # ❌ ค่าถูกแชร์ระหว่างการเรียกใช้ item_list.append(item) return item_list print(add_item("apple")) # ✅ ['apple'] print(add_item("banana")) # ❌ ['apple', 'banana'] (ค่าถูกแชร์) print(add_item("cherry")) # ❌ ['apple', 'banana', 'cherry']

💡 ปัญหา: item_list ถูกแชร์กันข้ามการเรียกใช้ฟังก์ชัน ทำให้ค่าถูกเก็บสะสมเรื่อย ๆ

วิธีแก้ไข


def add_item(item, item_list=None): # ✅ ใช้ None แทน if item_list is None: item_list = [] # ✅ สร้าง list ใหม่ในแต่ละครั้ง item_list.append(item) return item_list print(add_item("apple")) # ✅ ['apple'] print(add_item("banana")) # ✅ ['banana'] print(add_item("cherry")) # ✅ ['cherry']

 กรณีที่ 2: ส่ง Mutable Object เข้าไปในฟังก์ชัน


def modify_list(my_list): my_list.append("new item") data = ["old item"] modify_list(data) print(data) # ✅ ['old item', 'new item'] (ค่าเปลี่ยนแปลง!)

💡 สังเกต: data ถูกแก้ไขโดยตรงเพราะ list เป็น Mutable Object

ถ้าต้องการป้องกันการเปลี่ยนแปลงโดยไม่ตั้งใจ ให้ใช้ .copy()


def modify_list(my_list): new_list = my_list.copy() # ✅ ใช้สำเนาแทน new_list.append("new item") return new_list data = ["old item"] new_data = modify_list(data) print(data) # ✅ ['old item'] (ค่าเดิมไม่เปลี่ยน) print(new_data) # ✅ ['old item', 'new item']


กลุ่มแรกเป็นปัญหาที่เกี่ยวกับการใช้ Mutable Arguments กับ ตัวแปรทั่วไป

Python map(), filter() vs comprehensions และ lambda

    หลังจากที่เรารู้จัก List Comprehensions & Dictionary Comprehensions  ต่อมาเรามารู้จักอีก 2 คำสั่งที่ให้ผลคล้ายๆกัน คือ map และ filter 


เอาจริงๆก็ผมไม่ได้ใช้ 2 function นี้นะ แต่เค้าบอกให้เรียนก็เรียนๆไป คิดว่าน่าจะได้ใช้แหละ


มาดูความหมายและวิธีใช้งานกัน

map(function, iterable) ใช้สำหรับแปลงข้อมูลใน iterable ทุกตัว โดยใช้ function

filter(function, iterable) ใช้คัดกรองเฉพาะค่าที่ function คืนค่าเป็น True

 iterable หมายถึงตัวแปรหรือ object ที่สามารถ loop ได้นะครับ


map  

    การใช้ map จะต้องมี function กับ iterable ไว้ loop นะครับ โดยที่การทำงานจะประมาณว่า loop ข้อมูล แล้วแปลงค่าผ่าน function แล้วเอาค่าที่ return จาก function นั้นมาแทนที่

เริ่มจากเราต้องมี function ก่อน เพื่อให้ map ใช้ในการแปลงค่า ในตัวอย่างนี้ ให้เป็น function หาพื้นที่สี่เหลี่ยมจตุรัส เอาจริงๆก็ function ยกกำลัง 2 แหละ

ต่อมาเราต้องมี ข้อมูลอะไรสักอย่างที่มัน loop ได้ ตัวอย่างนี้เรามี list ความยาวด้านอยู่

list_length = [1,2,3,4]

def square_area(length: int) -> int:
    return length*length

list_square_area = list(map(square_area,list_length))


ไปลองมา เหมือนต้องใส่ list ครอบด้วย เพราะ function map จะ return มาเป็น object map

ครับ แล้วเราก็ได้ function การแปลงค่ามา ซึ่งถ้าเอาไปเทียบกับ list comprehension มันก็จะประมาณนี้

list_length = [1,2,3,4]
list_square_area = [_*_ for _ in list_lange]

# or
list_length = [1,2,3,4]
def square_area(length: int) -> int:
    return length*length

list_square_area = [square_area(_) for _ in list_length]


หรือถ้าเป็นแบบเต็มๆก็

list_length = [1,2,3,4]
list_square_area = []

for length in list_length:
    square_area = length*length
    list_square_area.append(square_area)

# or
list_length = [1,2,3,4]
list_square_area = []

def square_area(length: int) -> int:
    return length*length

for length in list_length:
    area = square_area(length)
    list_square_area.append(area)


ก็จะประมาณนี้แหละครับ


filter

    ต่อมาเป็นคิวของคำสั่ง filter  ตัวนี้ทำงานคล้ายกับคำสั่ง map ครับ แต่เปลี่ยนจาก เอาค่าที่ได้จาก function มา replace เป็นใช้ function ในการเช็กว่าค่านี้จะเอาป่าว ถ้า function return เป็น True ก็จะเก็บไว้ แต่ถ้าเป็น False ก็ทิ้งไป ตัวนี้ไม่เอา จบเท่านี้เลยครับ


จากที่อ่านผมก็มีคำถามว่า แล้วจะมี map กับ filter ไว้ทำไม คำตอบที่ผมได้มาคือ

    map() กับ filter() ว่า “ไม่จำเป็นต้องสร้าง list ทันที” เพราะทั้งคู่จะคืนค่าเป็น iterator แบบ lazy evaluation นั่นแปลว่า มันจะยังไม่คำนวณอะไรเลย จนกว่าจะมีคนไปดึงข้อมูลออกมาใช้จริงๆ เช่นแปลงเป็น list หรือเข้าไป loop อ่านค่าจากตัวมัน และ ถ้ามีข้อมูลเป็นล้านรายการ มันจะประหยัด memory มาก เพราะไม่โหลดทั้งหมดเข้าหน่วยความจำ


map() กับ filter() นิยมใช้ร่วมกับ lambda 

lambda คืออะไร?

lambda คือ ฟังก์ชันแบบย่อ (anonymous function)
ไม่มีชื่อเหมือนฟังก์ชันปกติ (def) และเขียนได้ในบรรทัดเดียว

รูปแบบการเขียน:


lambda arguments: expression

  • arguments → ตัวแปรรับค่า

  • expression → นิพจน์ที่คืนค่ากลับ (return โดยอัตโนมัติ)

  • ไม่มีคำว่า return


ถ้าให้อธิบายแบบภาษาที่ผมเข้าใจก็ประมาณว่า
ใช้คำสั่ง lambda แล้วก็ตามด้วยชื่อตัวแปร อะไรก็ได้ ใส่ๆไปเลย คั่นด้วย : ทีนึง 
จากนั้นก็ใส่ expression หรือ process ที่อยากให้ function ทำงาน 
ซึ่งข้อจำกัดคือ ใส่ได้แค่ expression เดียว ต่อให้ใส่ได้ก็ไม่ควร อ่านยาก



ตัวอย่าง map ด้านบน

list_length = [1,2,3,4]

def square_area(length: int) -> int:
    return length*length

list_square_area = list(map(square_area,list_length))


นำมาเขียนใหม่เป็น lambda ได้แบบนี้

list_length = [1,2,3,4]

list_square_area = list(map(lambda length: length*length, list_length))



หน้าแบบที่เค้านิยมกันก็

list_length = [1,2,3,4]

list_square_area = list(map(lambda i: i ** 2, list_length))




วันอาทิตย์ที่ 6 เมษายน พ.ศ. 2568

Python List Comprehensions & Dictionary Comprehensions

 อันนี้ใช้บ่อยอยู่นะ ก๊อบมาลงละกัน ให้เนื้อหามันครบๆ


    List Comprehensions คือ วิธีสร้าง list แบบกระชับ โดยใช้ไวยากรณ์ที่สั้นกว่า for loop

เอาแบบง่ายๆก่อนนะ ยกตัวอย่างเป็นตัวเลขก่อนละกัน 

สร้าง list 1-10 ปกติก็แค่ range(1,11) แหละนะ แต่มันสำเร็จรูปไป

เอามาเขียนเป็น for ละกัน

ตัวอย่าง code

range_10 = []

for _ in range(1,11):

    range_10.append(_)

ผมใช้ _ นะครับ เค้าบอกว่าตัวแปรแบบใช้แล้วทิ้ง ก็แนะนำให้ใช้ _ หรือใครสะดวกใช้ i ก็ได้ ไม่ติด

append เป็นคำสั่งที่ใช้กับตัวแปรประเภท list ใน python (ภาษาอื่นจะเรียก array) ใช้สำหรับเพิ่มค่าต่อท้ายเข้าไปใน list


พอมาเขียนเป็น List Comprehensions ก็จะเหลือแค่นี้

ตัวอย่าง code

range_10 = [_ for _ in range(1,11)]


ใช้ _ อาจมองไม่ชัด จัด i มาให้อีกอัน

range_10 = [i for i in range(1,11)]


จบแล้วบันทัดเดียว ให้มองแยกเป็น 2 อันนะครับ คือ

  • ตัวสีน้ำเงิน ก็คือรูปแบบ for ปกติ
  • ตัวสีแดง คือค่าที่จะถูกเพิ่มเข้าไปใน list เหมือนตอนที่ใช้คำสั่ง append

จากตัวอย่างนี้เหมือนจะไม่ค่อยมีประโยชน์เลยเนาะ ส่วนใหญ่ผมใช้ loop get ค่าออกมาจาก object หรือพวก query (ถ้าใครมีวิธีดีๆแนะนำผมได้นะ)

เราสามารถเพิ่ม if หรือ if else ไปใน list comprehensoin ได้ด้วยนะ เช่น


ตัวอย่าง code List Comprehensions + if

range_10 = [_ for _ in range(1,11) if _%2 == 0]

ก็จะเหมือนเอาเฉพาะเลขคู่มา


ตัวอย่าง code List Comprehensions + if else

a = ['1', '2', '3', 'a', 'b', 'c']

result = [int(_) if _.isdigit() else 0 for _ in a]

อันนี้ loop เช็กว่าค่าแต่ละอันเป็นจำนวนเต็มหรือเปล่า ถ้าใช่ให้แปลงเป็น int ถ้าไม่ใช่ ให้ fix เป็น 0


    จริงๆมันก็คือ loop ธรรมดานี่แหละ แค่เขียนย่อให้มันสั้นลง ควรใช้กับ loop ง่ายๆแต่ยังจำเป็นต้อง Loop ถ้าซับซ้อนไปเขียนแบบเต็มดีกว่า อ่านง่ายแก้ง่ายกว่า เคยลองเลย ปวดหัวตอนกลับมาแก้


    Dict Comprehensions อันนี้ก็แทบเหมือนกันเลย ต่างกันแค่ผลที่ได้จะเป็น dict กับวิธีเขียนนิดหน่อย

ถ้าเป็น list จะใช้ [ _ for _ in list_data ]

ถ้าเป็น dict จะเปลี่ยนเป็น {key:value for _ in list_data}

ซึ่งเราจะเอา _ ไปใส่แทน key หรือ value ก็ได้ 

    ตัวอย่างที่ผมใช้งานจริงคือผมเขียนโปรแกรมไปอ่านค่า config จากอุปกรณ์ แล้วใช้ key เป็นชื่อ แล้วก็ value เป็นค่าที่ได้

ตัวอย่าง code

config = getconfig(ip='192.168.1.1', user='admin', passwd='password')

json_config = {_.name:_.value for _ in config}


    ข้อดีของ dict คือเราใช้ชื่อเป็น key เลย ง่ายต่อการจำ และเข้าใจครับ แต่ก็ใช้ mem เยอะกว่านิดหน่อย ซึ่งข้อมูลผมไม่ได้เยอะขนาดนั้นเลยไม่ซีเรียส


ตัว Dict Comprehensions ก็ใช้ if else ได้เหมือนกับ ListComprehensions เลยนะ



สรุปนะครับ 

ข้อดี สั้น ถ้าเราจำเป็นต้อง loop เพื่อสร้าง list หรือ dict ก็เหมาะเลย

แต่ไม่ควรใช้กับพวกที่เงื่อนไขเยอะๆหรือมี process ที่ซับซ้อน ไม่งั้นตอนกลับมาแก้ กุมขมับแน่นอน


Python Docstrings - VS-Code

Docstrings เป็นตัวช่วยที่สำคัญตัวนึงเลยสำหรับผม อันนี้เคยไปดูมาจาก Youtube ช่องนึงมา ใครขี้เกียจอ่านก็กด Link ไปดูได้เลยครับ


เริ่มจาก Docstrings  คืออะไร

     ถ้าให้ผมอธิบายมันก็จะเป็นเหมือน comment หลายบันทัดแหละ แต่ผมจะไม่ได้ใช้งานแบบนั้นเท่าไหร่ เพราะผมใช้ # ในการ comment หมดเลย แล้วด ใช้ Docstrings ในการอธิบายการทำงานของ function ที่เขียนขึ้นมา โดยโครงสร้างก็จะประมาณใช้ double code 3 ตัวเปิด แล้วก็อีก 3 ปิดท้าย

"""อธิบายการทำงานของ function

Args input มีอะไรบ้าง type เป็นอะไร พร้อมคำอธิบายนิดหน่อย

Return มี type เป็นอะไร แล้วก็คำอธิบายนิดหน่อย

"""

ผมใช้ vs-code เป็นหลัก ก็จะมี extendtion ตัวนึงที่ทำงานร่วมกับ Docstrings คือตัวนี้




ไปที่กล้องสี่เหลี่ยมแตกๆด้านซ้ายนะครับ มันคือ extendtion ของ vs-code แล้ว search docstring ได้เลย

ติดตั้งไอตัวเขียวๆเหมือนในรูปนี้แหละ


เวลาใช้งานก็ เขียน function ให้เสร็จก่อน ไปที่ด้านบน ใต้ def แล้วพิมพ์ double code 3 ตัว มันก็จะขึ้นอันนี้มาให้

แล้วเราก็กด enter ได้เลย

หลังจากนั้นมันก็จะขึ้นมาประมาณนี้



คือมีตัวแปรให้หมดเลย เราก็ไปใส่คำอธิบายกับ type เอา ถ้าเรายังเขียนไม่เสร็จ มันก็จะไม่มีพวกนี้ขึ้นมาให้นะ

หลังจากแก้เสร็จของผมก็จะหน้าตาประมาณนี้


เวลาเรียกใช้ ก็จะมีคำอธิบายตามที่เขียนไว้ให้เลย ตัวอย่างก็ประมาณนี้



ก็จะช่วยให้เราเขียนโปรแกรมได้ง่ายขึ้น ไม่ต้องจำว่ามี input อะไรบ้าง return gxHovtwi

ตัวอย่างนี้เป็น code ส่ง alert telegram นะครับ จริงๆเค้า limit ไว้ที่ 4026 ตัวอักษรมั้ง ประมาณนี้แหละ แต่ผมว่า 3500 ก็เยอะละ ถ้าจะยาวขนาดนี้ไปอ่าน log เอาเถอะ