面向?qū)ο缶幊?/h3>
類和實例
來自:
廖雪峰python
面向?qū)ο笞钪匾母拍罹褪穷悾–lass)和實例(Instance),必須牢記類是抽象的模板铺遂,比如Student類驹愚,而實例是根據(jù)類創(chuàng)建出來的一個個具體的“對象”心铃,每個對象都擁有相同的方法捣郊,但各自的數(shù)據(jù)可能不同训裆。
由于類可以起到模板的作用抱慌,因此霜威,可以在創(chuàng)建實例的時候酪刀,把一些我們認(rèn)為必須綁定的屬性強(qiáng)制填寫進(jìn)去粹舵。通過定義一個特殊的__init__
方法,在創(chuàng)建實例的時候蓖宦,就把name
齐婴,score
等屬性綁上去:
class Student(object):
def __init__(self, name, score):
self.name = name #python不用提前聲明類中的對象
self.score = score
def print_score(self):
print('%s: %s' % (self.name, self.score))
注意:特殊方法“init”前后分別有兩個下劃線!3砻柠偶!
注意到__init__
方法的第一個參數(shù)永遠(yuǎn)是self
情妖,表示創(chuàng)建的實例本身,因此诱担,在__init__
方法內(nèi)部毡证,就可以把各種屬性綁定到self
,因為self
就指向創(chuàng)建的實例本身蔫仙。
有了__init__
方法料睛,在創(chuàng)建實例的時候,就不能傳入空的參數(shù)了摇邦,必須傳入與__init__
方法匹配的參數(shù)恤煞,但self
不需要傳,Python解釋器自己會把實例變量傳進(jìn)去:
>>> bart = Student('Bart Simpson', 59) #python新建施籍,不用new
>>> bart.name
'Bart Simpson'
>>> bart.score
59
和普通的函數(shù)相比居扒,在類中定義的函數(shù)只有一點不同丑慎,就是第一個參數(shù)永遠(yuǎn)是實例變量self
喜喂,并且,調(diào)用時竿裂,不用傳遞該參數(shù)玉吁。除此之外,類的方法和普通函數(shù)沒有什么區(qū)別腻异,所以进副,你仍然可以用默認(rèn)參數(shù)、可變參數(shù)捂掰、關(guān)鍵字參數(shù)和命名關(guān)鍵字參數(shù)敢会。
訪問限制
如果要讓內(nèi)部屬性不被外部訪問曾沈,可以把屬性的名稱前加上兩個下劃線__
这嚣,在Python中,實例的變量名如果以__
開頭塞俱,就變成了一個私有變量(private)姐帚,只有內(nèi)部可以訪問,外部不能訪問障涯,所以罐旗,我們把Student類改一改:
class Student(object):
def __init__(self, name, score):
self.__name = name#python不用提前聲明變量
self.__score = score
def print_score(self):
print('%s: %s' % (self.__name, self.__score))
需要注意的是,在Python中唯蝶,變量名類似__xxx__
的九秀,也就是以雙下劃線開頭,并且以雙下劃線結(jié)尾的粘我,是特殊變量鼓蜒,特殊變量是可以直接訪問的痹换,不是private變量,所以都弹,不能用__name__
娇豫、__score__
這樣的變量名。
有些時候畅厢,你會看到以一個下劃線開頭的實例變量名冯痢,比如_name
,這樣的實例變量外部是可以訪問的框杜,但是浦楣,按照約定俗成的規(guī)定,當(dāng)你看到這樣的變量時咪辱,意思就是椒振,“雖然我可以被訪問,但是梧乘,請把我視為私有變量澎迎,不要隨意訪問”。
雙下劃線開的實例變量是不是一定不能從外部訪問呢选调?其實也不是夹供。不能直接訪問__name
是因為Python解釋器對外把__name
變量改成了_Student__name
,所以仁堪,仍然可以通過_Student__name
來訪問__name
變量:
>>> bart._Student__name
'Bart Simpson'
但是強(qiáng)烈建議你不要這么干哮洽,因為不同版本的Python解釋器可能會把__name
改成不同的變量名。
總的來說就是弦聂,Python本身沒有任何機(jī)制阻止你干壞事鸟辅,一切全靠自覺。
summary:遇到對應(yīng)的私有變量莺葫,還是用get set方法吧
python之繼承
#注意python中的繼承是如何寫的
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def run(self):
print('Dog is running...')
class Cat(Animal):
def run(self):
print('Cat is running...')
當(dāng)子類和父類都存在相同的run()
方法時匪凉,我們說,子類的run()
覆蓋了父類的run()
捺檬,在代碼運行的時候再层,總是會調(diào)用子類的run()
。這樣堡纬,我們就獲得了繼承的另一個好處:多態(tài)聂受。
在繼承關(guān)系中,如果一個實例的數(shù)據(jù)類型是某個子類烤镐,那它的數(shù)據(jù)類型也可以被看做是父類蛋济。但是,反過來就不行
如何獲取對象信息
1.type-得到對象的類型
基本類型都可以用type()
判斷:
>>> type(123)
<class 'int'>
>>> type('str')
<class 'str'>
>>> type(None)
<type(None) 'NoneType'>
如果一個變量指向函數(shù)或者類炮叶,也可以用type()
判斷:
>>> type(abs)
<class 'builtin_function_or_method'>
>>> type(a)
<class '__main__.Animal'>
但是type()
函數(shù)返回的是什么類型呢碗旅?它返回對應(yīng)的Class類型鹊杖。如果我們要在if
語句中判斷,就需要比較兩個變量的type類型是否相同:
>>> type(123)==type(456)
True
>>> type(123)==int
True
>>> type('abc')==type('123')
True
>>> type('abc')==str
True
>>> type('abc')==type(123)
False
判斷基本數(shù)據(jù)類型可以直接寫int
扛芽,str
等骂蓖,但如果要判斷一個對象是否是函數(shù)怎么辦?可以使用types
模塊中定義的常量:
>>> import types
>>> def fn():
... pass
...
>>> type(fn)==types.FunctionType
True
>>> type(abs)==types.BuiltinFunctionType
True
>>> type(lambda x: x)==types.LambdaType
True
>>> type((x for x in range(10)))==types.GeneratorType
True
2.instance
那么川尖,isinstance()
就可以告訴我們登下,一個對象是否是某種類型。先創(chuàng)建3種類型的對象:
>>> a = Animal()
>>> d = Dog()
>>> h = Husky()
然后叮喳,判斷:
>>> isinstance(h, Husky)
True
沒有問題被芳,因為h
變量指向的就是Husky對象。
再判斷:
>>> isinstance(h, Dog)
True
h
雖然自身是Husky類型馍悟,但由于Husky是從Dog繼承下來的畔濒,所以,h
也還是Dog類型锣咒。換句話說侵状,isinstance()
判斷的是一個對象是否是該類型本身,或者位于該類型的父繼承鏈上毅整。
能用type()
判斷的基本類型也可以用isinstance()
判斷:
>>> isinstance('a', str)
True
>>> isinstance(123, int)
True
>>> isinstance(b'a', bytes)
True
并且還可以判斷一個變量是否是某些類型中的一種趣兄,比如下面的代碼就可以判斷是否是list或者tuple:
>>> isinstance([1, 2, 3], (list, tuple))
True
>>> isinstance((1, 2, 3), (list, tuple))
True
總是優(yōu)先使用isinstance()判斷類型,可以將指定類型及其子類“一網(wǎng)打盡”悼嫉。
3.dir-獲取一個對象內(nèi)的信息
如果要獲得一個對象的所有屬性和方法艇潭,可以使用dir()
函數(shù),它返回一個包含字符串的list戏蔑,比如蹋凝,獲得一個str對象的所有屬性和方法:
>>> dir('ABC')
['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']
類似__xxx__
的屬性和方法在Python中都是有特殊用途的,比如__len__
方法返回長度总棵。在Python中鳍寂,如果你調(diào)用len()
函數(shù)試圖獲取一個對象的長度,實際上彻舰,在len()
函數(shù)內(nèi)部伐割,它自動去調(diào)用該對象的__len__()
方法,所以刃唤,下面的代碼是等價的:
>>> len('ABC')
3
>>> 'ABC'.__len__()
3
可以通過函數(shù)直接操縱對象
實例屬性&類屬性
給實例綁定屬性的方法是通過實例變量,或者通過self
變量:
class Student(object):
def __init__(self, name):
self.name = name
s = Student('Bob')
s.score = 90
但是白群,如果Student
類本身需要綁定一個屬性呢尚胞?可以直接在class中定義屬性,這種屬性是類屬性帜慢,歸Student
類所有:
class Student(object):
name = 'Student' #所以在python中笼裳,提前聲明的非self的變量是類變量
**在編寫程序的時候唯卖,千萬不要對實例屬性和類屬性使用相同的名字,因為相同名稱的實例屬性將屏蔽掉類屬性躬柬,但是當(dāng)你刪除實例屬性后拜轨,再使用相同的名稱,訪問到的將是類屬性允青。 **