Python類和對象學(xué)習(xí)小記

第一次在B站用MarkDown發(fā)專欄,僅當(dāng)測試文。
因為以前學(xué)習(xí)過 C++ 的類和對象,接下來我盡可能從 C++ 的類和對象語法角度來快速過這部分內(nèi)容。重載和多態(tài)這部分內(nèi)容應(yīng)該用不到,就沒看了。
例程出處可見 Python 面向?qū)ο?| 菜鳥教程。
例子1:基本知識例子2:內(nèi)置屬性例子3:對象銷毀例子4:類的繼承例子5:訪問權(quán)限補充:單下劃線、雙下劃線、頭尾雙下劃線
例子1:基本知識
#!/usr/bin/python
#?-*-?coding:?UTF-8?-*-
class?Employee:
???'所有員工的基類'
???empCount?=?0
???def?__init__(self,?name,?salary):
??????self.name?=?name
??????self.salary?=?salary
??????Employee.empCount?+=?1
???def?displayCount(self):
?????print?"Total?Employee?%d"?%?Employee.empCount
???def?displayEmployee(self):
??????print?"Name?:?",?self.name,??",?Salary:?",?self.salary
"創(chuàng)建?Employee?類的第一個對象"
emp1?=?Employee("Zara",?2000)
"創(chuàng)建?Employee?類的第二個對象"
emp2?=?Employee("Manni",?5000)
emp1.displayEmployee()
emp2.displayEmployee()
print?"Total?Employee?%d"?%?Employee.empCount
class Employee: '所有員工的基類'
:類文檔字符串,相當(dāng)于注釋,但不是真的注釋,而是作為了代碼的一部分,方便閱讀代碼empCount
:應(yīng)視為C++的靜態(tài)成員變量(對,是加修飾詞 static 的那種,真的不是普通成員變量,普通成員變量都在“構(gòu)造函數(shù)”中就已經(jīng)“聲明”了。注意,因為python的語法沒那么嚴格,不需要聲明變量,別問我為什么python是這個鬼樣子)def \_\_init\_\_(self, name, salary)
:可視為構(gòu)造函數(shù)def displayCount(self)
:類的方法,可視為成員函數(shù)self
:相當(dāng)于C++中的 this 指針,實際上也可以換成別的名字。類的方法必須都加上這個參數(shù),用于指代自己- 創(chuàng)建實例(這里沒什么好說的,實例化對象罷了):
"創(chuàng)建?Employee?類的第一個對象"
emp1?=?Employee("Zara",?2000)
"創(chuàng)建?Employee?類的第二個對象"
emp2?=?Employee("Manni",?5000)
- 訪問屬性及調(diào)用方法(訪問成員變量、調(diào)用成員函數(shù)):
emp1.displayEmployee()
emp2.displayEmployee()
print?"Total?Employee?%d"?%?Employee.empCount
- 接下來的例子很有意思了,因為Python中可以在任意地方任意添加屬性(成員變量),但是C++不能:
emp1.age?=?7??#?添加一個?'age'?屬性
emp1.age?=?8??#?修改?'age'?屬性
del?emp1.age??#?刪除?'age'?屬性
因此,需要引入一個訪問屬性的機制,以方便監(jiān)控屬性:
hasattr(emp1,?'age')????#?如果存在?'age'?屬性返回?True。
getattr(emp1,?'age')????#?返回?'age'?屬性的值
setattr(emp1,?'age',?8)?#?添加屬性?'age'?值為?8
delattr(emp1,?'age')????#?刪除屬性?'age'
例子2:內(nèi)置屬性
接下來的例子確實很有Python的味道。。。
#!/usr/bin/python
#?-*-?coding:?UTF-8?-*-
class?Employee:
???'所有員工的基類'
???empCount?=?0
???def?__init__(self,?name,?salary):
??????self.name?=?name
??????self.salary?=?salary
??????Employee.empCount?+=?1
???def?displayCount(self):
?????print?"Total?Employee?%d"?%?Employee.empCount
???def?displayEmployee(self):
??????print?"Name?:?",?self.name,??",?Salary:?",?self.salary
print?"Employee.__doc__:",?Employee.__doc__
print?"Employee.__name__:",?Employee.__name__
print?"Employee.__module__:",?Employee.__module__
print?"Employee.__bases__:",?Employee.__bases__
print?"Employee.__dict__:",?Employee.__dict__
Python的內(nèi)置類屬性:
\_\_name\_\_
: 類名\_\_bases\_\_
: 類的所有父類構(gòu)成元素(包含了一個由所有父類組成的元組)。這個可以直接查看被繼承的類有哪些,比C++方便多了\_\_module\_\_
: 類定義所在的模塊(類的全名是'__main__.className',如果類位于一個導(dǎo)入模塊mymod中,那么className.__module__ 等于 mymod)\_\_doc\_\_
: 類的文檔字符串
例子3:對象銷毀
這個例子涉及對象的銷毀。
#!/usr/bin/python
#?-*-?coding:?UTF-8?-*-
class?Point:
???def?__init__(?self,?x=0,?y=0):
??????self.x?=?x
??????self.y?=?y
???def?__del__(self):
??????class_name?=?self.__class__.__name__
??????print?class_name,?"銷毀"
pt1?=?Point()
pt2?=?pt1
pt3?=?pt1
print?id(pt1),?id(pt2),?id(pt3)?#?打印對象的id
del?pt1
del?pt2
del?pt3
輸出結(jié)果:
3083401324?3083401324?3083401324
Point?銷毀
def \_\_del\_\_(self)
:相當(dāng)于C++中的析構(gòu)函數(shù)- 對象的id可以簡單理解為對象的“地址”
例子4:類的繼承
以下幾部分內(nèi)容與C++的習(xí)慣大有不同,雖然核心是相同的。注意其區(qū)別。
#!/usr/bin/python
#?-*-?coding:?UTF-8?-*-
class?Parent:????????#?定義父類
???parentAttr?=?100
???def?__init__(self):
??????print?"調(diào)用父類構(gòu)造函數(shù)"
???def?parentMethod(self):
??????print?'調(diào)用父類方法'
???def?setAttr(self,?attr):
??????Parent.parentAttr?=?attr
???def?getAttr(self):
??????print?"父類屬性?:",?Parent.parentAttr
class?Child(Parent):?#?定義子類
???def?__init__(self):
??????print?"調(diào)用子類構(gòu)造方法"
???def?childMethod(self):
??????print?'調(diào)用子類方法'
c?=?Child()??????????#?實例化子類
c.childMethod()??????#?調(diào)用子類的方法
c.parentMethod()?????#?調(diào)用父類方法
c.setAttr(200)???????#?再次調(diào)用父類的方法?-?設(shè)置屬性值
c.getAttr()??????????#?再次調(diào)用父類的方法?-?獲取屬性值
輸出:
調(diào)用子類構(gòu)造方法
調(diào)用子類方法
調(diào)用父類方法
父類屬性?:?200
class C(A, B): ? # 繼承類 A 和 B
- 實例化子類,只會調(diào)用子類的構(gòu)造方法(對應(yīng)C++構(gòu)造函數(shù))
- 如果在子類中需要父類的構(gòu)造方法就需要顯式的調(diào)用父類的構(gòu)造方法,或者不重寫父類的構(gòu)造方法(意思就是子類不寫構(gòu)造函數(shù)就完事了)
重要注意!如果要繼承父類的構(gòu)造方法,可以使用 super 關(guān)鍵字:
super(子類,self).__init__(參數(shù)1,參數(shù)2,....)
或
父類名稱.__init__(self,參數(shù)1,參數(shù)2,...)
例子:
class?Father(object):
????def?__init__(self,?name):
????????self.name=name
????????print?(?"name:?%s"?%(?self.name))
????def?getName(self):
????????return?'Father?'?+?self.name
class?Son(Father):
????def?__init__(self,?name):
????????super(Son,?self).__init__(name)
????????print?("hi")
????????self.name?=??name
????def?getName(self):
????????return?'Son?'+self.name
if?__name__=='__main__':
????son=Son('runoob')
????print?(?son.getName()?)
輸出(先調(diào)用父類方法,再調(diào)用子類方法):
name:?runoob
hi
Son?runoob
例子5:訪問權(quán)限
#!/usr/bin/python
#?-*-?coding:?UTF-8?-*-
class?JustCounter:
????__secretCount?=?0??#?私有變量,加了兩個下劃線在開頭
????publicCount?=?0????#?公開變量
????def?count(self):
????????self.__secretCount?+=?1
????????self.publicCount?+=?1
????????print?self.__secretCount
counter?=?JustCounter()
counter.count()
counter.count()
print?counter.publicCount
print?counter.__secretCount??#?報錯,實例不能訪問私有變量
- 私有屬性(私有成員變量):
__private_attrs:兩個下劃線開頭加在屬性名字開頭,表示為私有屬性
類內(nèi)部使用:self.__private_attrs
- 私有方法(私有成員函數(shù)):
__private_method:兩個下劃線開頭加在方法名字開頭,表示為私有方法
類的內(nèi)部調(diào)用:self.__private_methods
補充:單下劃線、雙下劃線、頭尾雙下劃線
__foo__: 定義的是特殊方法,一般是系統(tǒng)定義名字 ,類似 __init__() 之類的。
_foo: 以單下劃線開頭的表示的是 protected 類型的變量,即保護類型只能允許其本身與子類進行訪問,不能用于 from module import * (保護屬性在 C++ 中應(yīng)該很熟悉了,父類子類都能訪問,但是外部不能訪問;私有屬性是父類自己能訪問,繼承的子類和外部不能訪問)
__foo: 雙下劃線的表示的是私有類型(private)的變量, 只能是允許這個類本身進行訪問了。
好了,就看到這吧。