[python]類型與對象

來源:互聯網
上載者:User

標籤:建立對象   nat   浮點數   淺複製   encoding   type   error   hello   類集   

1. 術語

程式中所儲存的所有資料都是對象。每個對象都有一個身份、一個類型和一個值。對象的身份可以看作是指向它在記憶體中所處位置的指標,變數名就是引用這個具體位置的名稱。
對象的類型也稱作類別,用於描述對象的內部表示及它支援的方法與操作。建立特定類型的對象時,有時也將該對象稱為該類型的執行個體。執行個體被建立之後,它的身份和類型就不可改變。如果對象的值是可以修改的,稱為可變對象,反之稱為不變對象。如果某個對象包含對其他對象的引用,則將其稱為容器或集合。
大多數對象擁有大量特有的資料屬性和方法。屬性就是與對象相關的值。方法就是被調用時將在對象上執行某些操作的函數。使用點"."運算子可以訪問屬性和方法。

2. 對象的身份與類型

內建函數id()可返回一個對象的身份,傳回值為整數。is運算子用於比較兩個對象的身份。內建函數type()則返回一個對象的類型。例如:

def compare(a, b):    if a is b:        # 同一個對象    if a == b:        # 具有相同的值    if type(a) is type(b):        # 具有相同類型

對象的類型本身也是一個對象,稱為對象的類。所有類型對象都有一個指定的名稱,可用於執行類型檢查,例如:

if type(s) is list:    s.append(item)if type(d) is dict:    d.update(t)

檢查類型的更佳方式是用內建函數isinstance(object, type),例如:

if isinstance(s, list):    s.append(item)if isinstance(d, dict):    d.update(t)

因為isinstance()函數能夠實現繼承,因此是檢查所有Python物件類型的首選方式。

3. 引用計數與垃圾收集

所有對象都有引用計數。無論是給對象分配一個新名稱,還是將其放入一個容器,該對象的引用計數就會增加,例如:

a = 37 # 建立值為37的對象b = a # 增加37的引用計數c = []c.append(b) #增加37的引用計數

這個例子建立了一個包含值37的對象,a只是引用這個新建立對象的一個名稱,將a賦值給b時,b就成了同一對象的新名稱,而且該對象的引用計數會增加。類似地,將b放到一個列表中時,該對象的引用計數將再次增加。
使用del語句或者引用超出範圍時(或者被重新賦值),對象的引用計數就會減少,例如:

del a # 減少37的引用計數b = 42 #減少37的引用計數c[0] = 2.0 #減少37的引用計數

使用sys.getrefcount()函數可以獲得對象的當前引用計數,例如:

a = 37import sysprint(sys.getrefcount(a))

多數情況下,引用計數比猜測的要大得多,對於不可變資料(如數字和字串),解譯器會主動在程式的不同部分共用對象,以便節約記憶體。
當一個對象的引用計數歸零時,它將被垃圾收集機制處理掉。在某些情況下,很多已不再使用的對象間可能存在循環相依性關係,例如:

a = {}b = {}a[‘b‘] = bb[‘a‘] = adel adel b

在以上例子中,del語句將會減少a和b的引用計數,並銷毀用於引用底層對象的名稱。然而因為每個對象都包含一個對其他對象的引用,所以引用計數不會歸零,對象也不會被銷毀,從而導致記憶體泄露。為瞭解決這個問題,解譯器會定期執行一個迴圈檢測器,搜尋不可訪問對象的迴圈並刪除它們。

4. 引用與複製

在程式進行像a = b這樣的賦值時,就會建立一個對b的引用。對於像數字和字串這樣的不可變對象,這種賦值實際上建立了b的一個副本。然而,對於可變對象(如列表和字典)引用行為會完全不同,例如:

a = [1, 2, 3, 4]b = aprint(b is a) # Trueb[2] = -100print(a[2]) #-100

因為a和b引用的同一個對象,修改其中任意一個變數都會影響到另一個。所以必須建立對象的副本而不是新的引用。對於像列表和字典這樣的容器物件,可以使用兩種複製操作: 淺複製和深複製。淺複製將建立一個新對象,但它包含的是對原始對象中包含的項的引用,例如:

a = [1, 2, [3, 4]]b = list(a)print(b is a) #Falseb.append(100)print(b) # [1, 2, [3, 4], 100]print(a) # [1, 2, [3, 4]]b[2][0] = -100print(b) # [1, 2, [-100, 4], 100]print(a) # [1, 2, [-100, 4]]

