1. 元組概念
??元組(類型為 tuple)和列表十分相似,但是元組和字符串一樣是不可變的。
1.1. 元組的特點
- 元組可以存儲一系列的值,使用
小括號來定義,是一個有序的元素的集合。 - 元組內(nèi)的元素是
不可變的 - 當(dāng)元組內(nèi)嵌套列表這種引用類型時,元組的不可變表示的是嵌套的列表其內(nèi)存地址不會變,當(dāng)直接操作元組內(nèi)嵌套的列表時,是可以進(jìn)行修改的
1.2. 元組的定義
格式:
tuple() # 工廠函數(shù),用于創(chuàng)建并返回一個空元組
tuple(iterable) # 使用可迭代對象的元素,來初始化一個元組
例子:
In : t=(1) # 會認(rèn)為 () 只是優(yōu)先級
In : type(t)
Out: int
In : t=(1,)
In : type(t)
Out: tuple # tuple 表示元組類型
# 引用其他元組
In : a=(1,2,3)
In : t=('123',a)
In : t
Out:('123',(1, 2, 3))
# 通過索引只引用某一個值
In : t=('123', a[1])
In : t
Out:('123', 2)
# tuple 接受一個可迭代對象轉(zhuǎn)換為元組
In : tuple(range(1,7,2))
Out:(1, 3, 5)
1.3. 元組的訪問
??元組和列表在內(nèi)存中的格式是相同的,都是線性順序結(jié)構(gòu),所以我們可以像列表一樣,使用 索引訪問 元組的元素,其中元組支持 正索引 和 負(fù)索引,同樣不支持索引超界,會提示 IndexError。
In : b =(1,2,3)
In : b[1]
Out: 2
In : b[-1]
Out: 3
??當(dāng)元組內(nèi)嵌套的是列表這種引用類型時,你可以對列表內(nèi)的數(shù)據(jù)進(jìn)行修改,因為列表是可變的。
In : lst = (1, 2, [1, 2])
In : a = lst * 3
In : a
Out:(1, 2, [1, 2], 1, 2, [1, 2], 1, 2, [1, 2])
In : a[2][0] = 100 # 可以對嵌套的列表進(jìn)行賦值操作
In : a
Out:(1, 2, [100, 2], 1, 2, [100, 2], 1, 2, [100, 2])
In : a[3] = 100 # 修改指向的地址是不被允許的
---------------------------------------------------------------------------
TypeError Traceback(most recent call last)
<ipython-input-47-2b62bbdeb061> in <module>
----> 1 a[3] = 100
TypeError: 'tuple' object does not support item assignment
1.4. 元組的查詢
??我們通過使用元組的 index 方法和 count 來獲取和統(tǒng)計元組中的元素。
# 返回元組內(nèi)匹配 value 的第一個元素的 index
T.index(value, [start, [stop]]) --> integer
# 統(tǒng)計 value 在元組中出現(xiàn)的次數(shù),不存在時,則返回 0
T.count(value) --> integer
??注意:t.index 和 t.count 因為要遍歷列表所有元素,時間復(fù)雜度都是 O(n), 隨著列表的元素增加,而效率下降
In : a=('1','2','3')
In : a.count("4") # 不存在,返回 0
Out: 0
In : a.count("1")
Out: 1
# a.index(value) 用來返回 value 在元組中的索引,如果 value 不在元組中,則會報錯。
# 如果有多個,默認(rèn)返回第一個(可以指定從哪個索引開始查找到某個索引結(jié)束,指定范圍區(qū)間)
In : a=('1','2','3')
In : a.index('1')
Out: 0
In : a.index('3')
Out: 2
In : a=('1','2','3')
In : a.index('4') # 不存在,就會報錯
---------------------------------------------------------------------------
ValueError Traceback(most recent call last)
<ipython-input-58-dca64b8e9162> in <module>
----> 1 a.index('4')
ValueError: tuple.index(x): x not in tuple
>>> t1
('a', 'b', 'a', 'b', 'a', 'b', 'a', 'b')
>>> t1.index('a',5,7) # 在指定的區(qū)間內(nèi)查找
6
2. 命名元組
??命名元組是元組的子類,所以它也是無法進(jìn)行修改的,它的特點是可以針元組的對字段進(jìn)行命名。
??Tuple有一個兄弟,叫namedtuple。雖然都是tuple,功能更為強大。對于 namedtuple,你不必再通過索引值進(jìn)行訪問,你可以把它看做一個字典通過名字進(jìn)行訪問,只不過其中的值是不能改變的。
# 格式:
collections.namedtuple(typename, field_names, *, verbose=False, rename=False, module=None)
# 返回一個新的元組子類,名為 typename 。
這個新的子類用于創(chuàng)建類元組的對象,可以通過域名來獲取屬性值,同樣也可以通過索引和迭代獲取值。
常用參數(shù)含義
-
typename: 一般和命名元組的名稱相同。 -
field_names: 可以是空白字符或逗號分隔的字段的字符串,可以是字段的列表
??
namedtuple存放在 collections 包中,所以需要先進(jìn)行導(dǎo)入
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y']) # 創(chuàng)建一個名為 Point 的命名元組類,其中含有兩個字段
>>> p = Point(11, 22) # 創(chuàng)建一個實例,11 會傳遞給 x,22 會傳遞給 y。
>>> p[0] + p[1] # 可以通過索引訪問
33
>>> p.x + p.y # 也可以通過字段名訪問
33
>>> p.x = 33# 無法修改,將報錯
---------------------------------------------------------------------------
AttributeError Traceback(most recent call last)
<ipython-input-63-dac7085722b7> in <module>
----> 1 p.x = 33
AttributeError: can't set attribute
??Namedtuple 比普通 tuple 具有更好的可讀性,可以使代碼更易于維護(hù)。同時與字典相比,又更加的輕量和高效。但是有一點需要注意,就是 namedtuple 中的屬性都是不可變的。任何嘗試改變其屬性值的操作都是非法的。
In : from collections import namedtuple
In : Animal = namedtuple('animal', 'name age type')
# 創(chuàng)建一個名為 Animal 的命名元組類,其中含有 name、age、type 三個字段
In : Tom = Animal(name='Tom', age=33, type='cat')
# 創(chuàng)建一個實例并根據(jù)字段的關(guān)鍵字賦值。
In : Tom
Out: animal(name='Tom', age=33, type='cat')
In : print(Tom)
animal(name='Tom', age=33, type='cat')
In : type(Tom)
Out: __main__.animal
In : Tom.type# 可以通過字段名訪問
Out: 'cat'
In : Tom.age = 3 # 和 tuple 一樣,無法修改值,將報錯
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-9-63d4b4478930> in <module>
----> 1 Tom.age = 3
AttributeError: can't set attribute
3. 字符串
??字符串是 Python 中比較重要的數(shù)據(jù)類型,是以單引號 ' 或雙引號 " 括起來的任意文本,比如 'abc',"xyz" 等等。請注意,'' 或 "" 本身只是一種表示方式,不是字符串的一部分,因此,字符串 'abc' 只有 a,b,c 這 3 個字符。如果 ' 本身也是一個字符,那就可以用雙引號 "" 括起來,比如 "I'm OK" 包含的字符是 I,',m,空格,O,K 這 6 個字符。有三種方法定義字符串:單引號,雙引號,三引號,需要注意的是字符串是不可變對象,并且從 Python3 起,字符串就是Unicode 類型。
??定義方式:
str1='this is string'
str2="this is string"
# 也可以是三個雙引號,三個引號可以多行注釋但是不能單雙混合,三重引號除了能定義字符串以外,還可以表示注釋。
str3='''this is string'''
# 在 print 打印字符串的時候 \n 會被當(dāng)作換行符進(jìn)行打印
str4='hello\n world'
# 前面使用了 r 對字符串進(jìn)行整體轉(zhuǎn)義,所見即所得
str5=r'hello\n world'
# 當(dāng)然使用 \ 也可以對特殊符號進(jìn)行脫義
str6='hellow\\nworld'
# R 和 r 相同
str7=R'hello\nworld'
3.1. 字符串的基本操作
??Python 的字符串是一個有序序列,所以他可以和列表一樣使用下標(biāo)來訪問元素,但是由于它是不可變類型,所以無法對字符串中的某個字符進(jìn)行修改,下面介紹下字符串的基本操作。
??單個字符并沒有特殊的類型,Python 中沒有字符的概念,嚴(yán)格來講,說字符是不準(zhǔn)確的,字符串是由一個個長度為一的字符串組成的,雖然聽起來很別扭,但真的就是這樣!
3.1.1. 字符串的訪問
??字符串和列表是相似,都是順序的線性結(jié)構(gòu),所以它可以被索引,也可以被遍歷。字符串的索引類似數(shù)組的下標(biāo):
In : a = '1234567'
In : a[0] # 下標(biāo)從 0 開始,0 表示第一個數(shù)
Out: '1'
In : a[3] # 表示第四個數(shù)
Out: '4'
In : a[1] = 100 # 字符串無法修改
---------------------------------------------------------------------------
TypeError Traceback(most recent call last)
<ipython-input-3-8554a2b011c3> in <module>
----> 1 a[1] = 100
TypeError: 'str' object does not support item assignment
In : for i in a: # 可以被 for 循環(huán)進(jìn)行迭代
...: print(i)
...:
1
2
3
4
5
6
7
In : list(a)# 可以被當(dāng)作一個可迭代對象傳給 list,轉(zhuǎn)換為一個列表
Out: ['1', '2', '3', '4', '5', '6', '7']
3.1.2. 字符串的拼接
??當(dāng)我們需要把多個字符串連接在一起,那么就需要對字符串進(jìn)行拼接,python 提供了 join 方法,+ 號,以及 * 號,使我們方便的完成需求。
# 使用 join 對可迭代對象進(jìn)行拼接,返回拼接后的字符串。
str.join(iterable) --> str
-
join:str 可以為任意字符,包括空??傻鷮ο笾械脑乇仨毷?code>字符串類型 -
+:把兩個字符串直接進(jìn)行連接,返回一個新的字符串 -
*:把字符串重復(fù)復(fù)制 N 次,返回一個新的字符串
In : str1
Out: ['h', 'e', 'l', 'l', 'o']
In : ''.join(str1)
Out: 'hello'
In : str2 = ''.join(str1)
In : str2
Out: 'hello'
In : '-'.join(str1) # 使用 - 進(jìn)行拼接
Out: 'h-e-l-l-o'
In : str2 * 2
Out: 'hellohello'
In : str2 + str2
Out: 'hellohello'
In : lst = [['1','2'], '1', '3']
In : ''.join(lst) # lst 的第 0 個元素是列表,不是字符串,無法拼接,會報錯
---------------------------------------------------------------------------
TypeError Traceback(most recent call last)
<ipython-input-19-58ac5d2512ec> in <module>
----> 1 ''.join(lst)
TypeError: sequence item 0: expected str instance, list found
3.2. 字符串分割
??字符串中有關(guān)于字符分割功能的主要有兩類,split 系和 partition 系,他們分別適用于不用的場景。但用的比較多的是 split。
-
split系:將字符串按照分割符分隔成若干字符串,并返回列表 -
partition系:將字符串按照分割符分割成 2 段,返回這 2 段和分隔符組成的三元組
# 從左至右對字符串 str 進(jìn)行切割,分割符為 sep,默認(rèn)為盡可能多的空字符,
# maxsplit 表示分割幾次,默認(rèn)為 -1,全部進(jìn)行分割,返回一個切割后的列表。
str.split(sep=None, maxsplit=-1) --> list of strings
# 從左至右對字符串 str 進(jìn)行切割,必須指定一個分割符 sep,返回一個三元組,
# 其中中間的元素為分割符,第一個和最后一個元素為按照分隔符分開后的前后兩個元素。
# 當(dāng)分隔符無法對字符串進(jìn)行分割時,返回的是 字符串,空,空,組成的三元組。
str.partition(sep) --> (head, sep, tail)
# 例子:
In : s = "hello world I am Colin"
In : s.split() # 默認(rèn)使用空格進(jìn)行分割
Out: ['hello', 'world', 'I', 'am', 'Colin']
In : s.split('o') # 使用字母 o 進(jìn)行分割
Out: ['hell', ' w', 'rld I am C', 'lin']
In : s.split('o',1) # 使用字母 o 進(jìn)行分割,并且只分割 1 次
Out: ['hell', ' world I am Colin']
In : s.split(sep='o',maxsplit=1) # 也可以用關(guān)鍵字進(jìn)行傳參
Out: ['hell', ' world I am Colin']
In : s.partition(' ') # 使用 ' ' 進(jìn)行分割,返回三元組
Out:('hello', ' ', 'world I am Colin')
In : s.partition('o') # 用字母 o 進(jìn)行分割,返回一個三元組
Out:('hell', 'o', ' world I am Colin')
# --------------------------------------------------------------
In : s = "helloworldIamColin" # 當(dāng)分割符不存在時
In : s.split() # 一定會返回一個列表,如果沒有被切分,那么會返回一個元素的列表
Out: ['helloworldIamColin']
# 一定會返回一個三元組,如果沒有被切分,那么會從字符串的最右邊切開,
# 形成一個三元組,和一個空字符組成的列表
In : s.partition(' ')
Out:('helloworldIamColin', '', '')
In : s.partition('12')
Out:('helloworldIamColin', '', '')
??當(dāng)然 split 類還包含了其他兩個方法:
# 功能與 split 相同,只不過從右往左切分
str.rsplit(sep=None, maxsplit=-1) --> list of strings
# 按照行來切分,keepends 表示是否保留換行符,True 表示保留,F(xiàn)alse 表示不保留,默認(rèn)為 False
str.splitlines([keepends]) --> list of strings
# 例子:
In : s = 'I am struper Man'
In : s.rsplit('a') # 不指定分割次數(shù),一般和 split 是一樣的效果
Out: ['I ', 'm struper M', 'n']
In : s.rsplit(sep='a',maxsplit=1) # 當(dāng)指分割 1 次時,會從右邊開始切分
Out: ['I am struper M', 'n']
In : s = 'hello\nworld\rI\nam\r\nColin'
In : print(s)
hello
Iorld
am
Colin
In : s.splitlines() # 默認(rèn)不保留分隔符
Out: ['hello', 'world', 'I', 'am', 'Colin']
In : s.splitlines(True) # True 表示保留分隔符
Out: ['hello\n', 'world\r', 'I\n', 'am\r\n', 'Colin']
??partition 和 split 相似,也有個rpartition函數(shù),也是從右開始截取,需要注意的是,當(dāng)分隔符無法對字符切分時,返回的是空,空,字符串,組成的三元組。
3.3. 字符串大小寫
-
upper:將字符串轉(zhuǎn)換為大寫字母 -
lower:將字符串轉(zhuǎn)換為 -
swapcase: 大小寫對調(diào) -
capitalize:轉(zhuǎn)換成首字母大寫的單詞格式 -
title: 轉(zhuǎn)換成每個單詞首字母大寫的標(biāo)題模式
In : s = 'hElLo wORld i aM Colin'
In : s.upper()
Out: 'HELLO WORLD I AM Colin'
In : s.lower()
Out: 'hello world i am Colin'
In : s.swapcase()
Out: 'HeLlO WorLD I Am Colin'
In : s.capitalize()
Out: 'Hello world i am colin'
In : s.title()
Out: 'Hello World I Am Colin'
3.4. 字符串排版
-
center(width [,fillchar]):居中顯示,參數(shù) width 表示整體寬度,fillchar 表示填充字符,默認(rèn)填充字符為空格 -
ljust(width [, fillchar]):左對齊,width 表示整體寬度,fillchar 表示填充字符,默認(rèn)填充字符為空格 -
rjust(width [, fillchar]):右對齊,width 表示整體寬度,fillchar 表示填充字符,默認(rèn)填充字符為空格 -
zfill(width):居右顯示,參數(shù) width 表示整體寬度,左邊用 0 進(jìn)行填充
In : a
Out: 'abc'
In : a.ljust(20,'-')
Out: 'abc-----------------'
In : a.rjust(20,'-')
Out: '-----------------abc'
In : a.center(30,'-')
Out: '-------------abc--------------'
In : a.zfill(20)
Out: '00000000000000000abc'
3.5. 字符串修改
??前面說字符串是不可變的,為什么這里又說字符串的修改?請繼續(xù)往下看
# 對字符串 str 進(jìn)行查找,將指定的 old 字符串轉(zhuǎn)換為 new 字符串,count 表示替換的次數(shù),默認(rèn)表示重復(fù)替換所有
str.replace(old, new [, count]) --> str
# 從字符串 str 兩端去除指定的字符集 chars 中的所有字符,
# chars 默認(rèn)是所有空白字符(\n,\r\n,\r,\t 等等都包含)
str.strip([chars]) --> str
str.lstrip([chars]) --> str # 從左開始
str.rstrip([chars]) --> str # 從右開始
注意:replace 的替換是
生成一個新的字符串, 而不是就地修改原字符串,這也是字符串修改的原理
In : s = ' \n\t Hello World \n\r'
In : s.strip() # ' 不指定 chars,默認(rèn)是任意多個空白字符
Out: 'Hello World'
In : s.strip(' \n\tHd') # 如果指定了 chars,那么就挨個使用 char 進(jìn)行匹配去除
Out: 'ello World \n\r'
In : s.strip(' \n\rHd')
Out: '\t Hello Worl'
In : s.replace('World', 'Colin')
Out: ' \n\t Hello Colin \n\r'
In : s.replace('o', 'O') # 默認(rèn)從頭到尾進(jìn)行替換
Out: ' \n\t HellO WOrld \n\r'
In : s.replace('o', 'O', 1) # 指定替換 1 次
Out: ' \n\t HellO World \n\r'
3.6. 字符串查找
??我們有很多的時候要判斷關(guān)鍵字是否存在一個字符串中,那么我們就需要在字符串中 遍歷 查找,是否有匹配的字符串。python 提供了 find、rfind、index、count 等函數(shù)用于完成需求。
# 在指定的區(qū)間[start, end),從左至右,查找子串 sub 。找到返回索引,沒找到返回 -1
str.find(sub [, start [, end]]) --> int
# 在指定的區(qū)間[start, end),從右至左,查找子串 sub 。找到返回索引,沒找到返回 -1
str.rfind(sub [, start [, end]]) --> int
# 在指定的區(qū)間[start, end),從左至右,查找子串 sub 。找到返回索引,沒找到拋出異常 ValueError
str.index(sub [, start [, end]]) --> int
# 在指定的區(qū)間[start, end),從右至左,查找子串 sub 。找到返回索引,沒找到拋出異常 ValueError
str.rindex(sub[, start[, end]]) --> int
# 在指定的區(qū)間[start, end),從左至右,統(tǒng)計子串 sub 出現(xiàn)的次數(shù),默認(rèn)為整個字符串。沒有找到返回 0
str.count(sub [, start [, end]]) --> int
??find 、index 和 count 方法由于是遍歷查找,所以時間復(fù)雜度都是 O(n), 會隨著字符串序列的數(shù)據(jù)規(guī)模的增大,而效率下降。
In : s = 'abc abc abc'
In : s.find('a')
Out: 0
In : s.find('a',1,-1) # 指定區(qū)間,注意這里 -1 表示最后 1 位,但是不包含 -1,類似于 [1,-1)
Out: 4
In : s.find('a',-1,-15) # end 超出范圍,沒找到返回 -1
Out: -1
In : s.rfind('a')
Out: 8
In : s.rfind('a', 2, -1)
Out: 8
In : s.rfind('c', 2, -1)
Out: 6
In : s.rfind('c', 2, -100)
Out: -1 # end 超出范圍,沒找到返回 -1,start,end 表示起始和終止,最好不要使用負(fù)數(shù)表示區(qū)間
In : s.index('a')
Out: 0
In : s.rindex('a', 2) # 從索引 2 至最右邊,從右往左查找
Out: 4
In : s.index('e') # 沒找到,直接報異常
---------------------------------------------------------------------------
ValueError Traceback(most recent call last)
<ipython-input-25-90b1c28da6f0> in <module>
----> 1 s.index('e')
ValueError: substring not found
In : s.count('a')
Out: 3
3.7. 字符串判斷
??Python 的字符串對象提供了兩個函數(shù),用于對字符串的起始位和結(jié)尾位來進(jìn)行匹配,它們是 startswith 和 endswith。
# 在指定的區(qū)間[start, end),字符串是否是 prefix 開頭,默認(rèn)為 0,即整個字符串 str, 返回 bool 類型。
str.startswith(prefix [, start [, end]]) --> bool
# 在指定的區(qū)間[start, end),字符串是否是 suffix 結(jié)尾,默認(rèn)為 0,即整個字符串 str, 返回 bool 類型。
str.endswith(suffix [, start [, end]]) --> bool
??例子:
In : s
Out: 'abc abc abc'
In : s.startswith('bc',1,-1) # 從 s 的 [1,-1) 開始判斷 'bc' 是否是開頭
Out: True
In : s.endswith('bc',2,-1) # 從 s 的 [2,-1) 開始匹配 'bc' 是否是結(jié)尾
Out: False # 這里 -1 不包含,所以返回 False
In : s.endswith('bc',3,7)
Out: True
In : s.startswith('abc')
Out: True
In : s.endswith('bc')
Out: True
??除了判斷開始和結(jié)尾,Python 的字符串還提供了部分函數(shù),用來判斷字符串內(nèi)的元素類型,比如判斷字符串是否是純數(shù)字組成?是否是純字母組成等,這些函數(shù)的返回值統(tǒng)一都為bool型,可以作為if 語句的條件表達(dá)式。
str.isalpha() # 是否是字母
str.isalnum() # 是否是字母和數(shù)字組成
str.isdigit() # 是否全是十進(jìn)制數(shù)字,int
str.isdecimal() # 判斷是否是數(shù)字類型,包含 float,但不包含負(fù)數(shù)
str.islower() # 判斷字符串是否全是小寫字母
str.isupper() # 判斷字符串是否全是大寫字母
str.isspace() # 是否是空白字符
str.isnumberic() # 判斷是否是正整數(shù)
str.isidentifier() # 是否是一個合規(guī)的變量標(biāo)識符
3.8. 字符串格式化
??字符串格式化是我們需要重點掌握的東西,在早期的 Python 中使用的是 C 語言風(fēng)格的字符串替換,使用起來比較難看,不符合 python 的風(fēng)格(純屬筆者猜測)。后來 Python 推薦使用內(nèi)置的 format 函數(shù)來對字符串進(jìn)行格式化。
??字符串格式化是一種拼接字符串輸出樣式的手段,更靈活方便,之前我們使用 join 和 + 來對字符串進(jìn)行拼接。
-
join:只能使用分隔符,且要求被拼接的是可迭代對象且元素必須是字符串類型 -
+:使用起來比較方便,但是非字符串需要先轉(zhuǎn)換為字符串類型才可以進(jìn)行拼接。
3.8.1. C 語言格式化
??在 Python 2.5 版本以前,只能使用 printf-style formatting 風(fēng)格的 print 輸出,這種風(fēng)格來自于 C 語言的 printf 函數(shù),它有如下格式要求。(建議使用 format)
- 占位符:使用
% 和格式字符串組成,例如%s,%d等。s 調(diào)用str(),r 會調(diào)用repr()。所有對象都可以被這兩個轉(zhuǎn)換 - 占位符中還可以插入修飾字符,例如
%03d表示打印 3 個位置,不夠的話,前面補 0 -
format % value格式字符串和被格式字符串之間使用 % 分割 -
values只能是一個對象,或是一個與格式字符串占位符數(shù)量相等的元組,或一個字典
In : 'I am %03d' % 20 # 表示 3 為數(shù)字,不夠的話高位補 0
Out: 'I am 020'
In : 'I like %s' % 'Python' # 字符串格式化
Out: 'I like Python'
In : 'I am %s' % 20 # 20 會被 str 作用后,傳遞給字符串
Out: 'I am 20'
# 3.2f 表示最長 3 為,小數(shù)點后精度為 2 位,當(dāng)數(shù)字大時整體長度會被撐開,
# x 表示 16 進(jìn)制,02X 表示兩位顯示,高位補 0
In : '%3.2f%%,0x%x,0X%02X' % (89.7654,10,15)
Out: '89.77%,0xa,0X0F'
In : "I am %-5d" % 20
Out: 'I am 20 '
In : "I am %5d" % 20
Out: 'I am 20'
3.8.2. format 格式化
??Python 中推崇使用 format() 函數(shù)來對字符串進(jìn)行格式化。
# 函數(shù)的一般格式,{} 表示占位符,使用 format 中的參數(shù)進(jìn)行傳遞
'{}{XXX}'.format(*args, **kwargs) --> str
??format 非常靈活,下面是基本使用方法說明:
-
args是可變位置參數(shù),是一個元組 -
kwargs是可變關(guān)鍵字參數(shù),是一個字典 -
花括號表示占位符 -
{}表示按照順序匹配位置參數(shù),{n}表示取位置參數(shù)中索引為 n 的值 -
{xxx}表示在關(guān)鍵字參數(shù)中搜索名稱一致的值,kwargs必須放在可變位置參數(shù)的后面 -
{{}}表示打印花括號
# 按照位置格式化,第一個元素給第一個括號,第二個元素給第二個括號
In : '{}:{}'.format('10.0.0.13','8888')
Out: '10.0.0.13:8888' #
# 命名格式化,host 表示只獲取關(guān)鍵字為 host 的值來填充,
# 其他沒有指定關(guān)鍵字的占位符,則按照位置參數(shù)進(jìn)行傳遞,并格式化顯示
In : '{host}:{}:{}'.format('10.0.0.13','8888',host='Colin')
Out: 'Colin:10.0.0.13:8888'
# 訪問元素的方式進(jìn)行字符串格式化(不常用)
In : '{0[0]}:{0[1]}'.format(['10.0.0.13','8888'])
Out: '10.0.0.13:8888'
# 由于 p 對象含有 x 和 y 屬性,所以可以在字符串格式化時直接引用
In : from collections import namedtuple
In : Point = namedtuple('_Point',['x','y'])
In : p = Point(4,5)
In : print('{' + '{0.x},{0.y}'.format(p) + '}')
Out: '{4,5}'
3.8.3. 對齊
??字符串還提供了多種的對齊方式,便于我們對輸出內(nèi)容做一個簡單的優(yōu)化。
-
<:左對齊(默認(rèn)) -
>:右對齊 -
^: 居中對齊
??對齊方式需要在占位符內(nèi)使用
:號進(jìn)行分割
# 打印字符串,這個字符串占 5 位,默認(rèn)靠左對齊,其他位使用空格填充
In : '{:5}'.format('c')
Out: 'c '
# > 表示右對齊
In : '{:>5}'.format('c')
Out: ' c'
# 字符串站 5 位,左對齊,其他位使用 0 填充(可以簡寫為 '{:<05}')
In : '{:0<5}'.format('c')
Out: 'c0000'
In : '{:0>5}'.format('c')
Out: '0000c'
# > 表示右對齊,其他位用 * 填充
In : '{:*>5}'.format('c')
Out: '****c'
# 居中對齊,其它位使用 0 進(jìn)行填充
In : '{:0^5}'.format('c')
Out: '00c00'
# 居中對齊,其它位使用 * 進(jìn)行填充
In : '{:*^5}'.format('c')
Out: '**c**'
??當(dāng)填充符為數(shù)字的時候,可以與寬度寫在一起,比如
'{:0<5}'.format('3')可以寫成'{:<05}'.format('3'),而'{:0^5}'.format('3')可以寫成'{:^05}'.format('3')
3.8.4. 浮點數(shù)與進(jìn)制
??雖然用的不多,還是這里還是舉例說明一下進(jìn)制和浮點數(shù)的使用方法(注意寬度可以被撐破)
-
d: 表示十進(jìn)制 -
x: 表示十六進(jìn)制 -
o: 表示八進(jìn)制 -
b: 表示二進(jìn)制 -
F: 表示浮點型 -
#: 表示添加進(jìn)制前綴 -
*[1,2,3]: 表示把列表中的元素解構(gòu)出來:*[1,2,3]-->1,2,3
# 輸出時轉(zhuǎn)換進(jìn)制
In : "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42)
Out: 'int: 42; hex: 2a; oct: 52; bin: 101010'
# 加上進(jìn)制前綴
In : "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42)
Out: 'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010'
In : octets = [10,0,0,13]
In : '{:02X}{:02X}{:02X}{:02X}'.format(*octets)
Out: '0A00000D'
In : '{:02X}-{:02X}-{:02X}-{:02X}'.format(*octets)
Out: '0A-00-00-0D'
# ----------------------------------------------------------
In : "{}".format(3**0.4)# 默認(rèn)按照字符串打印
Out: '1.5518455739153598'
In : "{:f}".format(1.5518455739153598) # f 表示填充位為小數(shù),小數(shù)是有精度的
Out: '1.551846'
In : "{:02f}".format(1.5518455739153598) # 表示小數(shù)的長度為 2,但是如果小數(shù)的位數(shù)超過 2,會直接撐開
Out: '1.551846'
In : "{:10f}".format(1.5518455739153598) # 表示小數(shù)的長度為 10,默認(rèn)是右對齊
Out: ' 1.551846'
In : "{:<10f}".format(1.5518455739153598) # 左對齊
Out: '1.551846 '
In : "{:.2f}".format(1.5518455739153598) # .2f 表示小數(shù)點后取兩位的浮點型
Out: '1.55'
In : "{:3.2f}".format(123456.123456) # 總長 3 位,小數(shù)點后保留 2 位,若整數(shù)位長度超出,則撐開
Out: '123456.12'
In : "{:2.2%}".format(1.5518455739153598) # 使用百分比顯示
Out: '155.18%'
4. bytes、bytearray
??Python3 引入兩個新類型:
- bytes:不可變字節(jié)序列
- bytearray:字節(jié)數(shù)組,可變
字符串與 bytes
- 字符串是字符組成的有序序列,字符可以使用編碼來理解
- bytes 是字節(jié)組成的有序的不可變序列
- bytearray 是字節(jié)組成的有序的可變序列
編碼與解碼
- 字符串按照不同的字符集編碼 encode 返回字節(jié)序列 bytes
- str.encode(encoding='utf-8', errors='strict') --> bytes
- 字節(jié)序列按照不同的字符集解碼decode返回字符串
- bytes.decode(encoding="utf-8", errors="strict") --> str
- bytearray.decode(encoding="utf-8", errors="strict") --> str
In : '李'.encode()
Out: b'\xe6\x9d\x8e'
In : b'\xe6\x9d\x8e'.decode()
Out: '李'
In : b"\x41\x61".decode()
Out: 'Aa'
# bytearray 和 bytes 不一樣的地方在于,bytearray 是可變的。
In : str1 = '人生苦短,Python當(dāng)歌'
In : b1 = bytearray(str1.encode())
In : b1
Out: bytearray(b'\xe4\xba\xba\xe7\x94\x9f\xe8\x8b\xa6\xe7\x9f\xad\xef\xbc\x8cPython\xe5\xbd\x93\xe6\xad\x8c')
In : type(b1)
Out: bytearray
In : b1.decode()
Out: '人生苦短,Python當(dāng)歌'
In : b1[:6] = bytearray('生命'.encode())
In : b1
Out: bytearray(b'\xe7\x94\x9f\xe5\x91\xbd\xe8\x8b\xa6\xe7\x9f\xad\xef\xbc\x8cPython\xe5\xbd\x93\xe6\xad\x8c')
In : b1.decode()
Out: '生命苦短,Python當(dāng)歌'
4.1. ASCII
??ASCII(American Standard Code for Information Interchange,美國信息交換標(biāo)準(zhǔn)代碼)是基于拉丁字母的一套單字節(jié)編碼系統(tǒng),編碼范圍從 0 到 127
?? 熟記常用字符的 ASCII 碼_
| Char | Decimal(十進(jìn)制) | Hex(十六進(jìn)制) |
|---|---|---|
\t 水平制表符 |
9 | 09 |
\n 換行符 |
10 | 0A |
\v 垂直制表符 |
11 | 0B |
\f 換頁符 |
12 | 0C |
\r 回車符 |
13 | 0D |
(space) 空格 |
32 | 20 |
0~9 |
48~57 | 30~39 |
A-Z |
65~90 | 41~5A |
a-z |
97~122 | 61~7A |
4.2. bytes 定義
- bytes() 空 bytes
- bytes(int) 指定字節(jié)的 bytes,被 0 填充
- bytes(iterable_of_ints) --> bytes ( 由[0,255] 的 int 組成的可迭代對象 )
- bytes(string, encoding[, errors]) --> bytes ( 等價于 string.encode() )
- bytes(bytes_or_buffer) --> immutable copy of bytes_or_buffer (從一個字節(jié)序列或者 buffer 復(fù)制出一個新的不可變的 bytes 對象)
- 使用 b 前綴定義
- 只允許基本 ASCII 使用字符形式 b'abc9'
- 使用 16 進(jìn)制表示 b"\x41\x61"
In : bytes()
Out: b''
In : bytes(5)
Out: b'\x00\x00\x00\x00\x00'
In : bytes(range(3))
Out: b'\x00\x01\x02'
4.3. bytes 操作
- 和 str 類型類似,都是不可變類型,所以方法很多都一樣。只不過 bytes 的方法,輸入是 bytes ,輸出是 bytes
In : b'abcdef'.replace(b'f',b'k')
Out: b'abcdek'
In : b'abc'.find(b'b')
Out: 1
- 類方法
bytes.fromhex(string):string 必須是 2 個字符的 16 進(jìn)制的形式,'6162 6a 6b',空格將被忽略
In : bytes.fromhex('6162 09 6a 6b00')
Out: b'ab\tjk\x00'
- hex():返回16進(jìn)制表示的字符串
In : 'abc'.encode().hex()
Out: '616263'
- 索引:b'abcdef'[2] 返回該字節(jié)對應(yīng)的數(shù),int類型
In : b'abcdef'[2]
Out: 99
4.4. bytearray 定義
- bytearray() 空 bytearray
- bytearray(int) 指定字節(jié)的 bytearray,被 0 填充
- bytearray(iterable_of_ints) --> bytearray ([0,255]的 int 組成的可迭代對象)
- bytearray(string, encoding[, errors]) --> bytearray (近似 string.encode(),不過返回可變對象)
- bytearray(bytes_or_buffer) 從一個字節(jié)序列或者 buffer 復(fù)制出一個新的可變的 bytearray 對象
- 注意,b 前綴定義的類型是 bytes 類型
In : bytearray()
Out: bytearray(b'')
In : bytearray(6)
Out: bytearray(b'\x00\x00\x00\x00\x00\x00')
In : bytearray(range(3))
Out: bytearray(b'\x00\x01\x02')
4.5. bytearray 操作
- 和 bytes 類型的方法相同
In : bytearray(b'abcdef').replace(b'f',b'k')
Out: bytearray(b'abcdek')
In : bytearray(b'abc').find(b'b')
Out: 1
- 類方法
bytearray.fromhex(string):string 必須是 2 個字符的 16 進(jìn)制的形式,'6162 6a 6b',空格將被忽略
In : bytearray.fromhex('6162 09 6a 6b00')
Out: bytearray(b'ab\tjk\x00')
- hex():返回 16 進(jìn)制表示的字符串
In : bytearray('abc'.encode()).hex()
Out: '616263'
- 索引:
bytearray(b'abcdef')[2]返回該字節(jié)對應(yīng)的數(shù),int類型 - append(int) 尾部追加一個元素
- insert(index, int) 在指定索引位置插入元素
- extend(iterable_of_ints) 將一個可迭代的整數(shù)集合追加到當(dāng)前 bytearray
- pop(index=-1) 從指定索引上移除元素,默認(rèn)從尾部移除
- remove(value) 找到第一個 value 移除,找不到拋 ValueError 異常
- 注意:上述方法若需要使用 int 類型,值在 [0, 255]
- clear() 清空 bytearray
- reverse() 翻轉(zhuǎn) bytearray,就地修改
In : bytearray(b'abcdef')[2]
Out: 99
In : b = bytearray()
In : b.append(97)
In : b.append(99)
In : b.insert(1,98)
In : b.extend([65,66,67])
In : print(b)
bytearray(b'abcABC')
In : b.remove(66)
In : print(b)
bytearray(b'abcAC')
In : b.pop()
Out: 67
In : print(b)
bytearray(b'abcA')
In : b.reverse()
In : print(b)
bytearray(b'Acba')
In : b.clear()
In : print(b)
bytearray(b'')
4.6. 字節(jié)序
- 大端模式,big-endian;小端模式,little-endian
- Intel X86 CPU使用小端模式
- 網(wǎng)絡(luò)傳輸更多使用大端模式
- Windows、Linux使用小端模式
- Mac OS使用大端模式
- Java虛擬機是大端模式

