အခန်း 16 · animation 2 ခု

Chapter 15: OOP – Class နှင့် Object (Classes and Objects)

808 Coder မှ တင်ဆက်သည်

အရင်အခန်းတွေမှာ function တွေနဲ့ code ကို အပိုင်းပိုင်းခွဲပြီး ရေးခဲ့ပြီးပြီ။ အခု ဒီအခန်းကနေ စပြီး Python programming ရဲ့ အရေးအကြီးဆုံး အတွေးအခေါ်တစ်ခုကို လေ့လာတော့မယ် — အဲဒါကတော့ OOP (Object-Oriented Programming) ဖြစ်ပါတယ်။

OOP ဆိုတာ code တွေကို "object" ဆိုတဲ့ အစိတ်အပိုင်းလေးတွေအဖြစ် ဖွဲ့စည်းပြီး ရေးတဲ့ နည်းလမ်းပါ။ လက်တွေ့ဘဝမှာ ကျွန်တော်တို့ ပတ်ဝန်းကျင်က အရာအားလုံး — ကား၊ ဆိုင်၊ ဘဏ်အကောင့်၊ ကျောင်းသား — တစ်ခုချင်းစီဟာ သူ့ရဲ့ အချက်အလက် (data) နဲ့ သူလုပ်နိုင်တဲ့ အလုပ် (behavior) တွေ ပိုင်ဆိုင်ထားတယ်။ OOP က အဲဒီအတွေးအတိုင်းပဲ code ရေးတာဖြစ်လို့၊ ကြီးမားတဲ့ program တွေကို နားလည်ရလွယ်အောင်၊ ပြန်သုံးရလွယ်အောင် ကူညီပေးပါတယ်။

ဒီအခန်းပြီးရင်...

  • OOP ဆိုတာ ဘာလဲ၊ ဘာကြောင့် သုံးရတာလဲ ဆိုတာ ရှင်းပြနိုင်မယ်
  • OOP ရဲ့ အခြေခံတိုင် ၄ ခုကို ပြောပြနိုင်မယ်
  • class ကို ဖန်တီးပြီး object (instance) ထုတ်နိုင်မယ်
  • constructor (__init__), self, instance variable တွေကို နားလည်မယ်
  • ကိုယ်ပိုင် method တွေ ရေးပြီး object တွေကို အလုပ်ခိုင်းနိုင်မယ်

OOP ဆိုတာဘာလဲ

Object-Oriented Programming ဆိုတာ code ကို object တွေနဲ့ ဖွဲ့စည်းတဲ့ programming paradigm တစ်ခုပါ။ Object ဆိုတာ class တစ်ခုရဲ့ instance (လက်တွေ့ထုတ်ထားတဲ့ ကိုယ်ပွား) ဖြစ်တယ်။

ဥပမာ စဉ်းစားကြည့်ရအောင်။ ဆိုင်တစ်ဆိုင်ရဲ့ စာရင်းစနစ် ရေးတယ်ဆိုပါစို့။ Function တွေချည်း သုံးတဲ့ နည်းနဲ့ဆိုရင် ပစ္စည်းစာရင်း၊ ဈေးနှုန်း၊ ရောင်းရငွေ စတာတွေကို variable တွေအများကြီးနဲ့ လိုက်မှတ်ရမယ်။ OOP နည်းနဲ့ဆိုရင်တော့ "ပစ္စည်း" ဆိုတဲ့ class တစ်ခု ဆောက်လိုက်တယ်။ အဲဒီ class ကနေ ပစ္စည်းတစ်ခုချင်းစီကို object အဖြစ် ထုတ်လိုက်တယ်။ Object တစ်ခုချင်းစီမှာ သူ့နာမည်၊ သူ့ဈေး (data) နဲ့ ဈေးတွက်တာ၊ လက်ကျန်ပြတာ (behavior) တွေ အကုန်ပါပြီးသား။ ရှင်းတယ်၊ စနစ်ကျတယ်၊ ပစ္စည်းအသစ်တိုးရင်လည်း object အသစ်ထုတ်လိုက်ရုံပဲ။

မှတ်ချက်