深複製將建立一個新對象,並且遞迴地複製它包含的所有對象。可以使用標準庫中的copy.deepcopy()函數完成該工作,例如:

import copya = [1, 2, [3, 4]]b = copy.deepcopy(a)b[2][0] = -100print(b) # [1, 2, [-100, 4]]print(a) # [1, 2, [3, 4]]
5. 表示資料的內建類型

大約有12種資料類型可用於表示程式中用到的大多數資料。如下表所示:

類型分類 類型名稱 描述
None Type(None) null對象None
數字 int 整數
數字 float 浮點數
數字 complex 複數
數字 bool 布爾值
序列 str 字串
序列 list 列表
序列 tuple 元組
序列 range 建立的整數範圍
映射 range 建立的整數範圍
集合 set 可變集合
集合 frozenset 不可變集合

None類型表示一個沒有值的對象,在程式中表示為None。如果一個函數沒顯示傳回值,則返回該對象。None常用於選擇性參數的預設值,以便讓函數檢測調用者是否為該參數實際傳遞了值。
Python使用4種數字類型:布爾型、整數、浮點數以及複數。除了布爾值,所有數字對象都是有符號的。所有數字類型都不可變。數字類型擁有大量的屬性和方法,可以簡化涉及混合算術的運算。為了與有理數相容,整數使用了屬性x.numerator和x.denominator。為了相容複數,整數或浮點數y擁有屬性y.real和y.imag,以及方法y.conjugate()。使用y.as_interger_ratio()可將浮點數y轉換為分數形式的一對整數。方法y.is_interger()用於測試浮點數y是否表示整數值。通過方法y.hex()和y.fromhex()可用低級二進位形式使用浮點數。
序列表示索引為非負整數的有序對象集合,包括字串、列表和元組。所有序列支援的方法如下表:

項目 描述
s[i] 返回一個序列的元素i
s[i:j] 返回一個切片
s[i:j:stride] 返回一個擴充切片
lens(s) s中的元素數
min(s) s中的最小值
max(s) s中的最大值
sum(s [, initial]) s中各項的和
all(s) 檢查s中的所有項是否為True
any(s) 檢查s中的任意項是否為True

適用於可變序列的方法如下表:

項目 描述
s[i] = v 項目賦值
s[i:j] = t 切片賦值
s[i:j:stride] = t 擴充切片賦值
del s[i] 項目刪除
del s[i:j] 切片刪除
del s[i:j:stride] 擴充切片刪除

列表支援的方法如下表:

方法 描述
list(s) 將s轉換為一個列表
s.append(x) 將一個新元素x追加到s末尾
s.extend(x) 將一個新列表追加到s末尾
s.count(x) 計算s中x的出現次數
s.index(x [, start [, stop]]) 找到x首次出現的位置
s.insert(i, x) 在索引i處插入x
s.pop([i]) 返回元素i並從列表中移除它,省略i則返回列表中最後一個元素
s.remove(x) 搜尋x並從s中移除它
s.reverse() 顛倒s中的所有元素的順序
s.sort([key [, reverse]]) 對s中的所有元素進行排序。key是一個鍵函數。reverse表明以倒序對列表進行排序

list(s)可將任意可迭代類型轉換為列表。如果s已經是列表,則該函數構造的新列表是s的一個淺複製。
字串支援的方法如下表:

