> 在面向對象的語言中,類是最重要的一環,python自然擁有類這個機制。python的類機制,與C++,java的區別不是很大,類的大多數的重要特性都被沿用了,一樣可以多態,抽象,封裝;
### python3作用域:
在介紹類之前,首先介紹下一下關于python作用域的規則;
1.命名空間:
是從命名到對象的映射。當前命名空間主要是通過 Python 字典實現的,不過通常不關心具體的實現方式(除非出于性能考慮);
以下有一些命名空間的例子:
內置命名(像 abs() 這樣的函數,以及內置異常名)集,模塊中的全局命名,函數調用中的局部命名。某種意義上講對象的屬性集也是一個命名空間。
關于命名空間需要了解的一件很重要的事就是不同命名空間中的命名沒有任何聯系,例如兩個不同的模塊可能都會定義一個名為 maximize 的函數而不會發生混淆–用戶必須以模塊名為前綴來引用它們。比如:math中有sin函數,可以通過math.sin調用;
2.作用域:
就是一個 Python 程序可以直接訪問命名空間的正文區域。 這里的 直接訪問 意思是一個對名稱的錯誤引用會嘗試在命名空間內查找。
一個例子:
~~~
def scope_test():
def do_local():
spam = "local spam"#局部變量
def do_nonlocal():
nonlocal spam
spam = "nonlocal spam"#域變量,在整個函數域有效。
def do_global():
global spam
spam = "global spam"#
spam = "test spam"#全局變量,此處在函數域外有效;
do_local()
print("After local assignment:", spam)
do_nonlocal()
print("After nonlocal assignment:", spam)
do_global()
print("After global assignment:", spam)
scope_test()
print("In global scope:", spam)#全局變量作用域
##輸出:
After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam
~~~
### 類定義語法
類定義形式:
~~~
class className(superClass):
<statement 1>
.....
<statement N>
~~~
類定義就像函數定義一樣,要先執行才能生效。習慣上statement語句是函數定義,不過其他語句也可以。
進入類定義部分后會創建出一個新的命名空間,作為局部作用域,因此所有的賦值成為這個新命名空間的局部變量,特別時函數定義在此處綁定了新的名字
類定義完成時,就創建了一個類對象。也就是類名;
### 類對像:
類對象支持兩種操作:屬性應用和實例化.
屬性應用使用:類名.屬性;例如類定義如下:
~~~
class Myclass:
"一個簡單的類用于屬性介紹"
num=123
def fun(self):
return 'hello world'
~~~
那么我可以Myclass.num和Myclass.fun是有效的屬性引用;分別返回一個整數,和一個方法對象;
類定義的實例化:類的實例話使用函數符號 :類名();
例如:x=Myclass()
以上創建了一個新的類的實例,并將該對象賦值給了變量x。此去沒有初始化;
很多類都傾向于將對象創建為有初始狀態的。因此類可能會定義一個名為 **init**() 的特殊方法,像下面這樣:
~~~
def __init__(self):
self.data = []
~~~
類定義了 **init**() 方法的話,類的實例化操作會自動為新創建的類實例調用**init**() 方法。所以在下例中,可以這樣創建一個新的實例:
x = MyClass()
當 然 , 出 于 彈 性 的 需 要 , **init**() 方 法 可 以 有 參 數 。 事 實 上 , 參 數 通 過**init**() 傳遞到類的實例化操作上。
### 實例對象:
實例對象就是用來操作類的屬性引用;有兩種引用:數據和方法
數據:和java中的成員類似,其實就是變量;和局部變量一樣,數據屬性不需要聲明,第一次使用他們時就會生成;
比如:
~~~
x=Myclass()
#Myclass類中沒有聲明,可以直接使用;
x.counter=1
~~~
方法:方法是屬于一個類的函數,方法引用為:x.fun();
也可以將方法引用賦值給變量這與函數賦值是一樣的;
xf=x.fun()#注意self參數,是對象實例化作為第一個參數傳給變量的,不需要顯示調用;
### 實例屬性和類屬性
1實例屬性介紹:
給實例綁定屬性的方法是通過實例變量,或者通過self變量:
~~~
class Student(object):
def __init__(self, name):
self.name = name
s = Student('peace')
s.score =40
~~~
name和score都是實例屬性;
2類屬性:
可以直接在class中定義屬性,這種屬性是類屬性,歸類所有:
~~~
class student:
name="peace"
~~~
name就是類屬性,類的所有實例都可以訪問到,并且是指向同一個對象;
### 繼承:
沒有繼承就沒有類,而python類的定義如下:
~~~
class className(superClass):
<statement 1>
.....
<statement N>
##其中className就是superclass的派生類。
~~~
實例介紹:
~~~
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
pass
class Cat(Animal):
pass
~~~
1.
對于dog與cat來說,Animal就是它的父類。
1.
如果在子類中找不到請求調用的屬性,就搜索基類。如果基類是由別的類派生而來,這個規則會遞歸的應用上去。現在Dog和Cat方法都可以調用run方法了。
1.
也可以增加方法:
~~~
class Dog(Animal):
def see(self):
print('see a dog')
~~~
1. 多態(覆蓋):
派生類可以覆蓋其基類的方法。因為方法調用同一個對象中的其它方法時沒有特權,基類的方法調用同一個基類的方法時,可能實際上最終調用了派生類中的覆蓋方
法。
~~~
class Dog(Animal):
def run(self):
print('Dog is running...')
class Cat(Animal):
def run(self):
print('Cat is running...')
~~~
多態的好處:
~~~
def run_twice(animal):
animal.run()
animal.run()
##測試多態:
>>> run_twice(Animal())
Animal is running...
Animal is running...
>>> run_twice(Dog())
Dog is running...
Dog is running...
~~~
對于一個變量,我們只需要知道它是Animal類型,無需確切地知道它的子類型,就可以放心地調用run()方法,而具體調用的run()方法是作用在Animal、Dog、Cat還是Tortoise對象上,由運行時該對象的確切類型決定,這就是多態真正的威力:調用方只管調用,不管細節,而當我們新增一種Animal的子類時,只要確保run()方法編寫正確,不用管原來的代碼是如何調用的。這就是著名的“開閉”原則:
對擴展開放:允許新增Animal子類;
對修改封閉:不需要修改依賴Animal類型的run_twice()等函數。
5.派生類的的實例化與普通類沒有什么差別;
Python 有兩個用于繼承的函數:
~~~
? 函數 isinstance() 用于檢查實例類型: isinstance(obj, int) 只有在obj.__class__ 是 int 或其它從 int 繼承的類型
? 函數 issubclass() 用于檢查類繼承: issubclass(bool, int) 為 True,因為 bool 是 int 的子類。但是, issubclass(unicode, str) 是 False因為 unicode 不是 str 的子類(它們只是共享一個通用祖先類 basestring)。
~~~
### 多重繼承:
python支持多重繼承:
~~~
class className(superClass1,superClass1,superClass2.....):
<statement 1>
.....
<statement N>
##其中className就是superClass1,superClass1,superClass2.....的派生類。
~~~
### 私有變量:
只需要在數據或者方法前面加上__兩個下劃線就行,例如__spam。python獨特的命名編碼會將__spam替代為 _classname__spam
這樣在外面就不能正常的 按照:類名.__spam進行調用了。但是寫全的話替代為 類名. _classname__spam還是可以的,這時python的缺陷
~~~
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def print_score(self):
print('%s: %s' % (self.__name, self.__score))
~~~
對于外部代碼來說,是無法從外部訪問實例變量.__name和實例變量.__score了
### 異常也是類:
可以自己定義異常的派生類,通過rasie進行拋出;
有兩種拋出方式:
1.raise Classname()定義的派生類;
2.raise 實例;由異常類實例話而來;
演示如下:
~~~
class B(Exception):
pass
class C(B):
pass
class D(C):
pass
for cls in [B, C, D]:
try:
raise cls()
except D:
print("D")
except C:
print("C")
except B:
print("B")
~~~
要 注 意 的 是 如 果 異 常 子 句 的 順 序 顛 倒 過 來 ( execpt B 在 最 前 ) , 它 就 會 打 印B,B,B–第一個匹配的異常被觸發。
#### 相關鏈接:
[python3入門之類](http://rlovep.com/2015/09/23/python3%E5%85%A5%E9%97%A8%E4%B9%8B%E7%B1%BB/)
[python3入門之函數](http://rlovep.com/2015/09/06/python3%E5%85%A5%E9%97%A8%E4%B9%8B%E5%87%BD%E6%95%B0/)
[python3入門之循環](http://rlovep.com/2015/09/06/python3%E5%85%A5%E9%97%A8%E4%B9%8B%E5%BE%AA%E7%8E%AF/)
[python3之if語句](http://rlovep.com/2015/08/05/python3%E4%B9%8Bif%E8%AF%AD%E5%8F%A5/)
[python3入門之賦值語句介紹](http://rlovep.com/2015/08/03/python3%E5%85%A5%E9%97%A8%E4%B9%8B%E8%B5%8B%E5%80%BC%E8%AF%AD%E5%8F%A5%E4%BB%8B%E7%BB%8D/)
[python3入門之print,import,input介紹](http://rlovep.com/2015/08/03/python3%E5%85%A5%E9%97%A8%E4%B9%8Bprint%EF%BC%8Cimport%EF%BC%8Cinput%E4%BB%8B%E7%BB%8D/)
[python3入門之set](http://www.cnblogs.com/onepeace/p/4791578.html)
[python3入門之字典](http://rlovep.com/2015/07/29/python3%E5%85%A5%E9%97%A8%E4%B9%8B%E5%AD%97%E5%85%B8/)
[python3入門之字符串](http://rlovep.com/2015/07/28/python%E5%85%A5%E9%97%A8%E4%B9%8B%E5%AD%97%E7%AC%A6%E4%B8%B2/)
[python3入門之列表和元組](http://rlovep.com/2015/07/14/python%E5%85%A5%E9%97%A8%E4%B9%8B%E5%88%97%E8%A1%A8%E5%92%8C%E5%85%83%E7%BB%84/)
[python3入門之軟件安裝](http://rlovep.com/2015/07/14/python%E5%85%A5%E9%97%A8%E4%B9%8B%E8%BD%AF%E4%BB%B6%E5%AE%89%E8%A3%85/)
[python3爬蟲之入門和正則表達式](http://rlovep.com/2015/09/23/python3%E7%88%AC%E8%99%AB%E4%B9%8B%E5%85%A5%E9%97%A8%E5%92%8C%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/)