·類(Class) 筆記: Python是一種面向對象(Object Oriented)的編程語言,類(Class)是Python的核心概念。在Python中,不管是列表、字元串、函數和類都是對象。 在面向對象編程(OOP)中,任何一個對象都要包含兩個部分:屬性(是什麼)和方法(能做什麼) 舉個例子 ...
·類(Class)
筆記:
Python是一種面向對象(Object Oriented)的編程語言,類(Class)是Python的核心概念。在Python中,不管是列表、字元串、函數和類都是對象。
在面向對象編程(OOP)中,任何一個對象都要包含兩個部分:屬性(是什麼)和方法(能做什麼)
舉個例子:小紅有某些特征:眼睛大、皮膚白、身材好,這些特征可以比作類中屬性;除了特征之外,小紅會唱歌、跳舞、彈琴,這些能力可以比作類中的方法:
def 美女: 眼睛 = 大 皮膚 = 白 身材 = 好 唱歌() 跳舞() 彈琴()
將美女類實例化:
小紅 = 美女() #小紅是一個實例
針對”小紅“這個實例,訪問屬性和使用方法:
小紅.眼睛 #訪問類中的屬性 小紅.眼睛 = 小 #修改類中的屬性(眼睛由大變小) 小紅.唱歌() #使用類中的方法
@類中的基本概念
創建一個Hello類:
class Hello(object): #在python3中,所有類都是類object的子類;定義類也可以寫成 class Hello:或者 class Hello(): def __init__(self,name='world'): #初始化函數__init__ self.name = name #類中的屬性 def get_name(self): #類中的函數稱作方法。 return 'hello,{}'.format(self.name) h = Hello('jimmy') #實例化類(h是實例對象) print(h.name) #訪問類的屬性 print(h.get_name()) #訪問類的方法 print('顯示h是Hello的實例:',type(h)) print('顯示h是Hello的實例:',h.__class__) print('顯示h是Hello的實例,類Hello在記憶體中的地址為(at···):',h)
列印結果:
jimmy
hello,jimmy
顯示h是Hello的實例: <class '__main__.Hello'>
顯示h是Hello的實例: <class '__main__.Hello'>
顯示h是Hello的實例,類Hello在記憶體中的地址為(at···): <__main__.Hello object at 0x000001A057CE6CC0>
初始化函數: __init__
初始化函數意味著實例化時要給name提供一個值,通過__init__執行初始化,讓實例具有name的屬性。由於類Hello中name參數設有預設值,當沒有傳入參數時,預設為world。
在類外,字元串 'Jimmy' 通過初始化函數__init__()中的 name 參數存入記憶體中,以Hello類型存在,組成一個對象,這個對象和變數h建立引用關係。這個過程也可以理解成這些數據附加到一個實例上,這樣就能通過實例以訪問屬性的方式訪問它。
類中的: Self
在類中, 如果某個地方(比如類中的方法)想要使用實例化傳入的數據,那該怎麼辦?
在類中,將所有傳入數據都賦值給一個變數,這個變數是在初始化函數__init__中的第一個參數self。它能接收實例化過程中傳入的所有數據,這些數據是根據初始化函數後面的參數導入的。很顯然,self就是一個實例,準確說法是應用實例,因為它所對應的就是具體的數據。接下來來驗證:
class Hello(object): def __init__(self,name='world'): self.name = name
self.address = 'beijing' print(self) print(type(self)) def get_name(self): return 'hello,{}'.format(self.name) h = Hello()
列印結果:
<__main__.Hello object at 0x0000019FBBBB4E10>
<class '__main__.Hello'>
self實例和h實例一樣都有屬性。self.name是self的屬性,值為name,當然也可以寫成self.xxx = name也是可以的。self屬性的值不一定要從外部傳入,也可以在初始化函數中定義,比如self.address = 'beijing'
在get_name(self)方法中,self是預設的,當類實例化後調用此方法,不需要賦值(self能夠讓return中的語句訪問初始函數中傳入的值和屬性)
類提供預設的行為,而實例可以看成一個工廠。所謂工廠就是可以用一個模板作出很多產品,而類就是模板,實例就是具體的產品。
@類屬性和實例屬性
類是一個對象,有屬性;同樣,類實例化後也是一個對象,也有它的屬性。通過實例化得到的屬性稱為實例屬性,一般情況下可以通過類來訪問屬性,也可以通過實例來訪問屬性。
class A: x = 1 a = A() a.x = 5 #更改實例屬性 print('實例屬性為:',a.x) print('類屬性為:',A.x) 列印結果: 實例屬性為: 5 類屬性為: 1
實例屬性更改了,但類屬性沒有跟著改變,這是因為類屬性不會受實例屬性所左右。
class A: x = 1 a = A() A.x = 10 #更改類屬性 print('實例屬性為:',a.x) print('類屬性為:',A.x) 列印結果: 實例屬性為: 10 類屬性為: 10
類屬性更改了,實例屬性也跟著改變了,說明實例屬性受類屬性所左右。
以上所言是指類中的變數引用的是不可變的數據類型(整型、浮點型、字元串、元組),如果引用可變數據類型(字典、列表),數據將發生變化:
class B: x = [1,2,3,4] b = B() b.x.append(5) #實例屬性增加一個值5 print('實例屬性:',b.x) print('類屬性:',B.x) 列印結果: 實例屬性: [1, 2, 3, 4, 5] 類屬性: [1, 2, 3, 4, 5]
當變數中引用的是可變數據類型時,類屬性和實例屬性都能夠直接修改這個對象,從而影響另一方的值。
通過實例和類增加屬性:
class B: x = [1,2,3,4] b = B() B.y = 'hello,world!' #增加一個類屬性
print('實例屬性:',b.y) 列印結果: 實例屬性: hello,world!
結果表明:通過類增加一個類屬性,實例可以訪問到它。
如果是用實例增加一個實例屬性呢?
class B: x = [1,2,3,4] b = B() b.y = 'hello,world!' #增加一個實例屬性 print('實例屬性:',b.y) print('類屬性:',B.y) 列印結果: 實例屬性: hello,world! Traceback (most recent call last): File "test1.py", line 8, in <module> print('類屬性:',B.y) AttributeError: type object 'B' has no attribute 'y'
結果表明:增加的實例屬性可以通過實例訪問,如果通過類訪問,結果顯示類B中沒有屬性y。
@ 數據流轉
在類的應用中,最廣泛的是將類實例化,通過實例來執行各種操作。所以對此過程中的數據流轉必須弄明白。
class Hello(object): def __init__(self,name='world'): self.name = name def get_name(self): return 'hello,{}'.format(self.name) def get_color(self,color): print('My love color is:',color) h = Hello('jimmy') print(h.get_name()) print(h.get_color('red')) 列印結果: hello,jimmy My love color is: red None #由於get_color()方法沒有設置返回值,函數預設返回None
數據流轉過程:
創建實例 h = Hello('jimmy'),h 實例和初始化函數中self對應(self接收實例傳入的所有數據);'jimmy'是具體的數據,通過初始化函數中的name參數傳給self.name(self是個實例,可以設置它的屬性),此時name的值為jimmy。
類中除初始化函數以外的方法無論有沒有定義參數,都要以self開頭,這在類中是不能省略的,這表示所有方法都承接self實例對象。也就是實例的屬性被帶入到每個方法中,如get_name()中的return 'hello,{}'.format(self.name)語句,self.name調用前面已經確定的實例屬性數據為jimmy,所以函數返回hello,jimmy。因此,通過self,可以實現數據在類的內部流轉。
如果要把數據從類的內部傳到外部,可以通過return語句,由於def get_color():方法沒有設置函數返回值,函數預設返回None。
@ 類的命名空間和作用域
類命名空間:
定義類時,在class語句中的代碼都在一個命名空間中執行,即類的命名空間。命名空間是從所定義的命名到對象的映射集合。不同的命名空間可以同時存在但彼此相互獨立。
命名空間因對象不同,可以分為以下幾種:
內置命名空間:
內置函數的命名空間都屬於內置命名空間,因此,可以在程式中直接運行它們。比如print()函數id()函數等拿來就可以直接使用。
全局命名空間:
每個模塊都有自己的全局命名空間,不同模塊的全局命名空間彼此獨立;不同模塊相同名稱的命名空間,因為模塊不同而不會相互干擾。
本地命名空間:
模塊中有類和函數 ,每個類或者函數所定義的命名空間就是本地命名空間。如果函數返回結果或者異常,本地命名空間也將結束。
各個命名空間的關係(圖片來源於網路):
訪問命名空間的時候,就按照從裡到外的順序:
def Duo(x,y): name = 'jimmy' return locals() print(Duo('he','llo')) 列印結果: {'x': 'he', 'y': 'llo', 'name': 'jimmy'}
通過locals()訪問本地命名空間的方法,命名空間中的數據存儲結構和字典一樣;也可以通過globals()訪問全局命名空間。
作用域:是指在python程式中可以直接訪問到的命名空間。直接訪問意味著訪問命名空間中的命名時無需附加任何修飾語。程式按照命名空間從裡到外的順序,搜索相應命名空間能夠訪問到的作用域。
def out_t(): b = 10 def in_t(): c= 20 a = 30
假設我在def in_t():函數中,c對於我來說就是本地作用域,而a和b不是;如果我在def in_t():函數中新增加一個對象(b = 20),這和def out_t():中的b不會衝突,因為他們的作用域不同。
接下來我們證實:
def out_t(): a = 10 def in_t(): a = 20 print('in_t,a=',a) in_t() print('out_t,a=',a) a = 30 print(out_t()) print('a=',a) 列印結果: in_t,a= 20 out_t,a= 10 None a= 30
end~
****** 幾米花的Python ****** 博客主頁:https://www.cnblogs.com/jimmy-share/ 歡迎轉載 ~