方法 描述
s.captitalize() 首字元變大寫
s.center(width [, pad]) 在長度為width的欄位內將字串置中。pad是填充字元
s.count(sub [, start [, end]]) 計算指定子字串sub的出現次數
s.decode([encoding [, errors]]) 解碼一個字串並返回一個Unicode字串
s.encdoe([encoding [, errors]]) 返回字串的編碼版本
s.endswith(suffix [, start [, end]]) 檢查字串是否以suffix結尾
s.expandtabs([tabsize]) 使用空格替換定位字元
s.find(sub [, start [, end]]) 找到指定子字串sub首次出現的位置,否則返回-1
s.format(args, *kwargs) 格式化s
s.index(sub [, start [, end]]) 指到指定子字串sub首次出現的位置,否則報錯
s.isalnum() 檢查所有字元是否都為字母或數字
s.isalpha() 檢查所有字元是否都為字母
s.isdigit() 檢查所有字元是否都為數字
s.islower() 檢查所有字元是否都為小寫
s.isspace() 檢查所有字元是否都為空白
s.istitle() 檢查字串是否為標題字串(每個單字首大寫)
s.isupper() 檢查所有字元是否都為大寫
s.join(t) 使用s作為分隔字元串連序列t中的字串
s.ljust(width [, fill]) 在長度為width的字串內靠左對齊s
s.lower() 轉換為小寫形式
s.lstrip([chrs]) 刪掉chrs前面的空白或字元
s.partition(sep) 使用分隔字元字串sep劃分一個字串。返回一個元組(head, sep, tail)
s.replace(old, new [, maxreplace]) 替換一個子字串
s.rfind(sub [, start [, end]]) 找到一個子字串最後一次出現的位置
s.rindex(sub [, start [, end]]) 找到一個子字串最後一次出現的位置,否則報錯
s.rjust(width [, fill]) 在長度為width的字串內靠右對齊s
s.rpartition(sep) 使用分隔字元sep劃分字串,但是從字串的結尾處開始搜尋
s.rsplit([sep [, maxsplit]]) 使用sep作為分隔字元對一個字串從後往前進行劃分。maxsplit是最大劃分次數
s.rstrip([chrs]) 刪掉chrs尾部的空白或字元
s.split([sep [, maxsplit]]) 使用sep作為分隔字元對一個字串進行劃分。maxsplit是劃分的最大次數
s.splitlines([keepends]) 將字串分為一個行列表。如果keepends為1,則保留各行最後的分行符號
s.startswith(prefix [, start [, end]]) 檢查一個字串是否以prefix開頭
s.strip([chrs]) 刪掉chrs開頭和結尾的空白或字元
s.swapcase() 將大寫轉換為小寫,或者相反
s.title() 將字串轉換為標題格式
s.translate(table [, deletechars]) 使用一個字元轉換表table轉換字串,刪除deletechars中的字元
s.upper() 將一個字串轉換為大寫形式
s.zfill(width) 在字串的左邊填充0,直至其寬度為width

很多字串方法都接受可選的start和end參數,其值為整數,用於指定s中起始和結束位置的索引。大多數情況下,這些值可以為負值,表示索引是從字串結尾處開始計算的。
映射類型表示一個任意對象的集合,而且可以通過另一個幾乎是任意索引值的集合進行索引。和序列不同,映射對象是無序的,可以通過數字、字串和其他對象進行索引。映射是可變的。
字典是唯一內建的映射類型,任何不可變對象都可以用作字典索引值,如字串、數字、元組等。字典的方法如下表:

項目 描述
len(m) 返回m中的項目數
m[k] 返回m中鍵k的項
m[k] = x 將m[k]的值設為x
del m[k] 從m中刪除m[k]
k in m 如果k是m中的鍵,則返回True
m.clear() 刪除m中的所有項目
m.copy() 返回m的一個副本
m.fromkeys(s [, value]) 建立一個新字典並將序列s中的所有元素作為新字典的鍵,這些鍵的值均為value
m.get(k [, v]) 返回m[k],如果找不到m[k],則返回v
m.items() 返回由(key, value)對組成的一個序列
m.keys() 返回索引值組成的一個序列
m.pop(k [, default]) 如果找到m[k],則返回m[k]並從m中刪除,否則返回default的值
m.popitem() 從m中刪除一個隨機的(key, value)對,並把它返回為一個元組
m.setdefault(k [, v]) 如果找到m[k],則返回m[k],不則返回v,並將m[k]的值設為v
m.update(b) 將b中的所有對象添加到m中
m.values() 返回m中所有值的一個序列

集合是唯一的無序集。與序列不同,集合不提供索引或切片操作。它們和字典也有所區別,即對象不存在相關的索引值。放入集合的項目必須是不可變的。集合分為兩種類型,set是可變的集合,而frozenset是不可變的集合,這兩類集合都是用一對內建函數建立的,例如:

s = set([1, 5, 10, 15])f = frozenset([‘a‘, 37, ‘hello‘])

所有集合支援的方法如下表:

項目 描述
len(s) 返回s中項目數
s.copy() 製作s的一份副本
s.difference(t) 求差集。返回所有要s中,但不在t中的項目
s.intersection(t) 求交集。返回所有同時在s和t中的項目
s.isdisjoint(t) 如果s和t沒有相同項,則返回True
s.issubset(t) 如果s是t的一個子集,則返回True
s.issuperset(t) 如果s是t的一個超集,則返回True
s.symmetric_difference(t) 求對稱差集。返回所有在s或t中,但又不同時在這兩個集合中的項
s.union(t) 求並集。返回所有在s或t中的項

可變集合還另外提供了一些方法,如下表:

