[MITx: 6.00.1x] Introduction to Computer Science and Programming Using Python (Week 5) – OOP

ช่วงนี้ผมอัพ Blog เกี่ยว Course Python ของทาง MITx รัวๆ นะครับ เพราะ ใกล้สอบ Final แล้ว โดยสำหรับใน Week นี้เป็นเรื่องของ OOP เป็นหลัก มาเริ่มกันเลย

Type Hint

บอก Type ข้อมูล

  • ตัวแปร เติม : บอก Type ไป ผมทำ dotnet เลยมาจดๆ อันนี้
# Type Hint
name: str = "ping"
age: int = 34
gpa: float = 3.41
isPass: bool  = True
  • function
# Type Hint in function
def add (a: int, b: int) -> int:
  return a + b

add(5,7)

Lambda Function

เอาไว้เขียน function สั้นๆง่าย
รูปแบบ lambda arguments: expression โดยมีตัวอย่าง

add_10 = lambda x: x + 10
print(add_10(5))  # Output: 15

ปกติใช้ในการที่ต้องทำการ Function เล็ก ในการจัดการข้อมูล เช่น ใน List หรือ Stream ตัวอย่างเอามาช่วยหาที่เลขคู่

numbers = [1, 2, 3, 4]
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers)  # Output: [2, 4]

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)

📌 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))

📌 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.