OOP က အကြီးစား program တွေမှာ အထူးအသုံးဝင်ပါတယ် — code ပြန်သုံးရတာ လွယ်တယ်၊ အမှားရှာရတာ လွယ်တယ်၊ အဖွဲ့လိုက်ရေးရတာ လွယ်တယ်။

Reference

Function တွေချည်းသုံးတာနဲ့ ဘာကွာလဲ

Function တွေချည်း သုံးတဲ့ ပုံစံ (procedural style) နဲ့ နှိုင်းယှဉ်ကြည့်ရအောင်။ ကျောင်းသား ၃ ယောက်ရဲ့ အချက်အလက် မှတ်တယ်ဆိုပါစို့ —

# Procedural style: data တွေ ပြန့်ကျဲနေတယ်
s1_name = "Aung Khant"
s1_grade = 85
s2_name = "Mya Thiri"
s2_grade = 45
s3_name = "Zaw Htet"
s3_grade = 72

def show_result(name, grade):
    status = "Pass" if grade >= 50 else "Fail"
    print(f"{name}: {grade} ({status})")

show_result(s1_name, s1_grade)
show_result(s2_name, s2_grade)
show_result(s3_name, s3_grade)
Aung Khant: 85 (Pass)
Mya Thiri: 45 (Fail)
Zaw Htet: 72 (Pass)

အလုပ်ဖြစ်တယ် — ဒါပေမယ့် ကျောင်းသား ၁၀၀ ယောက် ဖြစ်လာရင် variable ၂၀၀ လောက် လိုက်မှတ်ရမယ်။ နာမည်နဲ့ အမှတ် တွဲဖက်မှု လွဲသွားနိုင်တယ် (ဥပမာ — show_result(s1_name, s2_grade) လို့ မှားထည့်မိရင် ဘယ်သူမှ သတိမထားမိဘူး)။ OOP နည်းနဲ့ဆိုရင်တော့ ကျောင်းသားတစ်ယောက်ချင်းစီက သူ့ data နဲ့ သူ့အလုပ် (result ပြတာ) ကို ကိုယ်တိုင်သယ်ဆောင်ထားတဲ့ object တစ်ခု ဖြစ်သွားတယ်။ Data ပြန့်ကျဲတာ မရှိတော့ဘူး၊ မှားယွင်းတွဲဖက်မိတာ မရှိတော့ဘူး။ ဒါကြောင့် program ကြီးလာလေ OOP ရဲ့ အကျိုး ထင်ရှားလာလေပဲ။

OOP ရဲ့ အခြေခံတိုင် ၄ ခု

OOP မှာ အဓိက အယူအဆကြီး ၄ ခု ရှိတယ်။ ဒါကို "4 Pillars of OOP" လို့ ခေါ်တယ်။ ဒီအခန်းမှာ အကျဉ်းချုပ် မိတ်ဆက်ပေးမယ်၊ နောက်အခန်းတွေမှာ တစ်ခုချင်းစီ အသေးစိတ် လေ့လာမယ်။

တိုင် အဓိပ္ပာယ် အကျဉ်းချုပ် ဘယ်အခန်းမှာ သင်မလဲ
Encapsulation Object ရဲ့ အတွင်းရေးကို ဖုံးကွယ်ပြီး လိုအပ်တဲ့အပိုင်းကိုပဲ အပြင်ကနေ သုံးခွင့်ပေးတာ Chapter 18
Abstraction အသေးစိတ်ကို ဝှက်ပြီး အရေးကြီးတဲ့ အပိုင်းကိုပဲ ပြတာ (ဥပမာ — ကားမောင်းတာ၊ အင်ဂျင်အတွင်းပိုင်း မသိလည်း ရ) Chapter 18 မှာ ဆက်စပ်
Inheritance class တစ်ခုက နောက်တစ်ခု class ရဲ့ အချက်အလက်/အလုပ်တွေကို အမွေဆက်ခံတာ Chapter 16
Polymorphism method နာမည်တူကို object အမျိုးအစားအလိုက် မတူညီတဲ့ အပြုအမူ ပြတာ ("many forms") Chapter 17

OOP ကို ဘယ်အချိန်သုံးသင့်လဲ