??C2 認(rèn)為是尾巴。尾巴放在低地址端,就是
小端模式LSB:Least Significant Bit,最低有效位;尾巴放在大地址端,就是大端模式MSB:Most Significant Bit,最高有效位。
4.7. int 和 bytes
-
int.from_bytes(bytes, byteorder)- 將一個字節(jié)數(shù)組表示成整數(shù)
-
int.to_bytes(length, byteorder)- byteorder 字節(jié)序
- 將一個整數(shù)表達(dá)成一個指定長度的字節(jié)數(shù)組
In : i = int.from_bytes(b'abc', 'big')
In : print(i, hex(i))
6382179 0x616263
In : print(i.to_bytes(3, 'big'))
b'abc'
In : b1 = bytearray()
In : b1.append(97)
In : b1
Out: bytearray(b'a')
In : b1.extend(range(98, 100))
In : b1
Out: bytearray(b'abc')
5. 切片
??列表、元組、字符串、bytes、bytearray 都屬于線性結(jié)構(gòu),線性結(jié)構(gòu)其他的特點還有:
- 可迭代 (for ... in)
- len() 可以獲取長度
- 可以通過下標(biāo)進(jìn)行訪問(有序)
- 都可以被切片
??那什么是切片?我們說通過索引區(qū)間訪問線性結(jié)構(gòu)一段數(shù)據(jù)的方法就叫做切片,需要注意的是 切片操作會引起內(nèi)存復(fù)制,當(dāng)對一個過于龐大的線性結(jié)構(gòu)進(jìn)行切片的時候,請慎重考慮內(nèi)存使用率的問題。切片的表達(dá)方式和基本特點有:
- 格式:
sequence[start:stop:[,step=1]]返回[start, stop, step=1)的前閉后開子序列。 - 支持負(fù)索引。注意方向問題
- 當(dāng) start 為 0 或 stop 為末尾時,可以省略。
[:]表示復(fù)制原線性結(jié)構(gòu)數(shù)據(jù),等效于 copy() 方法(注意當(dāng)對象為 list 時,屬于淺 copy) - 超過上界(右邊界),則取到末尾;超過下界(左邊界),則取到開頭。
- start 一定要在 stop 的左邊
In : a = 'hello world , My name is Colin'
In : a[2:-1]
Out: 'llo world , My name is Coli'
In : a[2:]
Out: 'llo world , My name is Colin'
In : a[-100:]
Out: 'hello world , My name is Colin'
In : a[10:-100] # stop 位置在 start 左邊,所以沒辦法取出,如果實在想要倒著取,那么需要使用負(fù)步長
Out: ''
In : a[10:-100:-1] # 負(fù)步長就可以形成開閉區(qū)間,注意是從起始位開始按照 step 取的(所以會倒序排列返回)
Out: 'dlrow olleh'
In : list('My Name is ColinLee')[4:20:2] # 列表類型,步長為 2
Out: ['a', 'e', 'i', ' ', 'o', 'i', 'L', 'e']
In : tuple('My Name is ColinLee')[4:20:2] # 元組類型,步長為 2
Out: ('a', 'e', 'i', ' ', 'o', 'i', 'L', 'e')
注意:
- 切片并不會對原數(shù)據(jù)進(jìn)行修改,會返回新的數(shù)據(jù)
- 如果不是用變量接受,那么就會被標(biāo)記為待回收
- 由于是新生成的數(shù)據(jù),所以
內(nèi)存地址和原數(shù)據(jù)內(nèi)存地址一定不相同。
5.1. 切片賦值
??既然可以進(jìn)行切片,那么就會引申出來,是否可以進(jìn)行切片賦值,什么是切片賦值?它該如何表示?下面以列表例進(jìn)行說明。
- 切片操作寫在等號的左邊
- 被插入的可迭代對象在等號右邊
In : lst = list(range(10))
In : lst
Out: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In : lst[1:3]
Out: [1, 2]
In : lst[1:3] = 1 # 只能針對可迭代對象賦值
---------------------------------------------------------------------------
TypeError Traceback(most recent call last)
<ipython-input-82-7fef59136c7e> in <module>
----> 1 lst[1:3] = 1
TypeError: can only assign an iterable
In : lst[1:3] = [100,200]
In : lst
Out: [0, 100, 200, 3, 4, 5, 6, 7, 8, 9]
In : a
Out: [0, 4]
In : b = list()
In : b[:] = a
In : b
Out: [0, 4]
In : c = a
In : print(id(a), id(b), id(c))
1935299790344 1935291542600 1935299790344
仔細(xì)看上面示例代碼會發(fā)現(xiàn)幾個問題:
- lst[1:3] = 1 切片賦值會失敗,因為
切片賦值賦的值必須是一個可迭代對象 - 切片賦值改變了原數(shù)據(jù)
- 字符串、元組這類不可變的元素,無法使用切片賦值
??當(dāng)我們使用切片時,它會產(chǎn)生新的內(nèi)存地址來存放生成的新列表,但是如果把切片操作放在賦值操作的左邊時,那么就相當(dāng)于引用了原列表的
[start:stop]的索引,這種操作是不會生成新的內(nèi)存空間的,換句話來講就是直接對原列表進(jìn)行了list.insert操作.
In : lst
Out: [0, 100, 200, 3, 4, 5, 6, 7, 8, 9]
In : lst[1:3] = [] # 這種操作相當(dāng)于在 [1:3) 的位置上進(jìn)行了 list.remove
In : lst
Out: [0, 3, 4, 5, 6, 7, 8, 9]
In : lst[1:3] = [100,200] # 這種操作相當(dāng)于在 [1:3) 的位置上進(jìn)行了 list.insert
In : lst
Out: [0, 100, 200, 5, 6, 7, 8, 9]
??我們知道 list 在進(jìn)行 insert 和 remove 時的時間復(fù)雜度都是 O(n),在進(jìn)行切片賦值時的時間復(fù)雜度也是一樣,所以建議不要使用這種方法。