Class တစ္ခုထဲမွာသူနဲ ့သက္ဆိုင္တဲ့ Functions ေတြ Variables ေတြပါ၀င္ပါမယ္။ Variable ဆိုလို ့Global & Local ေတာ့သိျပီးျပီမလား၊ မသိရင္လဲကြ်န္ေတာ္ Let's Write Python [4] ထဲကေအာက္ဆံုးပိုင္းနားေလာက္မွာအက်ဥ္းခ်ံုးရွင္းျပထားတာရွိပါတယ္။
Class အေျကာင္းကိုမေျပာခင္ကြ်န္ေတာ္တို ့ Class နဲ ့Object မတူတာကိုအရင္ရွင္းျပပါမယ္။ Class ဆိုတာကတကယ္ေတာ့ သူထဲမွာဘယ္လို Variable ေတြပါမယ္ေနာက္ဒီ Variable ေတြကိုဘယ္လို function ကအသံုးခ်မယ္ဒီလိုလုပ္ေဆာင္မည့္လုပ္ေဆာင္ခ်က္အတြက္ဆိုင္ရာဆိုင္ရာေတြကိုတစုတစည္း
ထဲစုစည္းလိုက္တာပါပဲ။ ပိုရွင္းေအာင္ေျပာရမယ္ဆိုသင္က encoder_decoder script တစ္ခုေရးုျပီဆို
ပထမ Class ကို encoder အတြက္သူေအာက္မွာ encoding method အမ်ိုးမ်ိုးအတြက္ function ေတြစုထားမယ္။ ေနာက္ decoder ဆိုတဲ့ Class အဲ့ေအာက္မွာလဲသူ ့သက္ဆိုင္ရာ function ေတြ
သတ္သတ္စုထားမယ္။ ဒီလိုလုပ္လိုက္ခ်င္းအားျဖင့္ source code ကျကည့္လိုလဲရွင္းျပီးသပ္သပ္ရပ္ရပ္ျဖစ္သြားပါတယ္။
ေနာက္ဒီလိုမ်ိုး Class တစ္ခုေဆာက္လိုက္ခ်င္းအားျဖင့္ဒါကို instance အေနနဲ့ျပန္ေခါ္
နိုင္ပါတယ္။
The Python Class
class Foo: # class is a keyword of making class
def __init__(self, val):
self.val = val
def valuePrint(self):
print self.val
ဘာမွမပ ာုတ္ပါဘူးရယ္ Foo ဆိုတဲ့ Class ေလးတစ္ခုေဆာက္လိုက္တယ္ေနာက္ဒီ Class ထဲမွာ function ၂ခုပါပါတယ္။ တစ္ခုက __init__ ဆိုတဲ့ေကာင္ေနာက္တစ္ေကာင္က valuePrint ဆိုတဲ့ေကာင္။ဒါဆို function ေတြ variable ေတြစုျကည့္လိုက္မယ္ဆို။ Function က __init__ ရယ္ valuePrint ရယ္ ေနာက္ Variable ကေတာ့ val ဆိုတဲ့တစ္ခုပဲ။ ဒီ Function ၂ခုစလံုးမွာ self ဆိုတဲ့ parameter ေတြပါရွိတယ္။ ေျပာအံုးမယ္ self လို ့ပဲေခါ္ရမယ္လို ့မသတ္မွတ္ထားပါဘူးခင္ဗ်ားဘာသာ ျကိုက္သလိုေပးရတယ္ဒါေပသိ self လို ့ပဲေပးပါဘာလို ့လဲဆိုေတာ့ Python မွာကဒီလိုပဲေရးျကပါတယ္။ သင့္ source code ကိုတျခား programmer ကျကည့္ရင္လဲအဆင္ေျပမွာပါ။ ေျပာရရင္ ပံုေသတစ္ခုလိုျဖစ္ေနျပီမို ့ပါ။ ေနပါအံုးဗ်အဲ့ self ျကီးကေကာဘာအတြက္ထည့္ေရးထားရတာလဲ?
ဘာအတြက္လဲဆိုေတာ့ class instance ေတြလုပ္တဲ့အခါဘယ္ instance နဲ ့အလုပ္လုပ္ေနမလဲဆိုတာကိုသိဖို ့အတြက္ Python ကအဲ့ကေန pass သြားမွာမို ့ပါ။
__init__ ဆိုတာကေတာ့ class ထဲမွာ Python က new instance ေတြလုပ္တိုင္းမွာေခါ္သံုးတဲ့ special method (function) တစ္ခုပါ။ အေပါ္က example မွာဆို input ကို accept လုပ္ဖို ့val ဆိုတဲ့ parameter တစ္ခုရွိပါမယ္ ေနာက္ member variable ထဲမွာသူကိုပဲ copy လုပ္ထားတဲ့ val ဆိုတာရွိပါေသးတယ္။ ေခါင္းစားသြားလားမသိ.... ဒီလိုဗ်။ Python မွာကေလတျခား Language ေတြနဲ ့မတူဘူးဗ် C တို ့ဆိုရင္လဲ Variable ကိုေျကညာေပးရပါတယ္ integer ဆိုလဲ integer ေပါ့သို့ေပမယ့္ Python မွာက်ေတာ့သူက assign လုပ္တဲ့အခါက်မွ variable ကို create လုပ္တာဗ် ခုနကေျပာသြားတဲ့ parameter val နဲ ့variable member val နဲ့ဘယ္လိုကြာလဲေျပာျပမယ္။ ေအာက္ကေကာင္ေလးမွာဆို...
self.val = val
self.val ဆိုတာက class instance နဲ ့သက္ဆိုင္တဲ့ variable member ကိုေျပာတာျဖစ္ျပီး val ဆိုတာကက်ေတာ့ function ထဲကို pass လုပ္မယ့္ parameter ကိုေျပာတာပါ ဒီေလာက္ဆိုျမင္ေလာက္မယ္ထင္ပါတယ္။ မရွင္းေသးရင္ေအာက္က Example ကိုထပ္ျကည့္ျကည့္သူက Class instance ကို create လုပ္လိုက္ပါတယ္။ __init__ ကိုေတာ့ Python ကေနပဲသူဘာသာေခါ္ေပးျပီး valuePrint ထဲကို pass လုပ္ေပးလိုက္ပါတယ္။ ေနာက္ေတာ့ instance ကေန Class ရဲ့ function ကိုေခါ္လိုက္ပါတယ္။
>>> the_example = Foo(1)
>>> the_example.valuePrint()
1
Standard Python Class Methods
Python Classes မွာ standard methods ေတြရွိပါတယ္ တစ္ခုကေတာ့အေပါ္မွာေရးခဲ့ျကတဲ့ __init__ ေပါ့။ သူကိုျပန္ရွင္းျပရမယ္ဆို သူက class instance တစ္ခုလုပ္လိုက္တိုင္း Python ကေခါ္ဖို ့အတြက္ပါ။ ေနာက္တျခား Methods ေတြကေတာ့...__del__
Instance တစ္ခုကုိဖ်က္မယ္ဆိုရင္သံုးပါတယ္။ Clean-up လုပ္တယ္ေပါ့ဗ်ာ ဥပမာ file close တာေနာက္ database conn ပိတ္တာမ်ိုးစသျဖင့္ေပါ့။
__repr__ , __str__
object ကို string အေနနဲ ့return ျပန္ေပးျကတာေတြပါပဲဒါေပသိ __repr__ ကအသံုးနဲပါတယ္ေနာက္ သူကို object က re-create ျပန္လုပ္မယ့္အခ်ိန္မ်ိုးေတဿြမွပဲသံုးသင့္ပါတယ္။
__str__ ကိုေတာ့ any type ကို return ျပန္နိုင္လို ့အသံုးမ်ားပါတယ္။
__call__
object ကိုေခါ္ရင္အသံုးျပုတာပါ။
__hash__
object ရဲ့ hash ကိုတြက္ရင္ေခါ္သံုးပါတယ္။ ေျပာရရင္dictionaries တို ့လို data structers ထဲမွာ objects ကိုထည့္တာမ်ိုးေပါ့။
__cmp__
သူကေတာ့ object အခ်င္းခ်င္း compare လုပ္တဲ့အခါမွသံုးပါတယ္ ဒါေပသိသူက ONLY PYTHON 2 ပါ။ Python 3 အတြက္က်ေတာ့ __cmp__ အစားတျခား comparison methods ေတြရွိပါတယ္။ အဲ့တာေတြကေတာ့..
__lt__
Less than ကိုေျပာတာပါ။
__le__
Less than or equal to...
__gt__
Greater than..__ge__
Greater than or equal to
__eq__
Equal to...
__ne__
Not Equal to
Python မွာ array like object ( example[2] = 'foo' ) ေနာက္ numeric type object ေတြကိုပါတဲ့ methods ေတြလုပ္လို ့ရပါတယ္
ျကံုတံုးေျပာအံုးမယ္ဗ် Google ေခါက္ျပီးရွာဖတ္ျကည့္အံုးဗ် Python Magic Methods အေျကာင္းေရးထားတာေလးေပါ့။ အဆင္ေျပေနာက္မွတင္ေပးအံုးမယ္သူကတျခားေတာ့မပ ာုတ္ဘူး Python Documention မွာကေဗ်ာက္ေသာက္ျဖစ္ေနတာေတြကိုစုစည္းျပီး Magic Methods ေတြပဲေဖာ္ျပေပးထားတာေလးပါ။ Python သမားေတြအေနနဲ ့ဖတ္သင့္တယ္ထင္လို ့ပါ။
ဒါနဲ ့ဒီမွာဖဲေဆာ့ဖူးတဲ့သူေတြရွိတယ္မလား Ace တို ့ King, Queen, Jack တို ့ကဘယ္နံပတ္လဲဆိုတာလဲသိတယ္မလား
class Card: # We use a keyword called 'class' to make a class
# Define the suits
DIAMONS = 1
CLUBS = 2
HEARTS = 3
SPADES = 4
SUITS = {
CLUBS: 'Clubs',
HEARTS: 'Hearts',
DIAMONDS: 'Diamonds',
SPADES: 'Spades'
} # Well Suit is a Dictionary
# Name of Special cards, I am sure you guys know them already.
VALUES = {
1: 'Ace',
11: 'Jack',
12: 'Queen',
13: 'King'
}
def __init__(self, suit, value):
# Save the suit and card value
self.suit = suit
self.value = value
def __cmp__(self, other):
# Compare the card with another card
# return <0 if smaller and >0 if greater
# 0 if the same
if self.suit < other.suit:
return -1
elif self.suit > other.suit:
return 1
elif self.value < other.value:
return -1
elif self.value > other.value:
return 1
else: #This mean the same
return 0
def __str__(self):
# return string representation of an object
if self.value in self.VALUES:
result = self.VALUES[self.value]
else: # it means self.value is not in self.VALUES
result = str(self.value)
result = result + ' of ' + self.SUITS[self.suit]
return result
ကြ်န္ေတာ္တို ့ကအရင္ဆံုး suit ထဲမွာေဖာ္ျပဖို ့အတြက္ class constant ေတြေရးပါတယ္ ေနာက္ Special cards ေတြအတြက္လဲ Dictionary တစ္ခုလုပ္ပါတယ္။__init__ ဆိုတာက parameter ၂ခုလက္ခံပါတယ္။ suit ဆိုတာနဲ ့value ဆိုတာပါ။ ေနာက္ __cmp__ ဆိုတဲ့ special method ကိုေခါ္ျပန္ပါတယ္။ သူကေတာ့ object ကို compare လုပ္ဖို ့အတြက္ေပါ့။ Less than ဆို -1, More than ကို 1 ေနာက္ တူေနရင္ 0 ေပါ့။ (ဒါက Python 2 မို ့__cmp__ သံုးတာေနာ္အကယ္လို ့Python 3 တာဆိုပ ာိုးအေပါ္မွာေျပာခဲ့တဲ့ comparison methods ေတြကိုအသံုးျပုရမွာပါ။ )
ေနာက္ဆံုးမွာေတာ့ __str__ ဆိုတဲ့ object ကို human readable အေနနဲ ့return ျပန္ဖို ့ေခါ္ပါတယ္။
ဒါဆိုေရးထားတဲ့ကုဒ္ေလးကိုေတာ့မိမိဘာသာစမ္းျကည့္ေစခ်င္ပါတယ္။ ကြ်န္ေတာ္ေတာ့၁ခုစမ္းျပေပးပါမယ္။
>>> card = Card(Card.DIAMONDS, 3)
>>> print card
3 of Diamonds
Private Python Class Methods and Variables
ပံုမွန္အားျဖင့္ေတာ့ methods နဲ ့variables ေတြက public ပါပဲဒါေပသိသူက encapsulation အတြက္ေတာ့မေကာင္းျပန္ဘူးဗ် ေျပာရရင္ constant အေနနဲ ့ထားဖို ့ေပါ့။ အဲ့ေတာ့ Python ကေနျပီးေတာ့ class method နဲ ့ variable ေတြမွာသာ underscore ၂ခုနဲ ့စရင္ (__) နဲ့စရင္ private လို ့သတ္မွတ္ေပးလိုက္ပါတယ္။ (Private ကေရွ ့မွာပဲ underscore ၂ခုပါတာေနာ္ ေနာက္က underscore မလိုဘူး ေတာ္ျကာ special methods ေတြနဲ ့ေရာမပစ္နဲ့အံုး example → __variable_name)ဒီလို Private method ကဘာေကာင္းလဲဆိုေတာ့ derived class ေတြက method နဲ ့variable ကိုနာမည္တူေပးလို ့ရသြားပါတယ္ ဒီေတာ့အရင္ေပးခဲ့တဲ့ေကာင္ကလဲဘာမွသက္ေရာက္မွုမရွိေတာ့ဘူးေပါ့။
Class Inheritance
Python မွာ Class Inheritance အတြက္ support လုပ္ပါတယ္။ ကြ်န္ေတာ္တို ့အေပါ္မွာ Foo ဆိုျပီးေရးခဲ့တယ္ေနာ္။
class Foo:
def __init__(self, val):
self.val = val
def valuePrint(self):
print self.val
ဒါကိုပဲ ေနာက္ Class တစ္ခုကေနျပီးေတာ့ inherit လုပ္ပါမယ္။ class DerivedFoo(Foo):
def doubleVal(self):
self.val = self.val * 2
DerivedFoo ဆိုတဲ့ clas တစ္ခုလုပ္ပါတယ္။ သူထဲကို Foo ဆိုတဲ့ Class ကို argument အေနနဲ ့ထည့္ထားပါတယ္ ဒီလိုလုပ္လိုက္ခ်င္းက Foo Class မွာရွိတဲ့ Variable နဲ့ Function ကလဲအခု Derived Class ျဖစ္တဲ့ DerivedFoo ထဲမွာလဲရွိသြားေစပါတယ္။ ေနာက္ Foo ရဲ့ function ေတြတင္မကပဲ သူကိုယ္ပိုင္ doubleValue ဆိုတဲ့ function အသစ္တစ္ခုထပ္ေရးပါတယ္။ >>> example = DerivedFoo(2)
>>> example.valuePrint()
2
>>> example.doubleValue()
>>> example.valuePrint()
Inheritance မွာက function အသစ္ထည့္ေရးတာမ်ိုးေတြတင္မကရွိျပီးသား ancestor က function ကိုပါ override ျပုလုပ္နိုင္ပါတယ္။ class NewDerivedFoo(Foo):
def valuePrint(self):
print “The value is %s.” % self.val
Foo ဆိုတဲ့ class ထဲမွာ valuePrint ဆိုတာကရွိျပီးသားပါအခုလို inheritance ထဲမွာျပန္ေရးလိုက္ခ်င္းအားျဖင့္နကို Foo က valuePrint ဆိုတာကို override ျဖစ္သြားပါတယ္။ >>> example = NewDerivedFoo(2)
>>> example.valuePrint()
The value is 2.
Class ကဘာ object လဲဆိုတာကိုသိဖို ့အတြက္ Python မွာ function တခ်ို ့ရွိပါတယ္။isinstance ကေတာ့ object က class ဒါမွမပ ာုတ္ derived class ရဲ့ instance ပ ာုတ္မပ ာုတ္ကိုသိခ်င္သံုးတာပါ။
issubclass ကေတာ့ တျခား Class ကေန derived လုပ္ထားတဲ့ class ပ ာုတ္မပ ာုတ္သိခ်င္သံုးတာပါ။
>>> print isinstance(example, Foo)
True
>>> print isinstance(example, DerivedFoo)
True
>>> print isinstance(example, NewDerivedFoo)
False
>>> print issubclass(DerivedFoo, Foo)
True
>>> class HelloWorld:
… pass
…
>>> print issubclass(HelloWorld, Foo)
False
Class Iterators and Generators
ကြ်န္ေတာ္တို့ Let's Write Python မွာထဲက for နဲ ့ Looping ပတ္ျပတာေတြကိုျမင္ျပီးသားျဖစ္မွာပါ။ for နဲ ့built-in types ေတြကိုပါ looping ပတ္လို ့ရပါတယ္။ >>> a = 'Hello World'
>>> for x in a:
... print x
…
H
e
l
l
o
W
o
r
l
d
ကြ်န္ေတာ္တို ့Class တစ္ခုေရးရင္လဲအခုလို Iterable လုပ္နိုင္ပါတယ္။ ဒီအတြက္ Special method ျဖစ္တဲ့ __iter__ ဆိုတာရွိပါတယ္။ ေနာက္ next ဆိုတဲ့ method နဲ ့ေနာက္လာမယ့္ value ကို return ျပန္နိုင္ပါတယ္။ (Python 3 မွာေတာ့ next အစား __next__ ကိုအသံုးျပုပါတယ္။)ခုနက Hello World ဆုိတဲ့စာကုိ backward ျပန္ျပတဲ့ class ေလးေရးျကည့္ရေအာင္ဗ်ာ။
>>> class Backwards:
... def __init__(self, val):
... self.val = val
... self.pos = len(val) #get the length of argument
...
... def __iter__(self):
return self
...
... def next(self):
... if self.pos <= 0:
... raise Iteration End
... self.pos -= 1
... return self.val[self.pos]
…
>>> for x in Backwards('Hello'):
… print x
o
l
l
e
H
__init__ ကဘာလဲေတာ့မေမးနဲ ့ေနာ္။ ကြ်န္ေတာ္အစမွာထဲကရွင္းခဲ့ျပီးပါျပီ။ ဒီ Class မွာအလုပ္၂ခုလုပ္သြားပါတယ္။ တစ္ခုက iteration ပါေနာက္တစ္ခုက iterate လုပ္တိုင္းေနာက္ value တစ္ခုကို return ျပန္သြားတာပါ။ __iter__ ဆိုတဲ့ေကာင္ကေတာ့ return self ဆိုျပီး iterate လုပ္သြားပါတယ္။ Python က object ကို looping ပတ္ေနခ်ိန္မွာေနာက္ value တစ္ခုကိုသူ ့ဘာသာေခါ္သြားပါတယ္။ ဘယ္အထိလဲဆုိ self.pos က <= 0 ျဖစ္သြားတဲ့အထိေပါ့။ဒါေပသိအခုလုိအလုပ္လုပ္သြားတဲ့ေကာင္ကို generators ဆိုတာအသံုးျပုသြားရင္သူ ့လို function မ်ိုးကိုစာေျကာင္းနဲနဲနဲ ့ပိုရွင္းေအာင္ေရးလုိ ့ရပါေသးတယ္။
generator ဆိုတာကေတာ့ special function တစ္ခုပါပဲသူက object ကို iterate လုပ္ျပီး loop position ကုိလဲ auto သိေစပါတယ္။ ေအာက္ကေကာင္ေလးကိုျကည့္လိုက္ရင္ backwardလုပ္တဲ့ function ကို generator အသံုးျပုလိုက္ရင္ပိုေတာင္ေရးရနည္းပါေသးတယ္။
>>> def backwards(val):
... for n in range(len(val), 0, -1):
... yield val[n-1]
စမ္းတာေတာ့ကိုယ့္ဘာသာကိုစမ္းတတ္တယ္မလား မလုပ္ျပေတာ့ဘူးေနာ္။range အေျကာင္းကိုေတာ့သိျပီးသားျဖစ္မယ္ထင္ပါတယ္။ range(start, stop[, step])
ဒီ generator မွာသတိထားဖို ့က yield ဆိုတဲ့ keyword နဲ ့value ကိုျပန္တာပါ။ သူက loop ကိုခဏရပ္လိုက္တယ္ေနာက္ caller ထဲကို next value ကို return ျပန္တယ္ျပီးမွ looping ကဆက္လုပ္သြားတယ္။
Classes as Objects
Class ဆိုတာကဘာလိုဆိုတာကိုဘယ္လို methods ေတြ variable ေတြဆုိင္ရာေတြကိုစုစည္းထားတယ္ဆိုတာကိုလဲအစမွာထဲကေျပာခဲ့ျပီးပါျပီ ေနာက္ Python မွာ Class ရဲ့ definition ကို run ခ်ိန္မွာ modify လုပ္နိုင္သလိုေနာက္ဆံုး run-time မွာတင္ class အသစ္တစ္ခုတည္ေဆာက္နိုင္ပါတယ္။ >>> class Foo:
... def __init__(self, val):
... self.val = val
…
>>> example = Foo(1)
>>> example.valuePrint()
AttributeError: Foo instance has no attribute 'valuePrint'
Foo ဆိုတဲ့ class ထဲမွာ valuePrint ဆိုတာမွမရွိတာ၊ မရွိတာကိုသြားေခါ္ေတာ့ Error တက္တာေပါ့။ ဒီေတာ့ေအာက္ကလို Class ထဲကို function ထည့္လိုက္လို ့ရပါတယ္။ >>> def valuePrint(self):
… print self.val
…
>>> Foo.valuePrint = valuePrint
>>> example.valuePrint()
1
အရင္ဆံုးကြ်န္ေတာ္တို ့က valuePrint ဆိုတဲ့ function ကိုေရးလိုက္ပါတယ္ေနာက္ျပီးေတာ့မွ Class ထဲကိုထည့္လိုက္ပါတယ္။ (Foo.valuePrint = valuePrint) ဒီေတာ့ valuePrint ဆိုတဲ့ function ကလဲ Foo ဆိုတဲ့ Class ေအာက္ကိုေရာက္သြားပါတယ္။အကယ္လို့ Class ထဲက function ကိုျပန္ဖ်က္ခ်င္ရင္ del ဆိုတဲ့ statement ကိုအသံုးျပုနိုင္ပါတယ္။
>>> del Foo.valuePrint
>>> example.valuePrint
AttributeError:.....
del နဲ ့ဖ်က္လိုက္ေတာ့ Foo ဆိုတဲ့ class ေအာက္မွာ valuePrint ဆိုတာမရွိေတာ့ပါဘူး မရွိတာကိုသြားေခါ္ေတာ့ error တက္တာေပါ့....အကယ္လို ့run-time မွာသာ Class တစ္ခုေဆာက္ခ်င္ရင္ type ဆိုတာကိုသံုနိုင္ပါတယ္။
>>> example = NewClass()
NameError: name 'NewClass' is not defined
>>> NewClass = type('NewClass', (object,), dict())
>>> example = NewClass()
>>> print example
<__main__.NewClass object at 0x7f57ea52d850>
type ရဲ့ ဒုတိယ parameter ေကာင္ကေတာ့ derive လုပ္ခ်င္တဲ့ classes ေတြအတြက္ပါေနာက္ တတိယ parameter ကေတာ့ Class ထဲမွာပါမယ့္ methods နဲ ့variables ေတြအတြက္ပါ။Class အေျကာင္းကေတာ့ဒီေလာက္ပါပဲ ဖတ္ရတာလဲေတာ္ေတာ္ပ်င္းေလာက္ျပီထင္ပါတယ္။
PyLab (c) 2016

0 comments:
Post a Comment