Program တိုင်းကို OOP နဲ့ ရေးရမလား? မဟုတ်ဘူး။ Script အသေးစား (ဥပမာ — file နာမည်ပြောင်းတဲ့ script) ဆို function တွေနဲ့တင် လုံလောက်တယ်။ ဒါပေမယ့် "အရာ" တွေ (entity) အများအပြား ပါဝင်လာတဲ့အခါ — ကျောင်းသား၊ အကောင့်၊ ပစ္စည်း၊ ဝန်ထမ်း — OOP က အနိုင်ရတယ်။ စည်းမျဉ်းအတိုချုပ်: data နဲ့ အဲဒီ data ပေါ် လုပ်တဲ့ အလုပ် တွဲဖက်နေရင် class လုပ်၊ ရိုးရိုးတွက်ချက်မှုသက်သက်ဆို function နဲ့တင် ရတယ်။

ဒီအခန်းကတော့ အခြေခံ — class နဲ့ object ကို အရင် ကျွမ်းကျင်အောင် လုပ်မယ်။ တိုင် ၄ ခုလုံးကို တစ်ခါတည်း အလွတ်ကျက်စရာ မလိုဘူး — အခု အကျဉ်းချုပ်ဖတ်ထားပြီး နောက်အခန်းတွေမှာ တစ်ခုချင်း လက်တွေ့နဲ့ သင်ယူသွားမယ်။

Reference

Class ဆိုတာဘာလဲ

Class ဆိုတာ object တွေ ထုတ်ဖို့ရဲ့ blueprint (ပုံစံခွက်) ပါ။ အိမ်ဆောက်ဖို့ အဆောက်အအုံ ပုံစံစာရွက် (blueprint) ရှိသလို၊ object ထုတ်ဖို့ class ရှိတယ်။ ပုံစံစာရွက်ကိုယ်တိုင်က အိမ် မဟုတ်ဘူး — အဲဒီစာရွက်ကနေ ဆောက်လိုက်တဲ့ အိမ်တွေကမှ တကယ့် အိမ် (object) တွေ။

Class ဖန်တီးတဲ့ syntax က ဒီလိုပါ —

class Person:
    pass

class ဆိုတဲ့ keyword ကို သုံးပြီး class နာမည်ပေးတယ်။ pass ဆိုတာ "အထဲမှာ ဘာမှ မရှိသေးဘူး" လို့ ပြောတာ။

မှတ်ချက်

Class နာမည်ပေးတဲ့အခါ PascalCase သုံးတာ စံဖြစ်ပါတယ် — စာလုံးတိုင်းရဲ့ အစကို အကြီးနဲ့ ရေးတာ (Person, BankAccount, Motorbike)။ variable/function နာမည်တွေနဲ့ ခွဲခြားရလွယ်အောင်ပါ။

Reference

Object ဆိုတာဘာလဲ

Object ဆိုတာ class တစ်ခုရဲ့ instance — blueprint ကနေ တကယ်ထုတ်လိုက်တဲ့ ကိုယ်ပွားတစ်ခုပါ။ Object ထုတ်တာကို "instantiate လုပ်တာ" လို့လည်း ခေါ်တယ်။

class Person:
    pass

p1 = Person()
p2 = Person()

print(type(p1))
print(p1 is p2)
<class '__main__.Person'>
False

p1 နဲ့ p2 ဟာ Person class ကနေ ထုတ်ထားတဲ့ object နှစ်ခု — ပုံစံတူကြပေမယ့် တစ်ခုနဲ့တစ်ခု သီးခြားစီ (is နဲ့ စစ်ရင် False ထွက်)။ ဒီသဘောက အရေးကြီးတယ် — object တစ်ခုချင်းစီမှာ သူ့ကိုယ်ပိုင် data ရှိတယ်။

Object တစ်ခုချင်းစီ သီးခြားရပ်တည်တယ်

Object တွေ သီးခြားစီဆိုတာ ဘာအဓိပ္ပာယ်လဲ၊ ကိုယ်တိုင်ပါတဲ့ ဥပမာငယ်နဲ့ စမ်းကြည့်ရအောင် —

class Counter:
    def __init__(self):
        self.count = 0

    def add(self):
        self.count += 1

c1 = Counter()
c2 = Counter()

c1.add()
c1.add()

print(c1.count)  # 2
print(c2.count)  # 0 — လုံးဝ မထိခိုက်ဘူး
2
0

