No.8 Python面向物件程式設計
面向物件三大關鍵:封裝、繼承、多型。我們從這三個方面介紹Python的面向物件程式設計,同時會提到Python中類的魔術方法:
1. 封裝成類:
在Python中,我們使用以下方式進行類的宣告:
class Person (object): def __init__(self, name, gender): self.name = name self.gender = gender def sayHello(self): print 'Hi~ I am %s' % (self.name) p = Person('xiaoming', 'male') p.sayHello()
這裡需要講解的是以下幾點:
1. __init__(self,...):類似於python的建構函式,不過同時python的成員變數也需要生命在__init__(self,...)中。類內部的所有成員函式均需要一個預設的self引數,並且需要放在第一位,作用類似於我們在java中的this一樣
2. 在python中,公有,私有通過下劃線來表示 。__xx或者__func(self):表示該變數或者函式是私有的,在外部無法獲取。公有的屬性(成員變數或者函式)使用xxx 或者__xxx__來表示。我們一般直接使用變數名來表示公有的成員變數,使用__xx__來表示特殊的公有屬性
3. 由於python是一個動態的語言,所以我們可以給例項化的物件繫結新的變數。這僅對於我們自己宣告的類物件,內建的類是不可以的
我們可以使用dir(p)來檢視p物件的屬性:
python使用@classmethod 和 直接在類中建立屬性來獲得類方法和類變數(類似於java中的static方法和變數)
在java中,我們會宣告屬性,設定get和set方法,在python中同樣有類似的用法:class Person(object): count = 0 @classmethod def objNum(cls): return cls.count def __init__(self, name, gender): self.name = name self.gender = gender Person.count = Person.count + 1 def sayHello(self): print 'Hi~ I am %s' % (self.name) print Person.count # 列印 0 p = Person('xiaoming', 'male') # 執行一次__init__(self)函式, count= 1 print p.count # 列印1 print Person.objNum() #列印1
# _*_ coding = utf-8 _*_
class Person(object):
count = 0
@classmethod
def objNum(cls):
return cls.count
def __init__(self, name, gender):
self.name = name
self.__gender = gender
Person.count = Person.count + 1
@property
def gender(self):
return self.__gender
@gender.setter
def gender(self, gender):
if gender == 'male' or gender == 'female':
self.__gender = gender
else:
raise ValueError("Wrong Gender")
def sayHello(self):
print 'Hi~ I am %s' % (self.name)
p = Person('xiaoming','male')
p.gender = 'xmale'
執行程式,會丟擲ValueError、
二、繼承:
在Person類下面,我們宣告一個Boy類,來繼承Person
# _*_ coding = utf-8 _*_
class Person(object):
count = 0
@classmethod
def objNum(cls):
return cls.count
def __init__(self, name, gender):
self.name = name
self.gender = gender
Person.count = Person.count + 1
def sayHello(self):
print 'Hi~ I am %s' % (self.name)
class Boy(Person):
def __init__(self,name,gender,hobby):
super(Boy, self).__init__(name, gender)
self.hobby = hobby
b = Boy('xiaoming','male','coding')
print b.name,b.gender,b.hobby
同時,python也可以很好的實現多根繼承:
# _*_ coding = utf-8 _*_
class Person(object):
count = 0
@classmethod
def objNum(cls):
return cls.count
def __init__(self, name, gender):
self.name = name
self.gender = gender
Person.count = Person.count + 1
def sayHello(self):
print 'Hi~ I am %s' % (self.name)
class Player(object):
def __init__(self,game):
self.game = game
def playgame(self):
print 'Play game %s' % (self.game)
class Boy(Person,Player):
def __init__(self,name,gender,game,hobby):
Person.__init__(self,name, gender)
Player.__init__(self,game)
self.hobby = hobby
b = Boy('xiaoming','male','LOL','coding')
print b.name,b.gender,b.game,b.hobby
這裡跟單根整合不同的地方是,我們在子類的__init__(self,...)函式中,採用了不同的方法呼叫父類__init__(),總結一下,有以下兩種方法:
1. super(Derived,self).__init__(arg1,arg2)
2. Base.__init__(self,args1..)
第一種方法僅適用於單根,第二種單根多根均可以,推薦使用第二種
三、多型:
python的多型沒有什麼特殊性,也很簡單。給上述Person 和Boy新增sayHello函式
# _*_ coding = utf-8 _*_
class Person(object):
count = 0
@classmethod
def objNum(cls):
return cls.count
def __init__(self, name, gender):
self.name = name
self.gender = gender
Person.count = Person.count + 1
def sayHello(self):
print 'Hi~ I am Person %s' % (self.name)
class Player(object):
def __init__(self,game):
self.game = game
def playgame(self):
print 'Play game %s' % (self.game)
class Boy(Person,Player):
def __init__(self,name,gender,game,hobby):
Person.__init__(self,name, gender)
Player.__init__(self,game)
self.hobby = hobby
def sayHello(self):
print 'Hi~ I am Boy %s' % (self.name)
def sayHello(x):
x.sayHello()
b = Boy('xiaoming','male','LOL','coding')
p = Person('xiaoming','male')
sayHello(b)
sayHello(p)
4. 魔術方法:
python的class中有很多魔術方法,這些魔術方法是我們不需要直接呼叫但是python的某些函式或者操作會呼叫的特殊方法。這類方法均為用雙下劃線包圍的函式,例如__str__。在我們對一個物件使用print 函式的時候,就會呼叫到物件的__str__()函式。如果我們對類中的一些魔術方法進行覆寫,就會得到我們想要的結果
例如,我們給Person新增一個__str__()方法:
# _*_ coding = utf-8 _*_
class Person(object):
count = 0
@classmethod
def objNum(cls):
return cls.count
def __init__(self, name, gender):
self.name = name
self.gender = gender
Person.count = Person.count + 1
def __str__(self):
return "I'm Person %s" % (self.name)
def sayHello(self):
print 'Hi~ I am Person %s' % (self.name)
p = Person('xiaoming','male')
print p
就會列印我們的想要的 I'm Person xiaoming在前面我們講到了,可以給具體的例項物件繫結屬性。如果我們不希望一個例項可以隨意的新增屬性呢?
我們可以使用__slots__,這會宣告類允許的屬性列表:
# _*_ coding = utf-8 _*_
class Person(object):
count = 0
__slots__ = ('name','gender')
@classmethod
def objNum(cls):
return cls.count
def __init__(self, name, gender):
self.name = name
self.gender = gender
Person.count = Person.count + 1
def __str__(self):
return "I'm Person %s" % (self.name)
def sayHello(self):
print 'Hi~ I am Person %s' % (self.name)
p = Person('xiaoming','male')
p.score = 123
print p
就會報錯,提示該物件沒有屬性score。
python中還有很多我們常用到的魔術方法,比如表示比較的__cmp__,表示長度的__len__,和將物件變為可呼叫物件,使得物件可以直接變成函式來返回結果的__call__等,這裡不再贅述