標籤:建立對象 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]類型與對象