c1 မှာ add() နှစ်ခါ ခေါ်လိုက်တာ c2 ကို လုံးဝ မထိခိုက်ဘူး။ Class တူကနေ ထုတ်ထားပေမယ့် data က ကိုယ်စီသီးခြား။ ဒီသဘောကြောင့် program မှာ အကောင့်ရာချီ၊ ကျောင်းသားထောင်ချီ ရှိလည်း တစ်ခုချင်းစီကို စိတ်ချလက်ချ ကိုင်တွယ်လို့ရတယ် — တစ်ခုကို ပြင်တာ နောက်တစ်ခုကို မထိဘူးဆိုတာ သေချာတယ်။

One class, many independent objects class Student name grade display() blueprint s1 "Aung", 10 s2 "Thida", 9 s3 "Zaw", 10 changing s1 never affects s2 or s3
class တစ်ခုတည်းက object အများကြီး ဖန်တီးပုံ

Reference

Constructor: __init__ နဲ့ self

Object ထုတ်လိုက်တဲ့အခါ အလိုအလျောက် ခေါ်ခံရတဲ့ အထူး method တစ်ခုရှိတယ် — အဲဒါ constructor ပါ။ Python မှာ သူ့နာမည်က __init__။ သူ့အလုပ်က object အသစ်ကို initialize လုပ်တာ — ဆိုလိုတာက စစချင်း တန်ဖိုးတွေ ထည့်ပေးတာ။

class Customer:
    def __init__(self, name, points):
        self.name = name
        self.points = points

    def show(self):
        print(f"{self.name} has {self.points} points.")

c1 = Customer("Thandar", 120)
c1.show()
Thandar has 120 points.

ဒီမှာ အရေးကြီးတဲ့ အချက် ၃ ခု ရှိတယ် —

  1. __init__ — Customer("Thandar", 120) လို့ object ထုတ်လိုက်တာနဲ့ Python က __init__ ကို အလိုအလျောက် ခေါ်တယ်။ ကိုယ်တိုင် c1.__init__(...) လို့ ခေါ်စရာ မလိုဘူး။
  2. self — method တိုင်းရဲ့ ပထမဆုံး parameter ဖြစ်ရမယ်။ self ဆိုတာ "object ကိုယ်တိုင်" ကို ဆိုလိုတာ။ c1.show() လို့ ခေါ်ရင် Python က c1 ကို self နေရာမှာ အလိုအလျောက် ထည့်ပေးတယ်။ ဒါကြောင့် self.name ဆိုတာ "ဒီ object ရဲ့ name" လို့ အဓိပ္ပာယ်ရတယ်။
  3. Instance variable — self.name = name လို့ ရေးလိုက်တာနဲ့ အဲဒီ object အတွက် သီးသန့် variable တစ်ခု ဖန်တီးပြီးသား ဖြစ်သွားတယ်။ Object တစ်ခုချင်းစီမှာ ကိုယ်ပိုင် name, points ရှိတယ်။
What happens in Customer("Thandar", 120) Customer("Thandar", 120) "Thandar" 120 -> name -> points object c1 self.name = "Thandar" self.points = 120 instance variables live inside the object self points to the new object __init__ runs automatically when the object is created
__init__ မှာ self နဲ့ parameter တွေ အလုပ်လုပ်ပုံ

သတိပြုရန်

Method တစ်ခုခုမှာ self ကို ပထမ parameter အဖြစ် မေ့ပြီး မထည့်မိရင် TypeError တက်မယ်။ def show(self): — ဒီ self က မဖြစ်မနေ ပါတယ်။

မှတ်ချက်

__init__ မှာ return ပြန်စရာ မလိုပါဘူး။ သူ့အလုပ်က object ကို ပြင်ဆင်ပေးရုံပဲ — object ကိုယ်တိုင်ကို Python က ပြန်ပေးတယ်။

Object ထုတ်တဲ့အခါ နောက်ကွယ်မှာ ဘာဖြစ်လဲ

