1. Python Programming 101 (พื้นฐานการเขียนโปรแกรมไพธอน)
บทนี้มีวัตถุประสงค์เพื่อปูพื้นฐานภาษา Python ตั้งแต่เริ่มต้น เนื้อหาถูกออกแบบมาให้ครอบคลุมโครงสร้างภาษาที่สำคัญ ตั้งแต่การประกาศตัวแปร การตัดสินใจ การวนซ้ำ ฟังก์ชัน ไปจนถึงการเขียนโปรแกรมเชิงวัตถุ (OOP) เพื่อเตรียมความพร้อมสำหรับการเขียนโปรแกรมคอมพิวเตอร์และหุ่นยนต์
1.1. Variables and Data Types (ตัวแปรและชนิดข้อมูล)
การเขียนโปรแกรมคือการสั่งให้คอมพิวเตอร์จัดการกับ "ข้อมูล" (Data) ดังนั้นสิ่งแรกที่ต้องสร้างคือ "ตัวแปร" (Variable)
ตัวแปรเปรียบเสมือน "กล่อง" ที่มีการแปะป้ายชื่อกำกับ ภายในกล่องสามารถบรรจุข้อมูลต่างๆ ลงไปได้ และเมื่อต้องการใช้งานข้อมูลนั้น สามารถทำได้โดยการเรียกชื่อที่ระบุไว้บนป้ายหน้ากล่อง
ภาษา Python เป็นภาษาแบบ Dynamic Typing หมายความว่า ผู้เขียนโปรแกรมสามารถสร้างตัวแปรขึ้นมาได้ทันทีโดยไม่ต้องระบุชนิดข้อมูลล่วงหน้า ตัวแปลภาษา (Interpreter) จะตรวจสอบชนิดของข้อมูลให้เองอัตโนมัติขณะทำงาน
1.1.1. Common Data Types (ชนิดข้อมูลที่พบบ่อย)
ในการเขียนโปรแกรมทั่วไปและงานหุ่นยนต์ เราจะพบเจอข้อมูลหลักๆ อยู่ 4 ชนิด ได้แก่:
Integer (int): จำนวนเต็ม คือตัวเลขที่ไม่มีจุดทศนิยม ใช้สำหรับนับจำนวนสิ่งของ ลำดับ หรือค่าคงที่ที่ไม่ต้องการความละเอียด เช่น จำนวนล้อ, รหัสประจำตัว (ID)
Float (float): จำนวนจริง คือตัวเลขที่มีจุดทศนิยม ใช้สำหรับข้อมูลที่ต้องการความละเอียดสูง เช่น ค่าที่อ่านได้จากเซนเซอร์, พิกัด (x, y), หรือความเร็วของหุ่นยนต์
String (str): ข้อความ คือชุดตัวอักษรที่นำมาเรียงต่อกัน ต้องเขียนอยู่ภายในเครื่องหมายคำพูด (Quotes) เสมอ เช่น ชื่อหุ่นยนต์, ข้อความแจ้งเตือน (Log)
Boolean (bool): ค่าความจริงทางตรรกศาสตร์ มีเพียง 2 ค่าเท่านั้นคือ
True(จริง) และFalse(เท็จ) ใช้สำหรับการตัดสินใจของหุ่นยนต์ เช่น "เจอกำแพงหรือไม่?", "แบตเตอรี่หมดหรือยัง?"
ตัวอย่างการประกาศตัวแปรและการตรวจสอบชนิดข้อมูล
1# 1. Integer: Whole numbers
2robot_id = 101
3wheel_count = 4
4
5# 2. Float: Decimal numbers
6battery_voltage = 24.5
7pi_value = 3.14159
8
9# 3. String: Text inside quotes
10robot_name = "Batly_R1"
11status_msg = 'System Ready'
12
13# 4. Boolean: Logic values (Capital T/F)
14is_active = True
15has_error = False
16
17# Print values to the terminal
18print(robot_name)
19print(battery_voltage)
20
21# Check data types using type() function
22print(type(robot_id)) # <class 'int'>
23print(type(battery_voltage)) # <class 'float'>
24print(type(robot_name)) # <class 'str'>
25print(type(is_active)) # <class 'bool'>
1.1.2. Reserved Words (คำสงวน)
ภาษา Python มีคำศัพท์เฉพาะที่เรียกว่า Keywords ซึ่งถูกสงวนไว้สำหรับใช้งานในระบบ ห้ามนำคำเหล่านี้มาตั้งเป็นชื่อตัวแปร ชื่อฟังก์ชัน หรือชื่อคลาส โดยเด็ดขาด
สามารถสังเกตได้เมื่อพิมพ์คำเหล่านี้ใน VS Code ตัวอักษรจะเปลี่ยนสี (เช่น เปลี่ยนเป็นสีม่วงหรือน้ำเงิน) เพื่อเตือนว่าเป็นคำสั่งเฉพาะ
ตารางด้านล่างแสดงคำสงวนทั้งหมดใน Python 3 ที่พบบ่อย:
Logic & Values |
Control Flow |
Structure |
Others |
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Pro Tip: หากมีการตั้งชื่อตัวแปรซ้ำกับคำสงวน Python จะแจ้ง Error ว่า SyntaxError: invalid syntax
ตัวอย่างสิ่งที่ห้ามทำ
1# BAD: Using reserved words as variable names
2class = "My Robot" # Syntax Error!
3global = 100 # Syntax Error!
4
5# BAD: Overwriting built-in functions (Not a syntax error, but causes bugs)
6# Don't use words like: print, list, str, int, sum, min, max
7sum = 10 + 20
8print(sum)
9
10# Later in the code...
11numbers = [1, 2, 3]
12total = sum(numbers)
13# This will CRASH because 'sum' is now just an integer!
1.2. String Operations (การจัดการข้อความ)
ข้อมูลในการเขียนโปรแกรมไม่ได้มีเพียงตัวเลข แต่ยังรวมถึง "ข้อความ" (Text) ด้วย ไม่ว่าจะเป็นชื่อหุ่นยนต์, สถานะการทำงาน (เช่น "Ready", "Error"), หรือข้อความที่ต้องการแสดงบนหน้าจอ
ในภาษา Python ข้อมูลประเภทข้อความเรียกว่า String ซึ่งมีความยืดหยุ่นในการใช้งานสูง โดยมีเทคนิคที่ควรทราบดังนี้
1.2.1. การสร้างและกำหนดค่า (Declaration)
Python รองรับการสร้างข้อความโดยใช้เครื่องหมาย "ฟันหนู" (Quote) ได้ 3 รูปแบบ ซึ่งแต่ละแบบมีประโยชน์แตกต่างกัน:
Single Quote (') และ Double Quote ("): ใช้งานเหมือนกัน ใช้สำหรับข้อความสั้นๆ บรรทัดเดียว โดยทั่วไปนิยมเลือกใช้แบบใดแบบหนึ่งให้เป็นมาตรฐานเดียวกันทั้งโปรแกรม
Triple Quote (''' หรือ """): ใช้สำหรับข้อความที่มีความยาวหลายบรรทัด โดย Python จะเก็บการเว้นวรรคและการขึ้นบรรทัดใหม่ไว้ทั้งหมด เหมาะสำหรับเขียนคำอธิบายยาวๆ
ตัวอย่างการประกาศตัวแปรข้อความ
1# 1. Single Quote (Most common)
2str1 = 'String Type 1'
3
4# 2. Double Quote (Useful if the string contains a single quote ')
5str2 = "String Type 2"
6
7# 3. Triple Quote (For multi-line strings)
8str3 = '''This is a long text
9that spans across
10multiple lines.'''
11
12print(str3)
1.2.2. การจัดรูปแบบข้อความ (String Formatting)
หัวข้อนี้มีความสำคัญอย่างยิ่งสำหรับการเขียนโปรแกรมหุ่นยนต์ เนื่องจากบ่อยครั้งที่โปรแกรมจำเป็นต้อง "แทรกค่าตัวแปร" ลงไปในข้อความ เช่น การแสดงค่าระดับแบตเตอรี่ หรือค่าพิกัดปัจจุบันจากเซนเซอร์
ภาษา Python มีวิธีจัดการการแสดงผลข้อความหลายวิธี ในที่นี้จะขอยกตัวอย่าง 3 วิธีหลักที่พบได้บ่อย โดยแนะนำให้ฝึกใช้วิธี f-string เป็นมาตรฐาน เนื่องจากกระชับและอ่านเข้าใจได้ง่ายที่สุด
แบบพื้นฐาน (Comma-separated): ใช้เครื่องหมายลูกน้ำ (,) คั่นระหว่างข้อความและตัวแปรภายในคำสั่ง print() วิธีนี้พิมพ์ง่ายที่สุดและเหมาะกับการดูค่าเร็วๆ แต่มีข้อจำกัดคือไม่สามารถจัดรูปแบบความสวยงามหรือปัดทศนิยมได้
แบบเก่า (.format()): ใช้วงเล็บปีกกา {} เป็นช่องว่าง แล้วระบุตัวแปรตามหลัง วิธีนี้อาจเกิดความสับสนหากมีตัวแปรจำนวนมาก
แบบใหม่ (f-string): เพียงใส่ตัวอักษร f ไว้หน้าเครื่องหมาย Quote จะสามารถระบุชื่อตัวแปรลงใน {} ได้ทันที
เทคนิคพิเศษ: สามารถกำหนดรูปแบบตัวเลขได้ เช่น {variable:.3f} เพื่อแสดงทศนิยม 3 ตำแหน่ง ซึ่งมีประโยชน์มากสำหรับการแสดงค่าจากเซนเซอร์
ตัวอย่างการแทรกตัวแปรลงในข้อความ
1# Define variables
2name = "Batly" # String
3battery = 85 # Integer
4pos_x = 1.5501564 # Float (Long decimal)
5
6# --- Method 1: Basic Print (Comma-separated) ---
7# ตัวแปรจะถูกนำมาต่อกันโดยมีช่องว่างคั่นให้อัตโนมัติ
8print("Basic Style: Robot", name, "Battery", battery, "% and X-Position", pos_x)
9
10# --- Method 2: Old Style (.format) ---
11# ตัวแปรจะถูกนำไปแทนที่ใน {} ตามลำดับ
12print("Old Style: Robot {}, Battery {} % and X-Position {}".format(name, battery, pos_x))
13
14# --- Method 3: New Style (f-string) --- ** Recommended **
15# สังเกตตัว f ด้านหน้า สามารถใส่ชื่อตัวแปรลงใน {} ได้เลย
16# หมายเหตุ: .3f ช่วยปัดเศษให้เหลือทศนิยม 3 ตำแหน่งโดยอัตโนมัติ
17print(f"New Style: Robot {name}, Battery {battery} % and X-Position {pos_x:.3f}")
1.3. Input and Output (การรับและแสดงผลข้อมูล)
การสื่อสารระหว่างโปรแกรมและผู้ใช้งาน (User Interface) ในระดับพื้นฐาน ทำได้ผ่านการรับค่าจากคีย์บอร์ดและการแสดงผลทางหน้าจอ โดย Python มีฟังก์ชันมาตรฐานเตรียมไว้ให้ใช้งาน 2 คำสั่งหลัก ได้แก่
1.3.1. การรับข้อมูล (Input)
ใช้คำสั่ง input() เพื่อรับข้อมูลจากผู้ใช้งาน โดยโปรแกรมจะหยุดรอจนกว่าผู้ใช้งานจะพิมพ์ข้อความและกดปุ่ม Enter
ข้อควรระวัง: ข้อมูลที่ได้รับจากฟังก์ชัน input() จะมีชนิดข้อมูลเป็น String (ข้อความ) เสมอ แม้ว่าผู้ใช้งานจะพิมพ์ตัวเลขลงไปก็ตาม หากต้องการนำค่าไปคำนวณทางคณิตศาสตร์ จำเป็นต้องทำการ Type Casting (การแปลงชนิดข้อมูล) ก่อนเสมอ
1.3.2. การแสดงผล (Output)
ใช้คำสั่ง print() เพื่อแสดงข้อความหรือค่าของตัวแปรออกทางหน้าจอ (Terminal)
ตัวอย่างการรับค่าและการแปลงชนิดข้อมูล (Type Casting)
1# 1. Standard Input (Returns string)
2# The variable 'name' will be of type <class 'str'>
3user_name = input("Enter your name: ")
4
5# 2. Input with Type Casting (String -> Integer)
6# Since input() returns a string, we must wrap it with int() for calculation
7user_age = int(input("Enter your age: "))
8
9# 3. Input with Type Casting (String -> Float)
10# Converting to float for decimal numbers
11user_height = float(input("Enter your height (m): "))
12
13# Display the results using f-string
14print(f"User: {user_name}, Age: {user_age}, Height: {user_height:.2f} m")
15
16# Verify data types
17print(f"Type of age variable: {type(user_age)}") # <class 'int'>
18print(f"Type of height variable: {type(user_height)}") # <class 'float'>
1.4. Operators (ตัวดำเนินการ)
ตัวดำเนินการ (Operators) คือเครื่องหมายพิเศษที่กำหนดให้คอมพิวเตอร์ทำการประมวลผลข้อมูล ไม่ว่าจะเป็นการคำนวณทางคณิตศาสตร์ การเปรียบเทียบค่า หรือการจัดการตรรกะ เพื่อให้ได้ผลลัพธ์ใหม่
1.4.1. Arithmetic Operators (ตัวดำเนินการทางคณิตศาสตร์)
ใช้สำหรับการคำนวณตัวเลขพื้นฐาน
Operator |
Name |
Description |
Example |
|---|---|---|---|
|
Addition |
การบวก |
|
|
Subtraction |
การลบ |
|
|
Multiplication |
การคูณ |
|
|
Division |
การหาร (ผลลัพธ์เป็น float เสมอ) |
|
|
Modulus |
การหารเอาเศษ |
|
|
Exponentiation |
การยกกำลัง |
|
|
Floor Division |
การหารปัดเศษทิ้ง (เอาเฉพาะจำนวนเต็ม) |
|
ตัวอย่างการใช้ตัวดำเนินการทางคณิตศาสตร์
1a = 10
2b = 3
3
4# Standard operations
5print(f"Addition: {a + b}") # 13
6print(f"Division: {a / b}") # 3.3333...
7
8# Floor Division vs Modulus
9# Useful for grid navigation or indexing
10print(f"Floor Division: {a // b}") # 3
11print(f"Modulus (Remainder): {a % b}") # 1
12
13# Exponentiation
14print(f"Power: {a ** 2}") # 100
1.4.2. Assignment Operators (ตัวดำเนินการกำหนดค่า)
ใช้สำหรับกำหนดค่าหรืออัปเดตค่าให้กับตัวแปร (ให้ x=5)
Operator |
Description |
Equivalent To |
Result (x=5) |
|---|---|---|---|
|
กำหนดค่าทางขวาให้ตัวแปรทางซ้าย |
|
|
|
บวกค่าเพิ่มแล้วเก็บผลลัพธ์ |
|
|
|
ลบค่าออกแล้วเก็บผลลัพธ์ |
|
|
|
คูณค่าเพิ่มแล้วเก็บผลลัพธ์ |
|
|
|
หารค่าแล้วเก็บผลลัพธ์ |
|
|
|
หารปัดเศษทิ้งแล้วเก็บผลลัพธ์ |
|
|
|
หารเอาเศษแล้วเก็บผลลัพธ์ |
|
|
|
ยกกำลังแล้วเก็บผลลัพธ์ |
|
|
|
Bitwise AND แล้วเก็บผลลัพธ์ |
|
|
|
Bitwise OR แล้วเก็บผลลัพธ์ |
|
|
|
Bitwise XOR แล้วเก็บผลลัพธ์ |
|
|
|
Bitwise Right Shift แล้วเก็บ |
|
|
|
Bitwise Left Shift แล้วเก็บ |
|
|
ตัวอย่างการใช้ตัวดำเนินการกำหนดค่า
1speed = 10.0
2
3# Increase speed by 5
4speed += 5.0 # Same as: speed = speed + 5.0
5print(f"Speed up: {speed}")
6
7# Decrease speed by 2
8speed -= 2.0 # Same as: speed = speed - 2.0
9print(f"Slow down: {speed}")
10
11# Multiply speed by 2
12speed *= 2.0 # Same as: speed = speed * 2.0
13print(f"Double speed: {speed}")
14
15# Divide speed by 4
16speed /= 4.0 # Same as: speed = speed / 4.0
17print(f"Reduce speed: {speed}")
1.4.3. Comparison Operators (ตัวดำเนินการเปรียบเทียบ)
ใช้เปรียบเทียบค่าสองค่า ผลลัพธ์ที่ได้จะเป็น Boolean (True หรือ False) เสมอ
Operator |
Name |
Description |
Example (a=5, b=3) |
|---|---|---|---|
|
Equal |
เท่ากับหรือไม่ |
|
|
Not Equal |
ไม่เท่ากับหรือไม่ |
|
|
Greater than |
มากกว่า |
|
|
Less than |
น้อยกว่า |
|
|
Greater or Equal |
มากกว่าหรือเท่ากับ |
|
|
Less or Equal |
น้อยกว่าหรือเท่ากับ |
|
ตัวอย่างการใช้ตัวดำเนินการเปรียบเทียบ
1target_distance = 1.0
2current_distance = 0.5
3
4# Check if we reached the target
5is_reached = (current_distance >= target_distance)
6print(f"Target Reached: {is_reached}")
7
8# Check equality
9print(f"Is distance exactly 0.5? {current_distance == 0.5}")
1.4.4. Logical Operators (ตัวดำเนินการทางตรรกศาสตร์)
ใช้เชื่อมประโยคเงื่อนไขหลายๆ เงื่อนไขเข้าด้วยกัน
Operator |
Description |
Logic Rule |
Example |
|---|---|---|---|
|
และ |
จริงเมื่อ ทั้งคู่ เป็นจริง |
|
|
หรือ |
จริงเมื่อ อย่างน้อยหนึ่งค่า เป็นจริง |
|
|
นิเสธ (กลับค่า) |
เปลี่ยนจริงเป็นเท็จ เท็จเป็นจริง |
|
ตารางค่าความจริง (Truth Table)
เพื่อความเข้าใจที่ชัดเจนขึ้น ด้านล่างคือตารางแสดงผลลัพธ์ของการนำตัวแปร A และ B มาผ่านตัวดำเนินการทางตรรกศาสตร์
A |
B |
A |
A |
|
|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ตัวอย่างการใช้ตัวดำเนินการทางตรรกศาสตร์
1battery_ok = True
2plugged_in = False
3obstacle_detected = False
4
5# การใช้ not: หุ่นยนต์จะเดินหน้าได้ ทางต้อง "ไม่" เจอสิ่งกีดขวาง
6path_clear = not obstacle_detected
7print(f"Path Clear (not): {path_clear}")
8
9# การใช้ or: หุ่นยนต์มีไฟเลี้ยงระบบ ถ้าแบตเตอรี่ยังมีไฟ "หรือ" เสียบปลั๊กชาร์จอยู่
10has_power = battery_ok or plugged_in
11print(f"Has Power (or): {has_power}")
12
13# การใช้ and: ระบบหุ่นยนต์จะพร้อมเคลื่อนที่ ถ้ามีไฟเลี้ยง "และ" ทางเดินสะดวก
14system_ready = has_power and path_clear
15print(f"System Ready (and): {system_ready}")
1.4.5. Identity Operators (ตัวดำเนินการตรวจสอบวัตถุ)
ตัวดำเนินการนี้ใช้สำหรับตรวจสอบว่า ตัวแปรสองตัวกำลังชี้ไปยัง "วัตถุชิ้นเดียวกัน" (Same Object) ในหน่วยความจำหรือไม่
ข้อควรระวัง: มือใหม่มักสับสนระหว่าง is กับ ==
==(Equality): เช็คว่า "หน้าตา" หรือ "ค่า" (Value) เหมือนกันหรือไม่is(Identity): เช็คว่าเป็น "ของชิ้นเดียวกัน" (Memory Address เดียวกัน) หรือไม่
เปรียบเทียบง่ายๆ:
==เหมือนถามว่า "รถสองคันนี้รุ่นเดียวกัน สีเดียวกันใช่ไหม?"isเหมือนถามว่า "รถสองคันนี้ คือคันเดียวกัน (ทะเบียนเดียวกัน) ใช่ไหม?"
Operator |
Description |
Example |
|---|---|---|
|
เป็นวัตถุชิ้นเดียวกัน (Memory Address ตรงกัน) |
|
|
ไม่ใช่วัตถุชิ้นเดียวกัน |
|
ตัวอย่างความแตกต่างระหว่าง is และ ==
# 1. Lists with SAME values but DIFFERENT objects
list_a = [1, 2, 3]
list_b = [1, 2, 3]
# Check Equality (Do they have the same content?)
print(f"Values are equal? {list_a == list_b}") # True
# Check Identity (Are they the same object in memory?)
print(f"Are they the same object? {list_a is list_b}") # False
# 2. Assignment creates a Reference
list_c = list_a # list_c points to the same object as list_a
print(f"list_a is list_c? {list_a is list_c}") # True
# Proof using id() function (shows memory address)
print(f"ID of A: {id(list_a)}")
print(f"ID of B: {id(list_b)}") # Different ID from A
print(f"ID of C: {id(list_c)}") # Same ID as A
1.4.6. Membership Operators (ตัวดำเนินการตรวจสอบสมาชิก)
ใช้ตรวจสอบว่ามีข้อมูลที่ต้องการ อยู่ในลำดับข้อมูล (เช่น List, String, Tuple) หรือไม่
Operator |
Description |
Example (list = [1, 2, 3]) |
|---|---|---|
|
มีค่าอยู่ในลำดับข้อมูลหรือไม่ |
|
|
ไม่มีค่าอยู่ในลำดับข้อมูลหรือไม่ |
|
1.4.7. Bitwise Operators (ตัวดำเนินการระดับบิต)
ในงานหุ่นยนต์และระบบฝังตัว (Embedded Systems) เรามักต้องสื่อสารกับฮาร์ดแวร์ในระดับต่ำสุด คือระดับ เลขฐานสอง (Binary) เช่น การอ่านค่าสถานะจาก Register ของมอเตอร์ หรือการถอดรหัสข้อมูลจากเซนเซอร์
ก่อนใช้งาน เราต้องเข้าใจการแปลงเลขฐานสิบเป็นฐานสองก่อน:
*5 ในฐานสิบ = ...000101 ในฐานสอง (\(4 + 1\))
*3 ในฐานสิบ = ...000011 ในฐานสอง (\(2 + 1\))
Operator |
Name |
Description |
|---|---|---|
|
AND |
เปรียบเทียบทีละบิต ต้องเป็น 1 ทั้งคู่ ผลลัพธ์จึงจะเป็น 1 (นิยมใช้ตัดค่า หรือ Masking) |
|
OR |
เปรียบเทียบทีละบิต ถ้ามี 1 อย่างน้อยหนึ่งตัว ผลลัพธ์จะเป็น 1 (นิยมใช้รวมค่า หรือ Setting Flags) |
|
XOR |
(Exclusive OR) ถ้าบิตเหมือนกันได้ 0 ถ้าต่างกันได้ 1 (นิยมใช้เช็คการเปลี่ยนแปลง หรือ Toggle) |
|
NOT |
กลับบิตจาก 0 เป็น 1 และ 1 เป็น 0 (Invert) |
|
Left Shift |
เลื่อนบิตไปทางซ้าย เติม 0 ด้านหลัง (มีค่าเท่ากับคูณด้วย 2 ยกกำลัง n) |
|
Right Shift |
เลื่อนบิตไปทางขวา (มีค่าเท่ากับหารด้วย 2 ยกกำลัง n) |
คำอธิบายและตัวอย่างการคำนวณ (Visual Calculation)
เพื่อให้เห็นภาพ เราจะใช้ตัวแปร a = 5 (0101) และ b = 3 (0011)
Bitwise AND (
&) เอาเฉพาะบิตที่เป็น 1 ทั้งคู่ (ตำแหน่งที่ตรงกัน)
0 1 0 1 (5)
& 0 0 1 1 (3)
---------
0 0 0 1 (Result = 1)
Bitwise OR (
|) เอาบิตที่เป็น 1 ทั้งหมดมารวมกัน
0 1 0 1 (5)
| 0 0 1 1 (3)
---------
0 1 1 1 (Result = 7)
Bitwise XOR (
^) ดูความต่าง (เหมือน=0, ต่าง=1)
0 1 0 1 (5)
^ 0 0 1 1 (3)
---------
0 1 1 0 (Result = 6)
Left Shift (
<<) เลื่อนบิตไปทางซ้าย 1 ตำแหน่ง (5 << 1)
0 0 1 0 1 (5)
<< 1
-----------
0 1 0 1 0 (Result = 10)
Right Shift (
>>) เลื่อนบิตไปทางขวา 1 ตำแหน่ง (12 >> 1)
0 1 1 0 0 (12)
>> 1
-----------
0 0 1 1 0 (Result = 6)
ตัวอย่างโค้ด Bitwise ใน Python
1a = 5 # Binary: 0101
2b = 3 # Binary: 0011
3
4# Helper function to print binary easily
5# bin() converts number to binary string (e.g., '0b101')
6def show_bin(name, val):
7 print(f"{name}: {val} (Binary: {bin(val)})")
8
9print("--- Initial Values ---")
10show_bin("a", a)
11show_bin("b", b)
12
13print("\n--- Operations ---")
14# AND
15show_bin("a & b", a & b) # 0001 (1)
16
17# OR
18show_bin("a | b", a | b) # 0111 (7)
19
20# XOR
21show_bin("a ^ b", a ^ b) # 0110 (6)
22
23# Left Shift (Multiply by 2)
24show_bin("a << 1", a << 1) # 1010 (10)
25
26# Right Shift (Divide by 2)
27show_bin("a >> 1", a >> 1) # 0010 (2)
1.4.8. Operator Precedence (ลำดับความสำคัญของตัวดำเนินการ)
เมื่อในหนึ่งประโยคคำสั่งมีตัวดำเนินการหลายตัว Python จะทำงานตามลำดับความสำคัญจาก บนลงล่าง ดังนี้:
Priority |
Operator |
|---|---|
1 (Highest) |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 (Lowest) |
|
1.4.9. คำแนะนำ (Best Practice)
แม้ Python จะมีลำดับความสำคัญที่ชัดเจน แต่การเขียนโค้ดที่ซับซ้อนโดยไม่ใส่วงเล็บ อาจทำให้ผู้อ่าน (หรือแม้แต่ตัวผู้เขียนเอง) สับสนได้
หลักการของ Pythonic Way คือ "Explicit is better than implicit" (ชัดเจนดีกว่าคลุมเครือ) ดังนั้น ควรใส่วงเล็บ () เสมอ เมื่อมีตัวดำเนินการหลายชนิดผสมกัน เพื่อให้อ่านง่ายและมั่นใจว่าผลลัพธ์ถูกต้อง
ตัวอย่างลำดับความสำคัญของตัวดำเนินการ
1# BAD: Confusing to read
2# Does it mean (5 + 10) * 2 or 5 + (10 * 2)?
3result = 5 + 10 * 2 > 20 and 5 - 1 == 4
4
5# GOOD: Clear and explicit
6# The logic is immediately obvious to human readers
7result = (5 + (10 * 2)) > 20 and ((5 - 1) == 4)
1.5. Control Flow: If-Else (การควบคุมทิศทางโปรแกรม)
โปรแกรมที่ดีต้องสามารถ "ตัดสินใจ" เลือกทำงานในเส้นทางที่แตกต่างกันได้ตามเงื่อนไขที่กำหนด โครงสร้างพื้นฐานในการควบคุมทิศทางคือ if, else และ elif (ย่อมาจาก else if)
1.5.1. If Statement
ใช้ตรวจสอบเงื่อนไข หากเป็นจริง (True) จะทำคำสั่งภายในบล็อกนั้น (สังเกตการย่อหน้า Indentation)
1battery_level = 10
2
3# Note: No parentheses () needed around the condition in Python
4if battery_level < 20:
5 print(f"Warning: Low Battery ({battery_level}%)")
1.5.2. If-Else Statement
ใช้เมื่อมีทางเลือก 2 ทาง คือ "ถ้าจริงทำ A" และ "ถ้าไม่จริงทำ B"
1is_connected = False
2
3if is_connected:
4 print("Status: System Online")
5else:
6 print("Status: Connection Failed")
1.5.3. If-Elif-Else Statement
ใช้เมื่อมีทางเลือกมากกว่า 2 ทาง โปรแกรมจะตรวจสอบเงื่อนไขจากบนลงล่าง และจะทำงานในบล็อกแรกที่เป็นจริงเพียงบล็อกเดียวเท่านั้น
1# Robot Modes: 0=Idle, 1=Manual, 2=Auto
2mode = 1
3
4if mode == 0:
5 print("Mode: Idle")
6elif mode == 1:
7 print("Mode: Manual Control")
8elif mode == 2:
9 print("Mode: Autonomous")
10else:
11 print("Error: Unknown Mode")
แบบฝึกหัด (Exercise)
โจทย์: จงเขียนโปรแกรม ระบบตัดเกรด (Grading System) โดยกำหนดตัวแปร score ให้มีค่าคะแนน 0-100 และแสดงผลเกรดตามเงื่อนไขดังนี้:
A: คะแนน \(\geq\) 80
B: คะแนน \(\geq\) 70
C: คะแนน \(\geq\) 60
D: คะแนน \(\geq\) 50
F: คะแนน \(<\) 50
คลิกเพื่อดูเฉลย (Click to show solution)
1# Define the score
2score = 75
3
4if score >= 80:
5 grade = "A"
6elif score >= 70:
7 grade = "B"
8elif score >= 60:
9 grade = "C"
10elif score >= 50:
11 grade = "D"
12else:
13 grade = "F"
14
15print(f"Score: {score}, Your Grade is: {grade}")
1.6. Data Structures (โครงสร้างข้อมูล)
เมื่อข้อมูลมีจำนวนมาก การเก็บในตัวแปรเดี่ยวๆ (เช่น x1, x2, x3...) จะจัดการยากและไม่ยืดหยุ่น Python จึงมีโครงสร้างข้อมูลแบบกลุ่มให้ใช้งาน เพื่อให้เราสามารถเก็บข้อมูลหลายๆ ตัวไว้ในตัวแปรชื่อเดียวได้
1.6.1. List (ลิสต์)
List คือกลุ่มข้อมูลที่เรียงต่อกันเป็นลำดับ (Ordered) และ แก้ไขได้ (Mutable) ข้อมูลภายในจะมีหมายเลขลำดับกำกับเรียกว่า Index (เริ่มนับจาก 0)
นิยมใช้เก็บข้อมูลชุดที่อาจมีการเพิ่มลดจำนวนได้ เช่น ข้อมูลระยะทางจาก Lidar 360 จุด
1# Create a list with mixed data types
2list_data = ["a", 2, 3, "5", "cat"]
3
4# 1. Indexing (Accessing individual elements)
5print(list_data[0]) # First element -> "a"
6print(list_data[-1]) # Last element -> "cat"
7
8# 2. Slicing (Extracting a part of the list)
9# Format: [start : stop] *Note: excludes the 'stop' index
10print(list_data[0:3]) # Index 0 to 2 -> ['a', 2, 3]
11print(list_data[2:]) # Index 2 to the end -> [3, '5', 'cat']
12
13# 3. Modifying the list
14list_data[0] = "dog" # Change first element
15list_data.append(100) # Add new element to the end
1.6.2. Tuple (ทูเพิล)
Tuple คล้ายกับ List แต่มีคุณสมบัติสำคัญคือ แก้ไขไม่ได้ (Immutable) เมื่อสร้างขึ้นมาแล้วจะไม่สามารถเปลี่ยนค่า เพิ่ม หรือลบข้อมูลภายในได้
นิยมใช้เก็บข้อมูลค่าคงที่ที่มาเป็นชุดและไม่ควรถูกเปลี่ยนแปลง เช่น พิกัด \((x, y, z)\) หรือค่าสี \((R, G, B)\)
1# Tuples use parentheses () instead of brackets []
2tuple_data = (1, 2, 3, 4, 5)
3list_data = [1, 2, 3, 4, 5]
4
5# Accessing data works the same as List
6print(tuple_data[0]) # Output: 1
7
8# Modifying data
9list_data[0] = 45 # OK: List is mutable
10# tuple_data[0] = 45 # ERROR: TypeError: 'tuple' object does not support item assignment
1.6.3. Dictionary(ดิคชันนารี)
Dictionary เป็นโครงสร้างข้อมูลที่เก็บข้อมูลเป็นคู่ของ Key และ Value (คล้าย JSON Format)
Key: เปรียบเสมือนคำศัพท์ (ต้องไม่ซ้ำกัน)
Value: เปรียบเสมือนคำแปล (เป็นข้อมูลอะไรก็ได้)
ในงานหุ่นยนต์ Dictionary มีความสำคัญมาก ใช้สำหรับเก็บค่าการตั้งค่า (Configuration) หรือพารามิเตอร์ต่างๆ ของระบบ
1# Define a dictionary for robot configuration
2robot_config = {
3 "name": "Batly_R1",
4 "id": 101,
5 "max_speed": 1.5,
6 "battery_type": "Li-Po"
7}
8
9# 1. Accessing values by Key
10print(robot_config["name"]) # Output: Batly_R1
11print(robot_config["max_speed"]) # Output: 1.5
12
13# 2. Adding or Updating values
14robot_config["max_speed"] = 2.0 # Update existing key
15robot_config["location"] = "Lab" # Add new key-value pair
16
17# 3. Checking keys
18# Useful to prevent errors before accessing
19if "battery_type" in robot_config:
20 print(f"Battery: {robot_config['battery_type']}")
1.7. Loops (การวนซ้ำ)
ในการเขียนโปรแกรม บ่อยครั้งที่เราจำเป็นต้องสั่งให้คอมพิวเตอร์ทำงานเดิมซ้ำๆ หลายครั้ง เช่น การอ่านค่าจากเซนเซอร์ 100 ครั้งเพื่อหาค่าเฉลี่ย หรือการสั่งให้หุ่นยนต์เดินไปเรื่อยๆ จนกว่าจะเจอสิ่งกีดขวาง
ภาษา Python มีคำสั่งสำหรับการวนซ้ำ 2 รูปแบบหลัก คือ for และ while
1.7.1. For Loop
For Loop เหมาะสำหรับการวนซ้ำที่ "รู้จำนวนรอบที่แน่นอน" หรือใช้สำหรับไล่อ่านข้อมูลสมาชิกภายใน List, Tuple, หรือ String ทีละตัวจนครบ
การวนอ่านค่าใน List (Iteration)
1# List of sensor readings (e.g., distances in meters)
2sensor_readings = [1.2, 0.8, 3.5, 0.4, 2.1]
3
4print("Analyzing sensor data...")
5
6# Loop through each item in the list
7for dist in sensor_readings:
8 # Check condition inside the loop
9 if dist < 0.5:
10 print(f"Warning: Obstacle detected at {dist}m")
11 else:
12 print(f"Path clear at {dist}m")
การใช้งานฟังก์ชัน range()
หากต้องการวนรอบตามจำนวนครั้งที่กำหนด สามารถใช้ฟังก์ชัน range() เพื่อสร้างลำดับตัวเลขได้ โดยมีรูปแบบการใช้งาน 3 แบบ:
range(stop): เริ่มจาก 0 ถึง stop-1
range(start, stop): เริ่มจาก start ถึง stop-1
range(start, stop, step): เพิ่มค่าทีละ step
1# 1. Basic range (0 to 4)
2print("--- Count 0 to 4 ---")
3for i in range(5):
4 print(f"Count: {i}")
5
6# 2. Range with start and stop: range(start, stop) -> Count 5 to 9
7print("\n--- 2. Start to Stop (5 to 9) ---")
8for i in range(5, 10):
9 print(f"Count: {i}")
10
11# 3. Range with step (Start at 2, Stop before 20, Step 3)
12print("\n--- Step Example ---")
13for i in range(2, 20, 3):
14 print(f"Step: {i}")
1.7.2. While Loop
While Loop เหมาะสำหรับการวนซ้ำที่ "ไม่รู้จำนวนรอบที่แน่นอน" โดยโปรแกรมจะทำงานวนไปเรื่อยๆ ตราบใดที่เงื่อนไขยังเป็นจริง (True)
ในงานควบคุมหุ่นยนต์ เรามักใช้ While Loop สำหรับสร้าง Main Loop ของโปรแกรม เพื่อให้หุ่นยนต์ทำงานตลอดเวลาจนกว่าจะถูกสั่งปิด หรือใช้รอจนกว่าเซนเซอร์จะอ่านค่าได้ตามที่ต้องการ
ตัวอย่างที่ 1: การใช้งาน While Loop พื้นฐาน
โค้ดด้านล่างจะจำลองการชาร์จแบตเตอรี่ โดยจะวนลูปชาร์จทีละ 10% ไปเรื่อยๆ จนกว่าแบตเตอรี่จะเต็ม
1battery_level = 10
2
3# วนลูปตราบใดที่แบตเตอรี่ยังน้อยกว่า 100
4while battery_level < 100:
5 battery_level += 10 # ชาร์จเพิ่มรอบละ 10%
6 print(f"Charging... Battery at {battery_level}%")
7
8print("Battery Full!")
ตัวอย่างที่ 2: การใช้ while ร่วมกับ else ในภาษา Python เราสามารถใช้ else ต่อท้าย while ได้ โดยคำสั่งในบล็อก else จะทำงาน ก็ต่อเมื่อเงื่อนไขของ while กลายเป็นเท็จ (False) (ลูปทำงานจนจบตามปกติ)
เราสามารถนำมาประยุกต์ใช้เพื่ออัปเดตสถานะของระบบเมื่อการทำงานในลูปเสร็จสิ้นสมบูรณ์ได้ เช่น การเปลี่ยนสถานะการชาร์จ
1battery_level = 10
2charging = True
3
4print(f"System State -> Charging: {charging}")
5
6# วนลูปตราบใดที่แบตเตอรี่ยังน้อยกว่า 100
7while battery_level < 100:
8 battery_level += 10
9 print(f"Charging... Battery at {battery_level}%")
10else:
11 # ทำงานเมื่อ battery_level < 100 กลายเป็นเท็จ (ชาร์จเต็มแล้ว)
12 charging = False
13 print("Loop finished naturally.")
14
15print("Battery Full!")
16print(f"System State -> Charging: {charging}")
1.7.3. Loop Control Statements (คำสั่งควบคุมลูป)
บางครั้งเราอาจต้องการบังคับให้ลูปหยุดทำงานทันที หรือข้ามการทำงานบางรอบ เราสามารถใช้คำสั่งพิเศษได้ดังนี้:
break: สั่งให้ "หยุดและออกจากลูปทันที" (มักใช้เมื่อเจอสิ่งที่ค้นหาแล้ว หรือเมื่อเจอ Error)
continue: ใช้สำหรับ "ข้ามการทำงานในรอบปัจจุบัน" (Skip) เพื่อกระโดดไปเริ่มรอบถัดไปทันที โดยไม่ทำคำสั่งที่เหลืออยู่ด้านล่าง นิยมใช้ในการกรองข้อมูลที่ไม่ต้องการทิ้งไป (Filtering)
ตัวอย่างการใช้งาน break
1# Search for a specific ID
2target_id = 55
3data_stream = [10, 23, 55, 89, 12]
4
5for id_num in data_stream:
6 if id_num == target_id:
7 print(f"Found target ID: {id_num}. Stopping loop.")
8 break # Exit the loop immediately
9
10 print(f"Checking ID: {id_num}...")
ตัวอย่างการใช้งาน continue
1# Mock sensor data (negative numbers represent errors)
2sensor_data = [1.5, -1.0, 2.3, -1.0, 0.8]
3
4print("Start processing sensor data...")
5
6for val in sensor_data:
7 # Check for error code
8 if val < 0:
9 print(f"Found error value: {val}, skipping...")
10 continue # Jump to the next iteration immediately
11
12 # This part runs ONLY if val is valid (not skipped)
13 print(f"Valid distance: {val} m")
1.8. Functions (ฟังก์ชัน)
ฟังก์ชันเปรียบเสมือน "เครื่องจักร" หรือ "สูตรคำนวณ" ที่เราสร้างเตรียมไว้ เมื่อต้องการใช้งานเพียงแค่เรียกชื่อและส่งวัตถุดิบ (Arguments) เข้าไป ฟังก์ชันจะทำการประมวลผลและส่งผลลัพธ์ (Return) กลับออกมา ช่วยให้โค้ดเป็นระเบียบ ลดการเขียนซ้ำซ้อน และง่ายต่อการแก้ไข
1.8.1. การสร้างและเรียกใช้ฟังก์ชันพื้นฐาน
โครงสร้างพื้นฐานเริ่มต้นด้วยคีย์เวิร์ด def ตามด้วยชื่อฟังก์ชัน และวงเล็บ
ตัวอย่างนี้คือการแปลงสูตรคณิตศาสตร์ \(f(x) = x^2 + 2x + 1\) ให้เป็นโค้ด Python โดยรับค่า x เข้าไปคำนวณ และส่งผลลัพธ์กลับออกมาด้วยคำสั่ง return
1# สร้างฟังก์ชันชื่อ func1 ที่รับค่า x
2def func1(x):
3 # คำนวณสมการและส่งค่ากลับ
4 return x**2 + 2*x + 1
5
6# เรียกใช้งานฟังก์ชันโดยส่งเลข 3 เข้าไปแทนที่ x
7y = func1(3)
8print(f"f(3) = {y}") # ผลลัพธ์: 16
1.8.2. ฟังก์ชันกับการนำไปประยุกต์ใช้งาน
เราสามารถประยุกต์ใช้ฟังก์ชันกับสูตรทั่วไปได้ เช่น การคำนวณพื้นที่วงกลม ทำให้เราไม่ต้องเขียนสูตร \(\pi r^2\) ซ้ำๆ ทุกครั้งที่ต้องการคำนวณ
1# สร้างฟังก์ชันคำนวณพื้นที่วงกลม รับค่ารัศมี (r)
2def circle_area(r):
3 area = 3.14 * (r**2)
4 return area
5
6# กำหนดค่ารัศมีและเรียกใช้งาน
7radius = 5.0
8result = circle_area(radius)
9print(f"Circle area of radius {radius} is {result} sq-m")
1.8.3. การรับค่าเข้าหลายตัว (Multiple Arguments)
ฟังก์ชันไม่จำเป็นต้องรับค่าแค่วัตถุดิบเดียว เราสามารถส่งตัวแปรเข้าไปกี่ตัวก็ได้โดยใช้เครื่องหมายลูกน้ำ (,) คั่น
1# ฟังก์ชันรับค่า 2 ตัว (a และ b) เพื่อนำมาบวกกัน
2def summation(a, b):
3 return a + b
4
5# เรียกใช้งานโดยส่งเลข 4 และ 5 เข้าไป
6val1 = 4
7val2 = 5
8total = summation(val1, val2)
9
10print(f"Sum of {val1} and {val2} is: {total}")
1.8.4. การคืนค่ากลับหลายตัว (Multiple Return Values)
จุดเด่นของ Python ที่ทรงพลังมากในงานหุ่นยนต์ คือฟังก์ชันสามารถ "คืนค่าผลลัพธ์ได้หลายตัวพร้อมกัน" ซึ่งเหมาะมากกับฟังก์ชันประเภทอ่านค่าเซนเซอร์ที่มักจะได้ค่ากลับมาพร้อมๆ กัน (เช่น ได้ทั้งพิกัดแกน X และ Y)
ผลลัพธ์ที่ได้กลับมาจะอยู่ในรูปแบบของ Tuple ซึ่งเราสามารถประกาศตัวแปรมารับค่าแยกกันได้ทันที (เรียกว่า Unpacking)
1# ฟังก์ชันนี้ส่งค่ากลับ 2 ค่าพร้อมกัน คือ ผลบวก และ ผลคูณ
2def sum_mul(a, b):
3 return a + b, a * b
4
5# สังเกตการใช้ตัวแปร 2 ตัว (res_sum, res_mul) มารอรับค่าผลลัพธ์
6res_sum, res_mul = sum_mul(4, 5)
7
8print(f"Result Sum: {res_sum}")
9print(f"Result Multiply: {res_mul}")
1.8.5. Functions with List (การใช้งานร่วมกับ List)
ในงานเขียนโปรแกรมจริง เรามักไม่ได้ส่งแค่ตัวเลขตัวเดียวเข้าฟังก์ชัน แต่สามารถส่งโครงสร้างข้อมูลที่เก็บค่าหลายๆ ค่าอย่าง List เข้าไปประมวลผลได้เลย ซึ่งมีประโยชน์มาก เช่น การส่งชุดข้อมูลจากเซนเซอร์เข้าไปหาค่าเฉลี่ย
1. การส่ง List เข้าไปหาผลรวม (Summation)
ฟังก์ชัน sum_list จะรับค่าข้อมูล List เข้ามา จากนั้นใช้ for loop ดึงตัวเลขออกมาทีละตัวเพื่อบวกสะสมไว้ในตัวแปร total
1# Function to calculate sum of a list
2def sum_list(list_input):
3 total = 0
4 for i in list_input:
5 total += i
6 return total
7
8# Test Data
9number_list = [1, 5, 8, 10, 4]
10result_sum = sum_list(number_list)
11
12print(f"Summation: {result_sum}")
2. การส่ง List เข้าไปตรวจสอบเงื่อนไข (Counting Items)
ฟังก์ชัน count_even มีความซับซ้อนขึ้นมาอีกระดับ โดยจะใช้ if ซ้อนเข้าไปในลูป เพื่อกรองและนับเฉพาะตัวเลขที่ตรงตามเงื่อนไข (ในที่นี้คือหาเลขคู่โดยใช้ i % 2 == 0)
1# Function to count even numbers
2def count_even(my_list):
3 count = 0
4 for i in my_list:
5 # Check if divisible by 2 (Even number)
6 if i % 2 == 0:
7 count += 1
8 print(f"Even number found: {i}")
9 return count
10
11# Test Data
12number_list = [1, 5, 8, 10, 4]
13total_even = count_even(number_list)
14
15print(f"Total even numbers: {total_even}")
1.8.6. Algorithm Optimization (การปรับปรุงประสิทธิภาพโค้ด)
ในงานหุ่นยนต์ที่ต้องประมวลผลข้อมูลจำนวนมหาศาล (เช่น ข้อมูลภาพ หรือ Lidar) ความเร็วเป็นเรื่องสำคัญ
การตรวจสอบเลขคู่/คี่ สามารถทำได้ 2 วิธี:
Modulo (
% 2): เป็นวิธีมาตรฐานทางคณิตศาสตร์Bitwise AND (
& 1): เป็นวิธีทางคอมพิวเตอร์ระดับล่าง ซึ่งทำงานได้เร็วกว่าการหาร
หลักการคือ เลขคู่ในฐานสอง บิตสุดท้ายจะเป็น 0 เสมอ ส่วนเลขคี่จะเป็น 1 ดังนั้นการนำไป & 1 จะได้ผลลัพธ์ทันที
1# Optimized version using Bitwise Operator
2def count_even_binary(my_list):
3 count = 0
4 for i in my_list:
5 # Check the last bit
6 # If (i & 1) is 0 (False), it means Even.
7 # So we use 'not' to make it True for Even numbers.
8 if not (i & 1):
9 count += 1
10 print(f"Even number: {i}")
11 return count
12
13large_data = [124958373, 3494385735934, 39385384357, 34835375385834]
14print(f"Total even (Bitwise): {count_even_binary(large_data)}")
1.9. Object-Oriented Programming (การเขียนโปรแกรมเชิงวัตถุ)
ในการเขียนโปรแกรมขนาดใหญ่ การจัดการข้อมูลกระจัดกระจายด้วยตัวแปรเดี่ยวๆ จะทำให้โค้ดยุ่งเหยิงและแก้ไขยาก ตัวอย่างเช่น หากต้องเก็บข้อมูลพนักงานด้วยตัวแปรปกติ:
1# Without OOP: Variables are scattered and hard to manage
2emp1_name = "John"
3emp1_age = 28
4emp1_salary = 28000
5
6emp2_name = "Jane"
7emp2_age = 33
8emp2_salary = 50000
หากมีพนักงาน 100 คน จำเป็นต้องประกาศตัวแปรถึง 300 ตัว ซึ่งไม่สามารถจัดการได้จริง OOP จึงเข้ามาแก้ปัญหานี้โดยการมองทุกอย่างเป็น วัตถุ (Object) ที่มีทั้งข้อมูล (Attributes) และการกระทำ (Methods) รวมอยู่ในก้อนเดียว
1.9.1. Class and Object (คลาสและวัตถุ)
Class (คลาส): เปรียบเสมือน "แม่พิมพ์" หรือแบบแปลน (Blueprint) ที่กำหนดว่าวัตถุนี้ต้องมีข้อมูลอะไรบ้าง
Object (วัตถุ): เปรียบเสมือน "ชิ้นงานจริง" (Instance) ที่ถูกสร้างออกมาจากแม่พิมพ์นั้น โดยอัดข้อมูลจริงๆ เข้าไป
1.9.2. 1. การสร้าง Class พื้นฐาน (Constructor)
ในการสร้าง Class เราจะใช้ฟังก์ชันพิเศษที่ชื่อว่า __init__ (ย่อมาจาก Initialize) ซึ่งทำหน้าที่เป็น "พนักงานต้อนรับ" ที่จะทำงานอัตโนมัติทันทีที่มีการสร้าง Object ใหม่ เพื่อเอาข้อมูลเริ่มต้นไปบรรจุไว้ในตัวแปร
ข้อควรรู้: คำว่า self ในภาษา Python หมายถึง "ตัววัตถุเอง" เป็นคำบังคับที่ต้องใส่ไว้เป็น Parameter แรกเสมอ เพื่อให้ตัวแปรต่างๆ รู้ว่ามันเป็นข้อมูลของวัตถุก้อนไหน
1# สร้างแบบแปลน (Class)
2class Employee:
3 # Constructor: ทำงานอัตโนมัติเมื่อถูกสร้าง (สังเกตเครื่องหมาย Underscore 2 ตัวหน้าหลัง)
4 def __init__(self, name, age, salary):
5 # นำค่าที่รับมา ไปเก็บไว้ในตัวแปรของตัวมันเอง (self)
6 self.name = name
7 self.age = age
8 self.salary = salary
9 print(f"Created Employee: {self.name}, Age: {self.age}, Salary: {self.salary}")
10
11# สร้างชิ้นงานจริง (Objects) โดยไม่ต้องส่งค่าให้ self
12print("--- Creating Objects ---")
13emp1 = Employee("John", 28, 28000)
14emp2 = Employee("Jane", 33, 50000)
15
16# การเรียกดูข้อมูลภายใน Object
17print("\n--- Accessing Data ---")
18print(f"Employee 1 is {emp1.name} and he earns {emp1.salary}")
เราสามารถปรับปรุงโครงสร้างของ Class ให้รองรับการทำงานมากขึ้นได้ดังนี้
ตัวอย่างโครงสร้าง Class
1class Employee:
2 # Constructor: Runs automatically when a new object is created
3 def __init__(self, name, age, salary):
4 self.name = name # Public Attribute
5 self.age = age # Public Attribute
6 self.__salary = salary # Private Attribute (Hidden)
7 print(f"Created Employee: {self.name}")
8
9 # Method to update salary
10 def update_salary(self, amount):
11 self.__salary += amount
12 print(f"Name: {self.name}, New Salary: {self.__salary}")
13
14 # Method to update age
15 def update_age(self, amount):
16 self.age += amount
17 print(f"Name: {self.name}, New Age: {self.age}")
18
19 # Getter method for private attribute
20 def get_salary(self):
21 return self.__salary
22
23# Create Objects (Instanciation)
24emp1 = Employee("John", 28, 28000)
25emp2 = Employee("Jane", 33, 50000)
26
27# Calling methods
28emp1.update_age(1) # John is now 29
29emp1.update_salary(2000) # John's salary increased
1.9.3. คำอธิบายเชิงลึก: ส่วนประกอบของ OOP
เพื่อให้เข้าใจการทำงานของโค้ดข้างต้น จำเป็นต้องทำความรู้จักกับ 5 คำศัพท์สำคัญและการทำงานภายใน ดังนี้:
Class vs Object (Instance)
Class (คลาส): เปรียบเสมือน "แม่พิมพ์" หรือ "แบบแปลน" (Blueprint) ซึ่งมีไว้กำหนดโครงสร้างว่าสิ่งนี้คืออะไร มีข้อมูลอะไรบ้าง แต่ยังจับต้องไม่ได้และยังไม่ได้ถูกสร้างขึ้นในหน่วยความจำ (เช่น
class Employee)Object หรือ Instance (วัตถุ): เปรียบเสมือน "ชิ้นงานจริง" ที่ถูกสร้างออกมาจากแม่พิมพ์นั้น เมื่อสร้างออกมาแล้วจะมีตัวตนจริงๆ ในหน่วยความจำ และสามารถนำไปใช้งานได้ (เช่น
emp1,emp2)
__init__ (Constructor)
ในภาษา Python ฟังก์ชันชื่อ __init__ คือฟังก์ชันพิเศษที่เรียกว่า Constructor (ตัวก่อสร้าง)
หน้าที่: เตรียมความพร้อมและกำหนดค่าเริ่มต้นให้กับวัตถุ
การทำงาน: จะถูกเรียกใช้งาน อัตโนมัติทันที เพียงครั้งเดียว เมื่อมีการสร้าง Object ใหม่ (ตอนที่พิมพ์
Employee(...)) หากไม่มีส่วนนี้ วัตถุที่สร้างมาจะว่างเปล่าไม่มีข้อมูล
Attributes (ตัวแปรภายในคลาส)
เมื่อตัวแปรเข้าไปอยู่ใน Class จะถูกเรียกว่า Attributes หรือ Properties ซึ่งเปรียบเสมือน "ข้อมูลประจำตัว" ของวัตถุนั้นๆ
Public Attribute (เช่น
self.name): ข้อมูลสาธารณะ สามารถเข้าถึงหรือแก้ไขได้โดยตรง เปรียบเสมือนป้ายชื่อพนักงานที่ใครก็มองเห็นPrivate Attribute (เช่น
self.__salary): ข้อมูลส่วนตัว ที่มี__นำหน้า เปรียบเสมือนเงินในกระเป๋าสตางค์ที่ไม่ควรให้ผู้อื่นหยิบไปดูหรือแก้ไขโดยตรง ต้องผ่านขั้นตอนที่ถูกต้องเท่านั้น
Methods (ฟังก์ชันภายในคลาส)
เมื่อฟังก์ชันเข้าไปอยู่ใน Class จะถูกเปลี่ยนชื่อเรียกว่า Method
Function: คือคำสั่งที่อยู่อย่างอิสระ เรียกใช้เมื่อไหร่ก็ได้ (เช่น
print(),len())Method: คือความสามารถเฉพาะตัวของ Object นั้นๆ จะเรียกใช้ได้ก็ต่อเมื่อมี Object เกิดขึ้นมาแล้วเท่านั้น (เช่น
emp1.update_salary()) เปรียบเสมือนกริยาอาการ เช่น "พนักงานเดิน", "พนักงานรับเงินเดือน"
self (ตัวระบุตัวตน)
ในทุก Method จะมีคำว่า self เป็นพารามิเตอร์ตัวแรกเสมอ
ความหมาย:
selfหมายถึง "ตัวของวัตถุเอง"ประโยชน์: เนื่องจาก Class เป็นแค่แม่พิมพ์ที่ใช้สร้าง Object ได้หลายตัว (emp1, emp2, ...) คอมพิวเตอร์จำเป็นต้องรู้ว่าคำสั่งนั้นกำลังกระทำกับวัตถุตัวไหน
เมื่อสั่ง
emp1.update_age()->selfจะหมายถึงemp1เมื่อสั่ง
emp2.update_age()->selfจะหมายถึงemp2
ภาพสรุปการทำงาน
1# 1. Class (The Blueprint)
2class Employee:
3
4 # 2. Constructor (Runs automatically when creating object)
5 def __init__(self, name, age, salary):
6 # 3. Attributes (Data stored in the instance)
7 self.name = name
8 self.age = age
1# 4. Object/Instance (Creating the actual object)
2emp1 = Employee("John", 28, 28000)
3
4# Internal process:
5# 1. Python calls __init__ automatically
6# 2. 'self' refers to 'emp1'
7# 3. emp1.name is set to "John"
1.9.4. Encapsulation (การห่อหุ้มข้อมูล)
สังเกตตัวแปร __salary (มีขีดล่าง 2 ขีดนำหน้า) นี่คือ Private Attribute ซึ่งมีคุณสมบัติพิเศษคือ "ห้ามเข้าถึงจากภายนอกโดยตรง"
print(emp1.age)-> ทำได้ (Public)print(emp1.__salary)-> Error! (Private)
จำเป็นต้องเข้าถึงหรือแก้ไขผ่าน Method ที่เตรียมไว้ให้เท่านั้น (เช่น get_salary() หรือ update_salary()) เพื่อความปลอดภัยของข้อมูล
1.9.5. แบบฝึกหัด (Exercise)
โจทย์: จงเขียนคลาส Car โดยมีข้อกำหนดดังนี้:
เก็บข้อมูล: แบรนด์ (
brand), โมเดล (model), ปี (year), สี (color)เก็บข้อมูลลับ (Private): ระยะทางที่ขับแล้ว (
__mileage), น้ำมันคงเหลือ (__fuel)สร้าง Method:
update_mileage(amount): เพิ่มระยะทางตามค่าที่รับมาupdate_fuel(amount): เปลี่ยนค่าน้ำมันให้เป็นค่าใหม่ (เติมน้ำมัน/ใช้น้ำมัน)
คลิกเพื่อดูเฉลย (Click to show solution)
1class Car:
2 # Constructor: Function to initialize the object
3 def __init__(self, brand, model, year, color, mileage, fuel):
4 self.brand = brand # Public
5 self.model = model
6 self.year = year
7 self.color = color
8 self.__mileage = mileage # Private (Mileage)
9 self.__fuel = fuel # Private (Fuel Level)
10 print(f"Created {self.brand} {self.model}")
11
12 # Method to update mileage
13 def update_mileage(self, amount):
14 self.__mileage += amount
15 print(f"Model: {self.model}, New Mileage: {self.__mileage}")
16
17 # Method to update fuel level
18 def update_fuel(self, amount):
19 self.__fuel = amount
20 print(f"Model: {self.model}, Fuel Level: {self.__fuel}")
21
22# Object Instantiation (Creating objects from class)
23c1 = Car("Tesla", "Model 3", 2024, "White", 0, 50)
24c2 = Car("Honda", "Civic", 2022, "Blue", 24015, 35)
25
26# Method Calls
27c1.update_mileage(1000) # Drive c1 for 1000 km
28c2.update_fuel(50) # Refuel c2
1.10. Custom Modules (การสร้างโมดูลใช้เอง)
เมื่อโปรแกรมเริ่มซับซ้อนขึ้น การเขียนโค้ดทุกอย่างรวมไว้ในไฟล์เดียวจะทำให้จัดการยากและแก้ไขลำบาก แนวทางปฏิบัติที่ดีคือการแยกโค้ดออกเป็นส่วนๆ ตามหน้าที่ เรียกว่า Module
1.10.1. หลักการทำงาน
สร้างไฟล์ Python (
.py) เพื่อเก็บฟังก์ชันหรือคลาสที่เกี่ยวข้องกัน (เช่นsensor_lib.pyเก็บคำสั่งอ่านเซนเซอร์)ในไฟล์หลัก (
main.py) ให้ใช้คำสั่งimportเพื่อดึงความสามารถจากไฟล์นั้นมาใช้
ตัวอย่างการสร้าง Module
สมมติเราสร้างไฟล์ชื่อ my_math.py เพื่อเก็บสูตรคำนวณทางคณิตศาสตร์
1# Variable
2PI = 3.14159
3
4# Function to calculate circle area
5def circle_area(radius):
6 return PI * (radius ** 2)
7
8# Class inside a module
9class Rectangle:
10 def __init__(self, w, h):
11 self.w = w
12 self.h = h
13
14 def area(self):
15 return self.w * self.h
ตัวอย่างการเรียกใช้ในไฟล์หลัก
สร้างไฟล์ main.py และเรียกใช้ module ข้างต้น
1# Method 1: Import the whole module
2import my_math
3
4print(f"PI value: {my_math.PI}")
5print(f"Circle Area: {my_math.circle_area(5)}")
6
7# Method 2: Import specific parts (Recommended for clean code)
8from my_math import Rectangle
9
10# Use the class directly without 'my_math.' prefix
11rect = Rectangle(10, 20)
12print(f"Rectangle Area: {rect.area()}")
13
14# Method 3: Import with Alias (Nicknaming)
15import my_math as mm
16
17print(f"Using Alias: {mm.circle_area(10)}")
Tip
Pro Tip: ในงาน ROS2 เราจะใช้การ Import แบบนี้ตลอดเวลา เช่น from rclpy.node import Node ซึ่งแปลว่า "ไปที่โมดูล rclpy เข้าไปที่ส่วน node แล้วเอาคลาส Node มาใช้"
1.10.2. รูปแบบการเรียกใช้งานโมดูล (Import Styles)
ในการดึงโค้ดจาก Module อื่นมาใช้งาน ภาษา Python มีคำสั่ง import ให้เลือกใช้หลายรูปแบบ ขึ้นอยู่กับความเหมาะสมและเพื่อลดความซ้ำซ้อนในการพิมพ์โค้ด
สมมติว่าเรามีไฟล์ my_math.py ที่มีทั้งตัวแปร PI, ฟังก์ชัน circle_area(), และคลาส Rectangle เราสามารถเรียกใช้ได้ 3 รูปแบบหลักดังนี้:
1. การ Import ทั้งโมดูล (Basic Import) ดึงมาทั้งหมด เวลาเรียกใช้ต้องอ้างอิงโดยพิมพ์ "ชื่อโมดูล.ชื่อฟังก์ชัน" เสมอ วิธีนี้ปลอดภัยที่สุดแต่อาจจะพิมพ์ยาว
1import my_math
2
3# ต้องมี my_math. นำหน้าเสมอ
4print(my_math.PI)
5print(my_math.circle_area(5))
2. การ Import เฉพาะส่วนที่ต้องการ (From ... Import ...) ดึงมาเฉพาะฟังก์ชัน หรือคลาสที่ระบุ วิธีนี้ เป็นที่นิยมมากที่สุด เพราะทำให้โค้ดหลักสั้นลง สามารถเรียกใช้ฟังก์ชันได้โดยตรงโดยไม่ต้องพิมพ์ชื่อโมดูลนำหน้า
1# ระบุเจาะจงเลยว่าจะดึงแค่ฟังก์ชัน circle_area และคลาส Rectangle
2from my_math import circle_area, Rectangle
3
4# สามารถเรียกชื่อฟังก์ชันหรือคลาสได้โดยตรงเลย!
5print(circle_area(5))
6rect = Rectangle(10, 20)
ข้อควรระวัง: หลีกเลี่ยงการใช้
from my_math import *(การใส่ดอกจันหมายถึงดึงมาทั้งหมดโดยไม่ต้องระบุชื่อ) เพราะอาจทำให้ชื่อฟังก์ชันที่ดึงมา ไปซ้ำซ้อนกับตัวแปรหรือโค้ดที่เราเขียนไว้ในไฟล์หลักได้
3. การ Import แบบตั้งชื่อเล่น (Alias Import)
กรณีที่ชื่อโมดูลเดิมยาวเกินไป หรือกลัวชื่อซ้ำ เราสามารถเปลี่ยนชื่อเรียก (ตั้งชื่อเล่น) ให้สั้นลงได้ด้วยคำว่า as
1import my_math as mm
2
3# พิมพ์แค่ mm แทนคำว่า my_math
4print(mm.circle_area(10))
1.10.3. แบบฝึกหัด: การสร้างและเรียกใช้งานโมดูล (Module Practice)
โจทย์: ให้นักศึกษานำความรู้เรื่อง Function และ Class ที่ได้เรียนไปก่อนหน้านี้ มาลองจัดระเบียบใหม่ด้วยการแยกไฟล์โค้ด
คำสั่ง:
สร้างไฟล์ชื่อ
my_module.pyให้นำโค้ดฟังก์ชัน
sum_list(ฟังก์ชันหาผลรวมตัวเลขใน List) และคลาสEmployee(ระบบจัดการพนักงาน) ที่เราเคยสร้างไว้ มาวางรวมกันไว้ในไฟล์นี้ไฟล์นี้จะทำหน้าที่เป็น "คลังเก็บเครื่องมือ" ของเรา ดังนั้น ห้าม มีการเรียกใช้งานฟังก์ชัน (Calling) หรือสร้าง Object ใดๆ ในไฟล์นี้ ให้มีเฉพาะโครงสร้าง
defและclassเท่านั้น
สร้างไฟล์ชื่อ
test_module.py(ต้องเซฟให้อยู่ในโฟลเดอร์เดียวกันกับไฟล์แรก)ให้ Import คลาส
Employeeเข้ามาโดยใช้วิธีfrom ... import ...ให้ Import ฟังก์ชัน
sum_listเข้ามาโดยใช้วิธีตั้งชื่อเล่น (Alias) เป็นsl(เช่นimport ... as ...)จากนั้นให้เขียนโค้ดในไฟล์นี้เพื่อ:
สร้างออบเจกต์ (Object) พนักงานใหม่ขึ้นมา 1 คน และทดลองอัปเดตเงินเดือน
สร้าง List ของตัวเลขขึ้นมา 1 ชุด แล้วส่งเข้าไปหาผลรวมผ่านตัวแปร
slที่เราตั้งชื่อเล่นไว้สั่ง
print()แสดงผลลัพธ์ข้อมูลพนักงานและผลรวมของตัวเลขออกทางหน้าจอ