項目 描述
s.add(item) 將item添加到s中。如果item已經在s中,則無任何效果
s.clear() 刪除s中的所有項
s.difference_update(t) 從s中刪除同時也在t中的所有項
s.discard(item) 從s中刪除item,如果item不要s的成員,則無任何效果
s.intersection_update(t) 計算s與t的交集,並將結果放入s
s.pop() 返回一個任意的集合元素,並將其從s中刪除
s.remove(item) 從s中刪除item,如果item不是s的成員,引發異常
s.symmetric_difference_update(t) 計算s與t的對稱差集,並將結果放入s
s.update(t) 將t中的所有項添加到s中

所有的這些操作都可以直接修改集合s。

6. 表示程式結構的內建類型

在Python中,函數、類和模組都可以當做資料操作的對象,如下表:

類型分類 類型名稱 描述
可調用 types.BuiltinFunctionType 內建函數或方法
可調用 type 內建類型和類的類型
可調用 object 所有類型和類的祖先
可調用 types.FunctionType 使用者定義的函數
可調用 types.MethodType 類方法
模組 types.ModuleType 模組
類 object 所有類型和類的祖先
類型 type 內建類型和類的類型

可調用類型表示支援函數叫用作業的對象。具有這種屬性的對象有:使用者定義的函數,方法、內建函數與方法,可調用的類與執行個體。
使用者定義的函數是指用def語句或lambda運算子在模組層級別上建立的可調用對象,它具有以下屬性:

屬性 描述
f._doc_ 文檔字串
f._name_ 函數名稱
f._dict_ 包含函數屬性的字典
f._code_ 位元組編譯的代碼
f._defaults_ 包含預設參數的元組
f._globals_ 定義全域命名空間的字典
f._closure_ 包含與嵌套範圍相關資料的元組

方法是在類定義中定義的函數。有3種常見的方法:執行個體方法、類方法和靜態方法。執行個體方法是操作指定類的執行個體的方法,執行個體作為第一個參數傳遞給方法,根據約定該參數一般稱為self。類方法把類本身當作一個對象進行操作,在第一個參數中將類對象傳遞給類。靜態方法就是打包在類中的函數,它不能使用一個執行個體或類對象作為第一個參數。例如:

f = Foo()meth = f.instance_methodmeth(30)

在以上例子中,meth稱為Binder 方法。Binder 方法是可調用對象,它封裝了函數和一個相關執行個體。調用Binder 方法時,執行個體就會作為第一個參數(self)傳遞給方法。方法尋找也可以出現類本身上,例如:

umeth = Foo.instance_methodumeth(f, 30)

在以下例子中,umeth稱為非Binder 方法。非Binder 方法是封裝了方法函數的可調用對象,但需要傳遞一個正確類型的執行個體作為第一個參數。如果傳遞的物件類型錯誤,就會引發TypeError異常。
為方法對象定義的屬性如下表:

屬性 描述
m._doc_ 文檔字串
m._name_ 方法名稱
m._class_ 定義該方法的類
m._func_ 實現方法的函數對象
m._self_ 與方法相關的執行個體(如果是非Binder 方法則為None)

類對象和執行個體也可以當作可調用對象進行操作。類對象使用class語句建立,並作為函數調用,以建立新執行個體。在這種情況下,將函數的參數傳遞給類的_init_()方法,以便初始化新建立的執行個體。如果執行個體定義了一個特殊方法_call_(),它就能夠類比函數的行為。如果該方法是為某個執行個體x而定義,使用x(args)語句等同於調用方法x._call_(args)。
定義類時,類定義通常會產生一個type類型的對象,一個類型對象t的常用屬性如下表:

屬性 描述
t._doc_ 文檔字串
t._name_ 類名稱
t._bases_ 基類的元組
t._dict_ 儲存類方法和變數的字典
t._module_ 定義類的模組名稱
t._abstractmethods_ 抽象方法名稱的集合

建立一個對象執行個體時,執行個體的類型就是定義它的類,例如:

f = Foo()print(type(f)) # <class ‘__main__.Foo‘>

下表顯示執行個體擁有的特殊屬性:

屬性 描述
t._class_ 執行個體所屬的類
t._dict_ 儲存執行個體資料的字典

模組類型是一個容器,可儲存使用import語句載入的對象。模組定義了一個使用字典實現的命名空間,比如,m.x=y等價於m._dic_["x"]=y。模組的可用屬性如下:

屬性 描述
m._dict_ 與模組相關的字典
m._doc_ 模組文檔字串
m._name_ 模組名稱
m._file_ 用於載入模組的檔案
m._path_ 完全限定包名,只在模組對象引用包時定義

[python]類型與對象

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.