c1 = Customer("Thandar", 120) ဆိုတဲ့ စာကြောင်းတစ်ကြောင်းမှာ အဆင့် ၃ ဆင့် ဖြစ်သွားတယ် —

  1. Python က Customer class အတွက် object အလွတ်တစ်ခု ဖန်တီးတယ်။
  2. __init__ ကို အလိုအလျောက် ခေါ်တယ် — self နေရာမှာ object အသစ်၊ name နေရာမှာ "Thandar"၊ points နေရာမှာ 120 ထည့်ပေးတယ်။ self.name = name ဆိုတာက object အသစ်ထဲမှာ name ဆိုတဲ့ instance variable ဖန်တီးပြီး "Thandar" သိမ်းတာ။
  3. ပြင်ဆင်ပြီးသား object ကို c1 variable ထဲ ထည့်ပေးတယ်။

ဒါကြောင့် __init__ ရဲ့ parameter တွေက object ထုတ်တဲ့အခါ ပေးရမယ့် တန်ဖိုးတွေနဲ့ တစ်ထပ်တည်း ကိုက်ညီရတယ် (self ကို ဖယ်ပြီး)။

သတိပြုရန်

__init__(self, name, points) လို့ သတ်မှတ်ထားရင် object ထုတ်တဲ့အခါ Customer("Thandar", 120) လို့ argument ၂ ခု မဖြစ်မနေ ပေးရမယ်။ self အတွက် ပေးစရာ မလိုဘူး — Python က အလိုအလျောက် ဖြည့်ပေးတယ်။ Customer("Thandar") လို့ points မပေးဘဲ ခေါ်ရင် TypeError တက်မယ်။

Reference

Method ဆိုတာဘာလဲ

Method ဆိုတာ class အထဲမှာ ရေးထားတဲ့ function ပါ။ Object တစ်ခုက "လုပ်နိုင်တဲ့ အလုပ်" တွေကို method တွေနဲ့ သတ်မှတ်တယ်။

class Motorbike:
    def ride(self):
        print("The motorbike is riding.")

    def honk(self):
        print("Beep beep!")

my_bike = Motorbike()
my_bike.ride()
my_bike.honk()
The motorbike is riding.
Beep beep!

ride() နဲ့ honk() ဟာ Motorbike class ရဲ့ method တွေ။ my_bike.ride() လို့ ခေါ်တာက "my_bike ဆိုတဲ့ object ကို ride ဆိုတဲ့ အလုပ် လုပ်ခိုင်း" တာ။ Dot (.) က "ဒီ object ရဲ့" လို့ အဓိပ္ပာယ်ရတယ်။

Method ခေါ်တဲ့အခါ dot ရဲ့ ဘယ်ဘက်က object ကို self အဖြစ် Python က အလိုအလျောက်ပို့ပေးတယ် — my_bike.ride() မှာ self = my_bike ဖြစ်သွားတယ်။ ဒါကြောင့် method ထဲမှာ self မပါရင် object ရဲ့ data ကို လှမ်းသုံးလို့ မရဘူး။

Method တွေက instance variable တွေကို self ကနေ တဆင့် သုံးနိုင်တယ် —

class Wallet:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance

    def deposit(self, amount):
        self.balance += amount
        print(f"Deposited: {amount} kyats")

    def withdraw(self, amount):
        if amount <= self.balance:
            self.balance -= amount
            print(f"Withdrew: {amount} kyats")
        else:
            print("Not enough balance!")

    def display(self):
        print(f"{self.owner}'s balance: {self.balance} kyats")

w1 = Wallet("Aung Khant", 5000)
w1.deposit(2000)
w1.withdraw(1500)
w1.withdraw(9000)
w1.display()
Deposited: 2000 kyats
Withdrew: 1500 kyats
Not enough balance!
Aung Khant's balance: 5500 kyats

ဒီ Wallet class က data (owner, balance) နဲ့ အဲဒီ data ပေါ်မှာ လုပ်တဲ့ အလုပ် (deposit, withdraw, display) တွေကို တစ်နေရာတည်း စုထားတယ်။ ဒါဟာ OOP ရဲ့ အနှစ်သာရပဲ — data နဲ့ behavior ကို တစ်ခုတည်း ထုပ်ပိုးထားတာ။

မှတ်ချက်

balance=0 လို့ __init__ မှာ ရေးထားတာက default parameter — Wallet("Aung Khant") လို့ balance မပေးဘဲ ထုတ်ရင် 0 နဲ့ စမယ်။

