摘要:類對象被創(chuàng)建時存在于類命名空間內(nèi)的所有名稱都是有效的屬性名稱。類的實例化,是使用函數(shù)表示法,可以把類對象看做是會返回一個新的類實例的函數(shù)。這就是可變對象作為類變量時的特性。類變量是所有類的實例共享的屬性和方法,實例變量是每個實例獨有的數(shù)據(jù)。
Python是面向?qū)ο蟮母呒壘幊陶Z言,在Python里面“一切都是對象”:數(shù)字、字符串、元組、列表、字典、集合等內(nèi)置數(shù)據(jù)類型,以及函數(shù)、方法、類、模塊都是對象。
語言本身提供了上述的基本對象,但在實際編程中,我們要創(chuàng)造各種各樣的對象,Python就為我們提供了創(chuàng)造我們自己的對象的方法:類。
類(Class),就是組合數(shù)據(jù)和功能的方法,它讓我們創(chuàng)建一個新類型的對象,并可以創(chuàng)建該類型的新實例。類組合的數(shù)據(jù),就是保存自己狀態(tài)的屬性,而它組合的功能(函數(shù))就是改變自己狀態(tài)的(定義在類中的)方法。類內(nèi)部定義的函數(shù),稱為類的方法。
Python中的類和其它語言(比如C++)有很多相似的特征但也有些區(qū)別。如果你已了解其它語言的類的概念,可以在學習Python類時做一定的對比進行學習;如果你沒有學過其它語言也不要緊,學過之后你會發(fā)現(xiàn),類的概念是如此簡單。
類的定義類的定義是通過關鍵字class實現(xiàn)的,下面是最簡單的類的定義的樣子:
class ClassName: 語句1 ... 語句n
是不是這個形式跟函數(shù)的定義(def 語句)很像。因為類是數(shù)據(jù)和功能的組合,所以語句1可能是內(nèi)部變量(數(shù)據(jù))的定義和賦值語句,也可能是內(nèi)部方法(函數(shù))的定義語句。類內(nèi)部的函數(shù)定義通常具有一種特別形式的參數(shù)列表,這是方法調(diào)用的約定規(guī)范里面指明的。這個特別形式就是第一個參數(shù)必須是self,后面將詳細介紹。
進入類定義時,就會創(chuàng)建一個新的命名空間,并把它用作局部作用域。因此,所有對局部變量的賦值都是在這個新命名空間內(nèi)進行的。特別的,函數(shù)定義會綁定到這個局部作用域里的新函數(shù)名稱。
正常離開(從結尾出)類定義時,就會創(chuàng)建一個類對象。它基本上是一個包圍在類定義所創(chuàng)建的命名空間內(nèi)容周圍的包裝器。元素的(在進入類定義之前起作用的)局部作用域?qū)⒅匦律?,類對象將在這里被綁定到類定義頭給出的類名稱(在上面的例子中就是ClassName)。
類對象類對象(比如上面例子的ClassName)支持兩種操作:屬性引用和實例化。
屬性引用的語法跟Python中所有屬性引用的方法一樣:obj.name。類對象被創(chuàng)建時存在于類命名空間內(nèi)的所有名稱都是有效的屬性名稱。下面是一個包含數(shù)據(jù)和方法的簡單的類定義:
class YuanRenXue: """A demo of class""" name = "猿人學" def say_hi(self): print("Hello world!")
對這個類的有效的屬性引用就是:YuanRenXue.name和YuanRenXue.say_hi,它們分別返回一個字符串和一個函數(shù)對象。
類屬性也可以被賦值,因此可以通過賦值來更改Yuanrenxue.name的值。
類的__doc__也是一個有效的屬性,對他的引用會返回所屬類的文檔字符串:"A demo of class"。
類的實例化,是使用函數(shù)表示法,可以把類對象看做是會返回一個新的類實例的函數(shù)。比如上面類對象的實例化就是:
yrx = YuanRenXue()
這就創(chuàng)建了一個類的新實例并將詞對象分配給局部變量yrx。
實例化操作可以看成是“調(diào)用”類對象。但我們在創(chuàng)建類實例時都想要做些初始化操作,為此類定義時可以定義一個名為__init__()的特殊方法。它是類實例化的初始化方法,跟C++語言中 的構造函數(shù)類似。
def __init__(self): self.data = None
定義了__init__()方法后,類的實例化操作會自動調(diào)用該方法。
當然,__init__()方法也可以有額外(除self之外)的參數(shù)以實現(xiàn)更靈活的初始化操作。類對象實例化時(“調(diào)用”類對象)傳遞的參數(shù)會被傳遞給__init__()方法。例如:
In [27]: class Point: ...: def __init__(self, x, y): ...: self.x = x ...: self.y = y ...: In [28]: p = Point(7, 8) In [29]: p.x, p.y Out[29]: (7, 8)實例對象
類實例化后我們就得到了實例對象,對它的操作就是:屬性引用。這里的有效屬性名稱是數(shù)據(jù)屬性和方法。
o
數(shù)據(jù)屬性,對應C++中的“數(shù)據(jù)成員”,不懂C++也沒關系,“數(shù)據(jù)成員”這名字字面上就很形象。數(shù)據(jù)屬性不需要聲明,它像普通變量一樣,在第一次賦值時產(chǎn)生。比如p是聲明創(chuàng)建的Point的實例,則以下代碼會打印數(shù)值8:
p.times = 1 while p.times < 5: p.times = p.times * 2 print(p.times) del p.times
雖然p.times并沒有在類定義時聲明(數(shù)據(jù)屬性不需要聲明),但在任何時候,我們可以給實例賦值一個新的數(shù)據(jù)屬性(這里是p.times),并可以隨時刪除實例的數(shù)據(jù)屬性(del p.times)。
方法,是“從屬于”對象的函數(shù)。方法這個術語并不是類實例獨有的,其它對象也可以有方法。比如,列表對象有append(), insert(), sort()等方法。
實例對象的有效方法名稱依賴于其所屬的類。 根據(jù)定義,一個類中所有是函數(shù)對象的屬性都是定義了其實例的相應方法。 因此在我們的示例中,yrx.say_hi是有效的方法引用,因為YuanRenXue.say_hi是一個函數(shù);而yrx.name不是方法,因為YuanRenXue.name不是一個函數(shù)。這里要注意,yrx.say_hi與YuanRenXue.say_hi并不是一回事,它是一個方法對象,不是函數(shù)對象,通俗講,前者是實例的方法,后者是類的函數(shù)。
方法對象通常,調(diào)用方法的方法是:
yrx.say_hi()
在YuanRenXue 示例中,這將打印字符串Hello World。但是,調(diào)用一個方法也可以換另外一種形式,把它賦值給一個變量后再調(diào)用。例如:
yrx_say = yrx.say_hi yrx_say()
當我們調(diào)用yrx.say_hi()時并沒有帶參數(shù),但say_hi()函數(shù)定義時指定了一個參數(shù)。實際上,方法的特殊之處就是實例對象會作為函數(shù)的第一個參數(shù)(self)被傳入。調(diào)用yrx.say_hi()其實就相當于YuanRenXue.say_hi(yrx)。
類變量和實例變量一般來說,類變量用于類的所有實例共享的屬性和方法,而實例變量用于每個實例的唯一數(shù)據(jù):
In [33]: class Tiger: ...: kind = "feline" ...: def __init__(self, name) File "", line 3 def __init__(self, name) ^ SyntaxError: invalid syntax In [34]: class Tiger: ...: kind = "feline" ...: def __init__(self, name): ...: self.name = name ...: In [35]: a = Tiger("Kiro") In [36]: b = Tiger("Zim") In [37]: a.kind Out[37]: "feline" In [38]: b.kind Out[38]: "feline" In [39]: a.name Out[39]: "Kiro" In [40]: b.name Out[40]: "Zim"
如果類變量是列表或字典這種可變對象會導致令人驚訝的結果,我們要明白這種結果,從而可以在需要的時候利用這個特性,也可以在不需要的時候避免這個特性。是取是舍,全在于我們在編程時要定義的類的作用。下面,我們看看這個“令人驚訝”的結果是什么:
In [42]: class Tiger: ...: places = [] ...: def __init__(self, name): ...: self.name = name ...: def go_place(self, place): ...: self.places.append(place) ...: In [43]: a = Tiger("Kiro") In [44]: b = Tiger("Zim") In [45]: a.go_place("北京") In [46]: b.go_place("上海") In [47]: a.places Out[47]: ["北京", "上海"]
這里,把places定義為類變量,它就記錄了所有老虎(Kiro和Zim,以及后面實例化出來個各個老虎)去過的地方,所以,盡管a只去過北京,但是當我們通過a查看places,也看到了上海。這就是可變對象作為類變量時的特性。如果我們就是想記錄所有老虎實例對象去過的地方,這樣的用法就是恰到好處。
如果,我們只想記錄每一只老虎去過的地方,那么就應該把places定義為實例變量,也就是在__init__()中進行初始化賦值。
需要注意的地方(1)數(shù)據(jù)屬性會覆蓋掉具有相同名稱的方法屬性,因此寫程序時為了避免名稱沖突,可以使用某些規(guī)范來減少沖突,比如:
方法名稱使用大寫字母;
屬性名稱加上特殊的前綴(或加一個下劃線);
用動詞來命名方法,用名詞來命名數(shù)據(jù)屬性。
這些規(guī)范稱為“代碼規(guī)范”,一個好的代碼規(guī)范讓代碼可讀性更高,也更利用團隊合作。有名的Python代碼規(guī)范有“PEP 8”,也有Google的Python風格規(guī)范。
(2)數(shù)據(jù)屬性可以被方法以及對象之外的任何用戶(使用該類的人)所引用。也就是說,Python不行C++類那樣有私有成員,Python沒有任何對象能強制隱藏數(shù)據(jù)。
(3)類對象的用戶應該謹慎使用數(shù)據(jù)屬性,直接操作數(shù)據(jù)屬性可能破壞其中的固定變量。但我們可以想一個實例對象添加我們自己的數(shù)據(jù)屬性,但要避免與原有的名稱沖突。
(4)方法的第一個參數(shù)常常被命名為self,代表實例對象。但這只是大家普通認同的一個約定。你可以用任何單詞來替代它,但是你的代碼讓氣體程序員讀起來就很費勁,也會對VS Code這樣的編輯器造成困惑。
總結類是組合數(shù)據(jù)和功能的方法,其中:
數(shù)據(jù),是類的屬性,從屬于類的各種數(shù)據(jù)對象;
功能,是類的方法,定義在類內(nèi)部的各種函數(shù)。
定義好一個類我們就創(chuàng)建了一個類對象,類對象支持兩種操作:屬性引用和實例化。
類對象實例化后就得到了實例對象,它有兩種屬性名稱:數(shù)據(jù)屬性和方法。
類變量是所有類的實例共享的屬性和方法,實例變量是每個實例獨有的數(shù)據(jù)。
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/43844.html
摘要:類的繼承,說明了不同類直接的關系,派生類復用了基類的代碼同時也繼承了基類的屬性和方法。派生類的實例化會創(chuàng)建該類的一個新實例。派生類既可以單獨繼承一個基類,也可以多重繼承多個基類。 面向?qū)ο笳Z言的一個特性就是類的繼承。繼承的關系跟人類繁衍的關系相似,被繼承的類稱為基類(也叫做父類),繼承而得的類叫派生類(也叫子類),這種關系就像人類的父子關系。 showImg(https://segme...
摘要:語句就是幫助我們拋出知道異常的,比如的使用很簡單,它的語法如下如果它后面不帶表達式參數(shù),它會重新引發(fā)當前作用域內(nèi)最后一個激活的異常。,用于異常的串聯(lián)。自定義的異常類的名稱通常以錯誤結尾,類似與內(nèi)置標準異常的命名。 前面我們講到的Python編程過程中,在可能出現(xiàn)異常的地方使用嘗試語句,來正確的處理一些異常,可以保證程序不中斷繼續(xù)運行。 showImg(https://segmentfa...
摘要:以下這些項目,你拿來學習學習練練手。當你每個步驟都能做到很優(yōu)秀的時候,你應該考慮如何組合這四個步驟,使你的爬蟲達到效率最高,也就是所謂的爬蟲策略問題,爬蟲策略學習不是一朝一夕的事情,建議多看看一些比較優(yōu)秀的爬蟲的設計方案,比如說。 (一)如何學習Python 學習Python大致可以分為以下幾個階段: 1.剛上手的時候肯定是先過一遍Python最基本的知識,比如說:變量、數(shù)據(jù)結構、語法...
摘要:學習筆記七數(shù)學形態(tài)學關注的是圖像中的形狀,它提供了一些方法用于檢測形狀和改變形狀。學習筆記十一尺度不變特征變換,簡稱是圖像局部特征提取的現(xiàn)代方法基于區(qū)域圖像塊的分析。本文的目的是簡明扼要地說明的編碼機制,并給出一些建議。 showImg(https://segmentfault.com/img/bVRJbz?w=900&h=385); 前言 開始之前,我們先來看這樣一個提問: pyth...
閱讀 2040·2021-09-30 09:47
閱讀 715·2021-09-22 15:43
閱讀 1996·2019-08-30 15:52
閱讀 2445·2019-08-30 15:52
閱讀 2556·2019-08-30 15:44
閱讀 919·2019-08-30 11:10
閱讀 3380·2019-08-29 16:21
閱讀 3305·2019-08-29 12:19