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

ช่วงนี้ผมอัพ 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)
  • 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.