Reference

လက်တွေ့ဥပမာ: စာကြည့်တိုက် စာအုပ်စနစ်

ဒီအခန်းမှာ သင်ခဲ့တာတွေကို တစ်ခုတည်း ပေါင်းသုံးထားတဲ့ ဥပမာတစ်ခု ကြည့်ရအောင် —

class LibraryBook:
    def __init__(self, title, author):
        self.title = title
        self.author = author
        self.is_borrowed = False   # စစချင်း ငှားလို့ရတယ်

    def borrow(self):
        if not self.is_borrowed:
            self.is_borrowed = True
            print(f"'{self.title}' borrowed.")
        else:
            print(f"'{self.title}' is already borrowed.")

    def return_book(self):
        self.is_borrowed = False
        print(f"'{self.title}' returned.")

    def status(self):
        state = "borrowed" if self.is_borrowed else "available"
        print(f"'{self.title}' by {self.author} - {state}")


b1 = LibraryBook("The Story of Myanmar", "Maung Maung")
b1.status()
b1.borrow()
b1.borrow()       # ထပ်ငှားကြည့်တာ — ငြင်းမယ်
b1.return_book()
b1.status()
'The Story of Myanmar' by Maung Maung - available
'The Story of Myanmar' borrowed.
'The Story of Myanmar' is already borrowed.
'The Story of Myanmar' returned.
'The Story of Myanmar' by Maung Maung - available

is_borrowed ဆိုတဲ့ instance variable က စာအုပ်ရဲ့ အခြေအနေကို မှတ်ထားတယ်။ borrow() method က အခြေအနေကို စစ်ပြီးမှ ပြောင်းတယ် — data ကို method ကတဆင့် ထိန်းချုပ်တဲ့ OOP အကျင့်ကောင်းပဲ။ (Chapter 18 မှာ ဒီအကျင့်ကို ပိုတင်းကျပ်တဲ့ private/validation ပုံစံနဲ့ သင်မယ်။)

Object တွေကို list ထဲမှာ စီမံတာ

လက်တွေ့ program တွေမှာ object တစ်ခုတည်း မဟုတ်ဘဲ အများအပြားကို list ထဲမှာ သိမ်းပြီး loop နဲ့ ကိုင်တွယ်လေ့ရှိတယ် —

class Student:
    def __init__(self, name, grade):
        self.name = name
        self.grade = grade

    def is_passed(self):
        return self.grade >= 50

students = [
    Student("Aung Khant", 85),
    Student("Mya Thiri", 45),
    Student("Zaw Htet", 72),
]

for s in students:
    status = "Pass" if s.is_passed() else "Fail"
    print(f"{s.name}: {s.grade} - {status}")
Aung Khant: 85 - Pass
Mya Thiri: 45 - Fail
Zaw Htet: 72 - Pass

Object တွေကို list ထဲ ထည့်ထားတော့ ကျောင်းသား ၃ ယောက်လုံး (သို့) အယောက် ၃၀၀ လုံးကို loop တစ်ခု တည်းနဲ့ ကိုင်တွယ်လို့ရတယ်။ Object တစ်ခုချင်းစီက သူ့ is_passed() ကို ကိုယ်တိုင်တွက်ပေးတယ် — ခေါ်တဲ့သူက အသေးစိတ် စဉ်းစားစရာ မလိုဘူး။ ဒီပုံစံက Chapter 17 ရဲ့ Hospital Appointment System မှာလည်း ပြန်တွေ့ရမယ် (self.doctors list)။

Class ကို docstring နဲ့ မှတ်တမ်းတင်တာ

Class ရေးတဲ့အခါ အဲဒီ class က ဘာလုပ်တာလဲ ဆိုတာ docstring (သုံးထပ်ကိုးကားနဲ့ စာသား) နဲ့ ရေးမှတ်ထားတာ အကျင့်ကောင်းပါ —

class Wallet:
    """ငွေစုပိုက်ဆံအိတ် — deposit/withdraw/display method တွေ ပါဝင်တယ်."""

    def __init__(self, owner, balance=0):
        """owner နာမည်နဲ့ စတင်လက်ကျန်နဲ့ wallet အသစ် ဖန်တီးတယ်။"""
        self.owner = owner
        self.balance = balance

