序列
序列是一種有序的集合,就是諸如數組、鏈表或者對外呈現類似結構的數據結構,特點就是擁有一串的元素,并且這些元素的存放是有順序的。
python內置多種序列類型,對所有這些序列類型,有一些通用的操作方法可以調用(見后面'序列的一般操作'章節),同時各種序列類型各自還有一些特有方法。
字符串
字符串str是一種字符序列,每個元素是一個字符,python沒有單個字符類型,只有字符串類型,一個字符也是字符串。
python對字符串的支持非常強大,使用起來很方便。
字符串字面量
字符串字面量(literal)就是字符串常量的書寫方式,包括單引號、雙引號、三引號,raw字符多種方式
-
單引號
用單引號把一串字符包起來,就構成一個字符串,特殊字符需要用轉義,轉義方法和c語言基本類似。>>> string = 'life is short, you need python' >>> print(string) #print是內置打印函數,類似c語言的printf,注意print函數默認會自動添加換行 life is short, you need python >>> >>> string = 'life is short, \nyou need python\n' >>> print(string) life is short, you need python >>> >>> len(string) #內置函數len可以獲取字符串長度即字符個數,注意不像c語言的字符串,python字符串是不需要'\0'結尾的 32
-
雙引號
雙引號和單引號的用法類似,但雙引號里可以包含單引號,單引號里可以包含雙引號而不需要轉義。>>> string = "life is short, 'you need python'" >>> print(string) life is short, 'you need python' >>> >>> string = 'life is short, "you need python"' >>> print(string) life is short, "you need python" >>>
-
三引號
三引號支持多行, 換行、tab等特殊字符可以直接輸入,所見即所得。三引號字符串也同樣可以使用轉義字符。>>> string = '''life is short, ... \tyou need python''' # 在python命令中換行時,會顯示‘...’, 表示可以繼續輸入 >>> print(string) life is short, you need python >>>
-
raw字符串
raw字符串用于禁止轉義, 用小寫r和和大寫R作前綴,可以和前面的幾種引號組合>>> string = r'life is short, \nyou need python\n' >>> print(string) life is short, \nyou need python\n >>>
格式化字符串
字符串的格式化不需要調用函數,直接使用 % 實現
>>> string = 'string = %s' % 'abc'
>>> print(string)
string = abc
>>>
>>> string = '%s = %d' % ('abc', 123) #多個參數要使用括號
>>> print(string)
abc = 123
字符串編碼
字符在內存中是用16位unicode表示的,因此字符可以不只是ascii字符,還可以包括中文、日文、德文等世界上幾乎所有的語言字符。可以用內置函數 ord 獲取單個字符的unicode值,用內置函數 chr 把單個unicode值轉成單個字符,還可以用16進制unicode值直接書寫字符串。
>>> ord('a')
97
>>> chr(97)
'a'
>>>
>>> ord('我')
25105
>>> chr(25105)
'我'
>>>
>>> string = '\u6211\u662f\u8c01'
>>> print(string)
我是誰
>>>
字符串在python內存中的編碼方式是unicode,每個字符固定2字節編碼,處理速度快但浪費存儲空間。一般各種文檔為了節省存儲空間,使用的編碼不是直接用unicode,而是用諸如ASCII(純英文)、國標GB2312(漢字)、UTF-8(通用)等其他編碼,這些編碼對不同字符采用不同長度的編碼,可節省存儲空間。
python解析器解析代碼時,默認是以UTF-8編碼來讀取的,因此若非有特殊原因,python代碼文件建議用UTF-8編碼保存。
字符串通過 encode 方法把unicode編碼轉成其他編碼方式,生成字節串,生成的字節串可以用于傳輸或寫到文件中。
注意:原始的字符串并沒有被改變,返回的字節串是新生成的
>>> 'who am i'.encode(encoding="utf-8")
b'who am i'
>>>
>>> 'who am i'.encode(encoding="ascii")
b'who am i'
>>>
>>> 'who am i, 我是誰'.encode(encoding="utf-8")
b'who am i, \xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81'
>>>
>>> 'who am i, 我是誰'.encode(encoding="gb2312")
b'who am i, \xce\xd2\xca\xc7\xcb\xad'
>>>
編碼后的字節串可以通過 decode 方法解出字符串,還可以通過內置函數 str 解出字符串
注意:原始的字節串并沒有被改變,返回的字符串是新生成的
>>> b'who am i'.decode(encoding="utf-8")
'who am i'
>>>
>>> b'who am i'.decode(encoding="ascii")
'who am i'
>>> b'who am i, \xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81'.decode(encoding="utf-8")
'who am i, 我是誰'
>>>
>>> b'who am i, \xce\xd2\xca\xc7\xcb\xad'.decode(encoding="gb2312")
'who am i, 我是誰'
>>>
>>> str(b'who am i, \xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81', encoding="utf-8")
'who am i, 我是誰'
>>>
字符串方法
字符串內置很多方法(字符串其實是對象,python里一切皆對象),以下羅列出常用的方法并簡要說明,需要用到時可以再查閱python文檔。
-
統計
方法 說明 str.count(sub[, start[, end]]) 統計子字符串 -
編碼
方法 說明 str.encode(encoding="utf-8", errors="strict") 編碼,轉成字節串bytes -
查找和替換
方法 說明 str.startswith(prefix[, start[, end]]) 檢查字符串前綴 str.endswith(suffix[, start[, end]]) 檢查字符串后綴 str.find(sub[, start[, end]]) 正序(即左查找)查找字符串,返回第一個找到的位置,沒找到則返回-1 str.rfind(sub[, start[, end]]) 右查找 str.index(sub[, start[, end]]) 和find的唯一區別是,沒找到拋出ValueError異常 str.rindex(sub[, start[, end]]) 和rfind的唯一區別是,沒找到拋出ValueError異常 str.replace(old, new[, count]) 替換字符串 str.expandtabs(tabsize=8) 把tabs轉成空格,注意并不是每個tab都轉成tabsize個空格,而是跟列對齊有關 -
格式化
方法 說明 str.format(*args, **kwargs) 格式化 str.format_map(mapping) 格式化,參數是個字典 -
檢查字符串
方法 說明 str.isalnum() 是否由字母和數字組成 str.isalpha() 是否只由字母組成 str.isdecimal() 是否是10進制數 str.isdigit() 是否只包含‘0’~‘9’ str.isidentifier() 是否是有效的Python標識符 str.islower() 是否全是小寫 str.isnumeric() 是否是數字,可以不只包括數字字符‘0’~‘9’, 甚至可以包括漢字‘一’、‘二’、‘三’等 str.isprintable() 是否全是可打印字符 str.isspace() 是否全是空白字符 str.istitle() 是否是標題,標題的每個單詞的首字母大寫 str.isupper() 是否全是大寫 -
對齊處理
方法 說明 str.center(width[, fillchar]) 居中處理 str.ljust(width[, fillchar]) 左對齊, 并使用空格填充至長度width str.rjust(width[, fillchar]) 右對齊, 并使用空格填充至長度width str.zfill(width) 右對齊, 并使用‘0’填充至長度width -
大小寫處理
方法 說明 str.capitalize() 把首字母變成大寫,其余變成小寫 str.casefold() 變成小寫,不僅僅針對英文字母,也包括其他字母,如德文 str.lower() 轉為全小寫 str.upper() 轉為全大寫 str.swapcase() 翻轉大小寫 str.title() 標題化,每個單詞首字母大寫 -
去頭去尾處理
方法 說明 str.lstrip([chars]) 去頭 str.rstrip([chars]) 去尾 str.strip([chars]) 去頭去尾 -
映射處理
方法 說明 static str.maketrans(x[, y[, z]]) 創建字符映射表, 是個靜態方法 str.translate(table) 根據映射表,轉換字符串 -
連接和分割處理
方法 說明 str.join(iterable) 用字符串作為分隔符,把序列中的元素連接起來 str.partition(sep) 正序分離字符串,sep為第一個 str.rpartition(sep) 反序分離字符串,sep為最后一個 str.split(sep=None, maxsplit=-1) 正序分割字符串,可以指定最多分割次數,從左到右查找sep str.rsplit(sep=None, maxsplit=-1) 反序分割字符串,可以指定最多分割次數 str.splitlines([keepends]) 按行分割
二進制字節串
二進制字節串有兩種類型,bytes和bytearray,bytes是不可變的,一旦初始化就不可修改,對其修改都是生成新字節串,bytearray的元素可以修改,并且長度也是可變的。
-
bytes字面量
bytes常量用 b 前綴加上ascii字符串或小于256的16進制或8進制數表示>>> a = b'\x10\x11\x12' #每個元素用2位16進制數表示 >>> >>> a = b'\20\21\022\347' #每個元素用2或3位8進制數表示, 個人建議不要用8進制,比如b'\378', 最后的8不是8進制數的一部分,暈吧? >>> >>> a = b'abc' #每個元素用1個asciii字符表示 >>> >>> a = b'\x10\x11\x12abc' #混合使用16進制數和ascii字符 >>> >>> len(a) #獲取字節串長度 6
-
字節串創建
>>> a = bytes() >>> a b'' #不是None >>> >>> a = bytearray() >>> a bytearray(b'') #不是None >>> >>> a = bytes(10) >>> a b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' #元素默認為0 >>> >>> a = bytearray(10) >>> a bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') ##元素默認為0 >>> >>> a = bytes(range(10)) >>> a b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t' >>>
實際上,bytes或bytearray可以通過bytes(obj)或bytearray(obj)創建,只要obj支持buffer protocol。至于什么是buffer protocol可以查閱python規范
-
字節串方法
str的方法幾乎都有對應的bytes和bytearray方法,這里只列出幾個特殊的。>>> bytes.fromhex('2Ef0F1f2') # b'.\xf0\xf1\xf2' >>> >>> b'.\xf0\xf1\xf2'.hex() '2ef0f1f2' >>>
列表和元組
列表和元組的每個元素可以是不同的數據類型,元組是不可變的,一旦初始化就不可更改,列表是可變的。
-
創建
列表用中括號或內置函數list創建,元組用圓括號或內置函數tuple創建。>>> a = [] # 空列表 >>> a [] >>> b = () # 空元組 >>> b () >>> >>> a = (1,2,'aaa', None) # 初始化值 >>> a (1, 2, 'aaa', None) >>> >>> b = [1,2,'aaa', None] # 初始化值 >>> b [1, 2, 'aaa', None] >>> >>> a = [1, 2, [3, 4], (5, 6)] # 元素甚至可以是列表或元組 >>> a [1, 2, [3, 4], (5, 6)]
-
列表推導
即List Comprehensions,是指創建列表時,列表的每一個元素通過一個表達式來推導,表達式一般是個for循環, 可以帶if表達式,還可以是多重循環。
使用列表推導可以精簡代碼,減少代碼行,但不建議寫太復雜的推導表達式,可讀性太差。
注意元組沒有類似推導,如果寫成'元組推導',實際生成的不是元組,而是另一種東西,叫生成器(generator),后面會講。[x*x for x in range(1, 11)] # 列表為:[1x1, 2x2, 3x3, ..., 10x10] [x*x for x in range(1, 11) if x % 2 == 0] # 列表為:[2x2, 4x4, ..., 10x10], 只有偶數部分 a = (1, 2, 3) b = (4, 5, 6) [x*y for x in a for y in b] # 列表為:[4, 5, 6, 8, 10, 12, 12, 15, 18] (x*x for x in range(1, 11)) # 生成的不是元組,是生成器
列表排序
列表內建排序 sort(, key=None, reverse=None)* 方法,使用 '<' 比較元素,排序是在原列表上直接操作的,如果某個元素比較失敗,則整個排序失敗,并且已經被修改的元素不會還原。
參數 key:一個函數,用來預處理每個比較 key, 比如 key=str.lower
參數 reverse:是否反序,True則反序。
元組沒有排序方法,因為元組是不可變的。
range
range用來生成一個數序列, 一般用在 for 循環中,range是不可變的,一旦生成后就不可更改,range的每個元素是在訪問到時才生成的,因此就算是一個很大整數的range也不會占用太多內存。這點和元組不同,也是為什么有元組了為何還需要range類型的原因。
>>> range(10)
range(0, 10)
>>> a = range(10)
>>> a
range(0, 10)
>>>
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
>>> list(range(0, 10, 2))
[0, 2, 4, 6, 8]
序列的一般操作
字符串、字節串、元組、列表等序列類型有一些通用的操作。
-
通用操作
操作 說明 x in s 檢查序列中是否有元素等于x,有為True,否則為False x not in s 以上面剛好相反 s + t 連接兩個序列, 注意:如果是不可變序列,則返回新的序列,不是修改原序列 s[i] 第i個元素, i可以為負數,-1表示最后一個,-2為倒數第二個,以此類推 s[i:j] 子序列切片:第i到第j-1元素, i,j可以為負數,-1表示最后一個,-2為倒數第二個,以此類推 len(s) 序列長度 s * n or n * s 相當于序列重復n次 s[i] 第i個元素 s[i:j] 子序列切片:第i到第j-1元素 s[i:j:k] 子序列切片:第i到第j-1元素,間隔為k min(s) 元素最小值 max(s) 元素最大值 s.index(x[, i[, j]]) 從[i:j]中第一個值等于x的元素的索引 s.count(x) 值等于x的元素個數 -
可變序列特有的操作
可變序列是指序列的元素在是可以修改的,列表是可變序列,字符串、字節串、元組、range是不可變序列操作 說明 s[i] = x 第i個元素改寫為x s[i:j] = t 用t[0:j-i]替換s[i:j],t不一定是序列,只要是可迭代對象就行 del s[i:j] 刪除第i到第j-1元素,也可以寫成 s[i:j] = [] s[i:j:k] = t 跟s[i:j] = t類似,指定間隔 del s[i:j:k] 跟del s[i:j]類似,指定間隔 s.append(x) 把x加入到序列的尾部 s.clear() 清空序列s 也可以寫成 del s[:] s.copy() 淺拷貝 也可以寫成 s[:] s.extend(t) or s += t 把序列t加入到序列s的尾部 s *= n 相當于序列s重復n次,直接修改原序列s s.insert(i, x) 把x插入到i位置 也可以寫成 s[i:i] = [x] s.pop([i]) 彈出i元素,即返回i元素,并從序列中刪除i元素 s.remove(x) 刪除序列中等于x的元素,如果有多個,則只刪除第一個 s.reverse() 第一個元素和最后一個對調,第二個和倒數第二個對調,以此類推