ช่วงนี้ผมอัพ Blog เกี่ยว Course Python ของทาง MITx รัวๆ นะครับ เพราะ ใกล้สอบ Final แล้ว โดยสำหรับใน Week นี้เป็นเรื่องของ OOP เป็นหลัก มาเริ่มกันเลย
Object Oriented Programming
- ทุกอย่างใน Python เป็น Object แต่มี Type ของตัวเอง
- การทำเป็น Object มันเพิ่มตัว Data Abstraction มากขึ้นครับ โดยรวมสิ่งที่ใช้อยู่ด้วยกัน ผ่านทาง
- Data Attribute - สิ่วที่เราเก็บ เช่น ข้อมูลพนักงาน มีพวกซื่อ นามสกุล ตำแหน่ง เป็นต้น ครัช
- Interface - ช่องทาง ที่เราเรียกใช้งาน Object นั้น และเป็นกรอบของ Spec คร่าวๆ ให้สำหรับคนที่นำไป Implement ต่อ
- Class & Instance
- ตัว Python เอง มี Object พื้นฐานที่จำเป็นมาให้อยู่แล้ว อาทิ เช่น พวก Data Type ต่างๆ หรือ เป็นเฉพาะด้านอย่าง Math, String เป็นต้น ครับ
- ทำเป็น OOP แล้วได้อะไรบ้าง
- จัดกลุ่มเป็น Package ได้ - หา Pattern ที่ซ้ำกัน แยกออกมาเป็น Intercace
- Divide & Conquer - นอกแยก implement กับ interface แล้ว ยัง แยกขิ้นของงานออกมาให้ชัดเจน เพื่อลดความซับซ้อน
- Reuse - จริงๆ แล้ว OOP ออกแบบมา เพื่อแก้ปัญหาของการเขียนโปรแกรมแบบเก่าครับ คือ Object ที่เราสร้าง สามารถเอามาใช้ซ้ำได้ แต่ชิ้นอยู่กับการ Design
ลองมาสร้าง Object ของตัวเองดีกว่า
- สร้าง Class - ทุก Class สืบทอดมาจาก Class Object ดังนี้ครับ
class Animal(object): def __init__(self, age): self.age = age self.name = None
- ใช้ Method ที่ตัว Object โดยมี Pattern ที่สังเกตุได้ คือ __xxxx__ ได้แก่
- Constructor ของ Object
- def __init__(self): กับ def __init__(self, param a, param b, .... n):
- เปรียบได้กับ Method toString() ของ C# และ Java ครับ
- def __str__(self):
- และยังมี Method อื่นๆของ Class Object ให้ Override เช่น ในกลุ่มของการเปรียบเทียบ +, -, ==, <, >
- def __add__(self, other) //self + other
- def __sub__(self, other) //self - other
- def __eq__(self, other) //self == other
- def __lt__(self, other) //self < other
- หรือ การวัด เช่น len() เป็นต้น
- def __len__(self) //len(self)
- Constructor ของ Object
- self คือ อะไร ถ้าจาก Bullet ที่แล้ว แต่ละ Method มีหมดเลยนะ
- ถ้าเขียน C# หรือ Java มาก่อน มัน คือ this แหละครับ เอาไว้อ้างอิง member หรือ method ของ Class นั้นๆ
- สร้าง Method เอง เหมือนกับการสร้าง Method ที่ผ่านๆมาครับ แต่ Parameter ตัวแรกตัวเป็น self เสมอ เช่น
class Coordinate(object): def __init__(self, x, y): self.x = x self.y = y def distance(self, other): x_diff_sq = (self.x-other.x)**2 y_diff_sq = (self.y-other.y)**2 return (x_diff_sq + y_diff_sq)**0.5 def __str__(self): return "<" + str(self.x) + "," + str(self.y) + ">"
- เรียกใช้ Class ที่สร้าง
- แบบที่ 1 - เอา Instance ของ Class มาอ้างเลย ถึง method
c = Coordinate(3,4) origin = Coordinate(0,0) print(c.distance(origin))
- แบบที่ 2 - ชื่อ Class อ้าง Method แล้วส่วน Instance ของ Class เข้าไป (ส่วนตัวมองว่าแบบนี้ดูงงๆ กว่านะ)
c = Coordinate(3,4) origin = Coordinate(0,0) print(Coordinate.distance(c, origin))
- แบบที่ 1 - เอา Instance ของ Class มาอ้างเลย ถึง method
- Class Variable vs Instance Variable
- Class Variable - ถ้าเป็นพวก C#/Java ให้นึกถึงตัวแปรที่มี Modifier static นำหน้า
- Instance Variable - ตัวแปรกลุ่มนี้ ตรงข้ามกับ Class Variable แต่มีข้อสังเกตุ คือ ถูกกำหนดไว้ใน Contructor ตัว def __init__ นั่นเองครับ
Information Hiding ทำให้ข้อมูลนั้นปลอดภัย
- ความปลอดภัย มันเพิ่มขึ้น เพราะว่า เราได้กำหนดช่องทางให้จัดการ DataAttribute ผ่านตัว Method จากเดิมที่ใครๆก็เข้าถึงได้ Pattern ที่นิยมกันเป็นพวก Get กับ Set ตามตัวอย่าง year สามารถดึงข้อมูล ผ่านไปทาง Method get_age ครับ
class Animal(object): def __init__(self, age): self.years = age def get_age(self): return self.years
Inheritance(Extend) เมื่อ Object มีลูกหลาน
- จากตอนที่สร้าง Class เรารู้อยู่แล้วว่า ทุก Class Extend มาจาก Class Object เช่น Class Animal
class Animal(object): def __init__(self, age): self.age = age self.name = None def get_age(self): return self.age def get_name(self): return self.name def set_age(self, newage): self.age = newage def set_name(self, newname=""): self.name = newname def __str__(self): return "animal:"+str(self.name)+":"+str(self.age)
- ถ้าเราสร้าง Class เพิ่ม เราสามารถให้มัน Extend มาจาก Class เดิมได้ เช่น Class Cat ได้ทุกอย่างที่ Class Animal มีครับ ( Substitution principle) แต่มีการแก้ไข Method __str__(self) ให้เป็นตามที่ Class Cat ต้องการ ซึ่งการแก้ไขแบบนี้เรียกว่า Override ครับ
class Cat(Animal): def speak(self): print("meow”) def __str__(self): #override แก้ไขพฤติกรรมจาก Class Animal ครับ return "cat:"+str(self.name)+":"+str(self.age)
- สามารถดูสรุปได้ตามรูปนี้เลยครับ
Generator & Yield
- ทำไมต้องใช้ 2 ตัวนี้หละ ลองดูจาก Code ตัวอย่างนี้ดูครับ
class Grades(object): #Do something def allStudents(self): """Return a list of the students in the grade book""" if not self.isSorted: self.students.sort() self.isSorted = True return self.students[:]
- จาก Code ข้างต้น พบว่าคำสั่ง self.students[:] เป็นการ Copy List ซึ่งถ้ามีข้อมูลเยอะๆ สัก 100,000 Record มันไม่มีประสิทธิภาพครับ
- ตัวข่วยของเรา คือ Generator กับ Yield
- Yield - เป็นจุด Check Point เก็บ State ของการทำงานเดิมไว้ จากนั้นคืนค่ากลับมา
- Generator - Method ทีมีคำสั่ง Yield อยู่ข้างใน
- ตัว Generator มี Method __next__()
- ทำไม เราต้องใช้ตัว Generator หละ
- ต้องการ Performance เลยพยายามใช้ Memory เท่าที่จำเป็นต้องใช้งานเท่านั้น
- มันทำงานจนถึงคำสั่ง Yield แล้ว คืนค่าออกมาเป็นที่ละช่วง พอคืนค่าเสร็จ สิ่งที่ทดไว้ใน Memory จะถูกล้างไปได้
- แล้ว Class Grade ที่ปรับปรุงแล้วหละ ตามนี้เลยครับ
class Grades(object): #Do something def allStudents(self): """Return a list of the students in the grade book""" if not self.isSorted: self.students.sort() self.isSorted = True #ใช้ yield เพื่อเพ่มความเร็วในการทำงาน และลด Memory ที่ใช้ for s in self.students: yield s
หลังจากเรียนใน Course นี้ไป ผมเพิ่งว่าตัว Python สามารถเอามาเขียนแบบ OOP ได้ จากเดิมที่ใช้ Google Programming เขียน Code แบบ Procedural เพื่อให้งานเสร็จครับ อ๋อและสำหรับเรื่อง Generator กับ Yield ผมอาจจะเขียน Blog อีกตอนเพิ่มนะครับ ^___^
Discover more from naiwaen@DebuggingSoft
Subscribe to get the latest posts sent to your email.