print(Wallet.__doc__)
ငွေစုပိုက်ဆံအိတ် — deposit/withdraw/display method တွေ ပါဝင်တယ်။

__doc__ က class ရဲ့ docstring ကို ပြန်ပေးတယ်။ လအတော်ကြာမှ ကိုယ့် code ကို ပြန်ဖတ်ရတဲ့အခါ ဒီမှတ်တမ်းလေးတွေက အချိန်အများကြီး သက်သာစေတယ်။

Reference

Reference

အနှစ်ချုပ်

ဒီအခန်းမှာ OOP ရဲ့ အခြေခံအုတ်မြစ်ကို ချခဲ့ပြီးပြီ။ Class ဆိုတာ ပုံစံခွက်ဖြစ်ပြီး object ဆိုတာ အဲဒီပုံစံခွက်ကနေ ထုတ်ထားတဲ့ လက်တွေ့ကိုယ်ပွားဆိုတာ၊ object ထုတ်တိုင်း __init__ က အလိုအလျောက်အလုပ်လုပ်ပြီး self က object ကိုယ်တိုင်ကို ကိုယ်စားပြုတာဆိုတာ၊ data နဲ့ method ကို တစ်ခုတည်း ထုပ်ပိုးထားတာဟာ OOP ရဲ့ အနှစ်သာရဆိုတာ — ဒါတွေအားလုံး နားလည်သွားရင် နောက် ၃ ခန်းမှာ လာမယ့် inheritance, polymorphism, encapsulation တွေကို သင်ယူဖို့ အဆင်သင့် ဖြစ်နေပြီ။

  • OOP ဆိုတာ code ကို object တွေနဲ့ ဖွဲ့စည်းတဲ့ programming paradigm — data နဲ့ behavior ကို တစ်ခုတည်း ထုပ်ပိုးထားတယ်။ Program ကြီးလာလေ အကျိုးပိုထင်ရှားလေပဲ။
  • Class က blueprint (ပုံစံခွက်)၊ object က အဲဒီ blueprint ကနေ ထုတ်ထားတဲ့ instance (ကိုယ်ပွား)။ Class တစ်ခုတည်းကနေ object အများအပြား ထုတ်နိုင်ပြီး တစ်ခုချင်းစီ သီးခြားရပ်တည်တယ်။
  • Constructor (__init__) က object ထုတ်တိုင်း အလိုအလျောက်ခေါ်ခံရပြီး စစချင်း တန်ဖိုးတွေ ထည့်ပေးတယ်။ return ပြန်စရာ မလိုဘူး။
  • self က method တိုင်းရဲ့ ပထမ parameter — "object ကိုယ်တိုင်" ကို ဆိုလိုတယ်။ Python က အလိုအလျောက် ဖြည့်ပေးတယ်။
  • Instance variable (self.name = ...) က object တစ်ခုချင်းစီရဲ့ ကိုယ်ပိုင် data။
  • Method က class အထဲက function — object ရဲ့ အလုပ်တွေကို သတ်မှတ်တယ်။

နောက်တစ်ခေါက် ပြန်ဖတ်တဲ့အခါ ဒီအနှစ်ချုပ်က စစ်ဆေးစရာစာရင်း (checklist) အဖြစ် သုံးနိုင်တယ် — တစ်ချက်ချင်းစီကို ကိုယ့်ဘာသာ ဥပမာနဲ့ ရှင်းပြနိုင်ရင် ဒီအခန်း ကျွမ်းကျင်ပြီလို့ သတ်မှတ်နိုင်တယ်။

