一、創建類
class Student:
name = "jack"#屬性
age = 18 #公有屬性
__private_sttrs = ""#兩個下劃線開頭,聲明該屬性為私有
def __init__(self,age):#__init__是構造方法
self.age = age
print ("init")
def __private_method(self):#兩個下劃線開頭,聲明該方法為私有方法,不能在類地外部調用。在類的內部調用
print "private method"
def setName(self,name):#方法
self.name = name
print("setName")
stu = Student(20)#創建實例對象
stu.setName("jim")#調用方法
print stu.name
print stu.age
self 代表類的實例,self 在定義類的方法時是必須有的,雖然在調用時不必傳入相應的參數。
self 不是 python 關鍵字,只是習慣用這個命名表示類的實例,我們把他換成 runoob 也是可以正常執行
class Test:
def prt(self):
print(self)
print(self.__class__)
t = Test()
t.prt()
二、添加,刪除,修改類的屬性
stu.gender = "male" #類中沒有gender屬性,直接添加屬性
stu.gender = "female"#修改屬性
del stu.gender #刪除屬性
三、訪問屬性的函數方法
你也可以使用以下函數的方式來訪問屬性:
getattr(obj, name[, default]) : 訪問對象的屬性。
hasattr(obj,name) : 檢查是否存在一個屬性。
setattr(obj,name,value) : 設置一個屬性。如果屬性不存在,會創建一個新屬性。
delattr(obj, name) : 刪除屬性。
hasattr(stu, "age") # 如果存在 'age' 屬性返回 True。
getattr(stu, "age") # 返回 'age' 屬性的值
setattr(stu, "age", 8) # 添加屬性 'age' 值為 8
delattr(stu, "age") # 刪除屬性 'age'
四、Python內置類屬性
dict : 類的屬性(包含一個字典,由類的數據屬性組成)
doc :類的文檔字符串
name: 類名
module: 類定義所在的模塊(類的全名是'main.className',如果類位于一個導入模塊mymod中,那么 className.module 等于 mymod)
bases : 類的所有父類構成元素(包含了一個由所有父類組成的元組)
print Student.__dict__
print Student.__doc__
print Student.__name__
print Student.__module__
print Student.__bases__
輸出結果:
{'__module__': '__main__', 'name': 'jack', 'setName': <function setName at
0x1096c37d0>, 'age': 18, '__doc__': None, '__init__': <function __init__ at
0x1096c3758>}
None
Student
__main__
()
五、類的繼承
面向對象的編程帶來的主要好處之一是代碼的重用,實現這種重用的方法之一是通過繼承機制。繼承完全可以理解成類之間的類型和子類型關系。
需要注意的地方:繼承語法 class 派生類名(基類名)://... 基類名寫在括號里,基本類是在類定義的時候,在元組之中指明的。
在python中繼承中的一些特點:
1:在繼承中基類的構造(init()方法)不會被自動調用,它需要在其派生類的構造中親自專門調用。
2:在調用基類的方法時,需要加上基類的類名前綴,且需要帶上self參數變量。區別在于類中調用普通函數時并不需要帶上self參數
3:Python總是首先查找對應類型的方法,如果它不能在派生類中找到對應的方法,它才開始到基類中逐個查找。(先在本類中查找調用的方法,找不到才去基類中找)。
如果在繼承元組中列了一個以上的類,那么它就被稱作"多重繼承" 。
語法:
派生類的聲明,與他們的父類類似,繼承的基類列表跟在類名之后,如下所示:
class SubClassName (ParentClass1[, ParentClass2, ...]):
'Optional class documentation string'
class_suite
class Parent: # 定義父類
parentAttr = 100
def __init__(self):
print "調用父類構造函數"
def parentMethod(self):
print '調用父類方法'
def setAttr(self, attr):
Parent.parentAttr = attr
def getAttr(self):
print "父類屬性 :", Parent.parentAttr
class Child(Parent): # 定義子類
def __init__(self):
print "調用子類構造方法"
def childMethod(self):
print '調用子類方法'
c = Child() # 實例化子類
c.childMethod() # 調用子類的方法
c.parentMethod() # 調用父類方法
c.setAttr(200) # 再次調用父類的方法 - 設置屬性值
c.getAttr() # 再次調用父類的方法 - 獲取屬性值
六、多繼承
class P1(object):
def foo(self):
print 'p1-foo'
class P2(object):
def foo(self):
print 'p2-foo'
def bar(self):
print 'p2-bar'
class C1(P1, P2):
pass
class C2(P1, P2):
def bar(self):
print 'C2-bar'
class D(C1, C2):
pass
對經典類和新式類來說,屬性的查找順序是不同的。現在我們分別看一下經典類和新式類兩種不同的表現
1、經典類
d = D()
d.foo() # 輸出 p1-foo
d.bar() # 輸出 p2-bar
實例d調用foo()
時,搜索順序是
D = > C1 = > P1
實例d調用bar()
時,搜索順序是
D = > C1 = > P1 = > P2
換句話說,經典類的搜索方式是按照“從左至右,深度優先”的方式去查找屬性。d先查找自身是否有foo方法,沒有則查找最近的父類C1里是否有該方法,如果沒有則繼續向上查找,直到在P1中找到該方法,查找結束。
2、新式類
使用新式類要去掉第一段代碼中的注釋
d = D()
d.foo() # 輸出 p1-foo
d.bar() # 輸出 c2-bar
實例d調用foo()
時,搜索順序是
D = > C1 = > C2 = > P1
實例d調用bar()
時,搜索順序是
D = > C1 = > C2
可以看出,新式類的搜索方式是采用“廣度優先”的方式去查找屬性。
可以調用類的mro屬性來查看查找順序
七、方法重寫
class Parent: # 定義父類
def myMethod(self):
print '調用父類方法'
class Child(Parent): # 定義子類
def myMethod(self):
print '調用子類方法'
c = Child() # 子類實例
c.myMethod() # 子類調用重寫方法
單下劃線、雙下劃線、頭尾雙下劃線說明:
foo: 定義的是特殊方法,一般是系統定義名字 ,類似 init() 之類的。
_foo: 以單下劃線開頭的表示的是 protected 類型的變量,即保護類型只能允許其本身與子類進行訪問,不能用于 from module import *
__foo: 雙下劃線的表示的是私有類型(private)的變量, 只能是允許這個類本身進行訪問了。