အမှားများတတ်တဲ့ အချက်များ

  1. self မေ့တာ — def show(): လို့ self မထည့်မိရင် TypeError တက်မယ်။ Method တိုင်းမှာ self က ပထမ parameter ဖြစ်ရမယ်။
  2. Class နာမည်နဲ့ object နာမည် ရောတာ — Person (class, အကြီးနဲ့စ) နဲ့ p1 (object) ကို ခွဲခြားမှတ်ပါ။ Person() လို့ လက်သည်းကွင်းနဲ့ ခေါ်မှ object ရတယ်။
  3. __init__ ရဲ့ argument အရေအတွက် လွဲတာ — __init__(self, name, grade) ဆို object ထုတ်တဲ့အခါ argument ၂ ခု တိတိကျကျ ပေးရမယ်။ လိုတာ/ပိုတာ TypeError ပဲ။
  4. Method ကို class အပြင်မှာ ရေးမိတာ — indent မှားရင် method က class ထဲ မဝင်ဘဲ သာမန် function ဖြစ်သွားမယ်။ Method တိုင်းက class အထဲမှာ မှန်ကန်စွာ indent ဖြစ်နေဖို့ အမြဲ စစ်ပါ။

လေ့ကျင့်ခန်းများ

အောက်က လေ့ကျင့်ခန်းတွေကို အရင်ကိုယ်တိုင် ကြိုးစားရေးကြည့်ပါ။ ပြီးမှ အဖြေနဲ့ တိုက်ကြည့်ပါ။ မှားမှာကို မကြောက်ပါနဲ့ — မှားမှ တကယ်သင်ယူရတာ။

၁။ Novel class — title, author, year ဆိုတဲ့ attribute တွေနဲ့ details() method ပါတဲ့ Novel class တစ်ခု ရေးပါ။

class Novel:
    def __init__(self, title, author, year):
        self.title = title
        self.author = author
        self.year = year

    def details(self):
        print(f"'{self.title}' by {self.author} ({self.year})")

n1 = Novel("Shwe Thway", "Journal Kyaw Ma Ma Lay", 1975)
n1.details()
'Shwe Thway' by Journal Kyaw Ma Ma Lay (1975)

၂။ Triangle class — base, height ယူပြီး area() method က ဧရိယာ (0.5 * base * height) ပြန်ပေးတဲ့ Triangle class ရေးပါ။

class Triangle:
    def __init__(self, base, height):
        self.base = base
        self.height = height

    def area(self):
        return 0.5 * self.base * self.height

t = Triangle(10, 6)
print("Area:", t.area())
Area: 30.0

၃။ Song class — title, singer, duration (စက္ကန့်နဲ့) ပါပြီး show_info() method က အချက်အလက် ၃ ကြောင်း ထုတ်ပြတဲ့ Song class ရေးပါ။

class Song:
    def __init__(self, title, singer, duration):
        self.title = title
        self.singer = singer
        self.duration = duration

    def show_info(self):
        print(f"Title   : {self.title}")
        print(f"Singer  : {self.singer}")
        print(f"Duration: {self.duration} seconds")

s1 = Song("A Chit Sone", "Sai Sai Kham Leng", 245)
s1.show_info()
Title   : A Chit Sone
Singer  : Sai Sai Kham Leng
Duration: 245 seconds

၄။ Trainee class — name, trainee_id, score ပါပြီး၊ is_passed() method က score 60 နဲ့အထက် ဆို True ပြန်ပေးတဲ့ Trainee class ရေးပါ။ (is_passed ကို class အထဲမှာ မှန်ကန်စွာ indent လုပ်ဖို့ သတိထားပါ။)

class Trainee:
    def __init__(self, name, trainee_id, score):
        self.name = name
        self.trainee_id = trainee_id
        self.score = score

    def show_info(self):
        print(f"Name      : {self.name}")
        print(f"Trainee ID: {self.trainee_id}")
        print(f"Score     : {self.score}")

    def is_passed(self):
        if self.score >= 60:
            return True
        else:
            return False

t1 = Trainee("May Thazin", "T101", 78)
t2 = Trainee("Kaung Htet", "T102", 45)

t1.show_info()
print("Passed?", t1.is_passed())
print()
t2.show_info()
print("Passed?", t2.is_passed())
Name      : May Thazin
Trainee ID: T101
Score     : 78
Passed? True

Name      : Kaung Htet
Trainee ID: T102
Score     : 45
Passed? False

၅။ (စိန်ခေါ်မှု) — owner, balance ပါတဲ့ BankAccount class ကို deposit(amount), withdraw(amount), display_balance() method ၃ ခုနဲ့ ရေးပါ။ withdraw မှာ လက်ကျန်ထက် ပိုထုတ်ရင် "Insufficient balance" ပြရမယ်။