Python_4_內置結構-元組-字符串

1. 元組概念

??元組(類型為 tuple)和列表十分相似,但是元組和字符串一樣是不可變的。

1.1. 元組的特點

  • 元組可以存儲一系列的值,使用 小括號 來定義,是一個 有序 的元素的集合。
  • 元組內的元素是 不可變
  • 當元組內嵌套列表這種引用類型時,元組的不可變表示的是嵌套的列表其內存地址不會變,當直接操作元組內嵌套的列表時,是可以進行修改的

1.2. 元組的定義

格式:

tuple()   # 工廠函數,用于創建并返回一個空元組
tuple(iterable)   # 使用可迭代對象的元素,來初始化一個元組

例子:

In : t=(1)    # 會認為 () 只是優先級

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 接受一個可迭代對象轉換為元組
In : tuple(range(1,7,2))
Out:(1, 3, 5)

1.3. 元組的訪問

??元組和列表在內存中的格式是相同的,都是線性順序結構,所以我們可以像列表一樣,使用 索引訪問 元組的元素,其中元組支持 正索引負索引,同樣不支持索引超界,會提示 IndexError

In : b =(1,2,3)

In : b[1]       
Out: 2

In : b[-1]
Out: 3

??當元組內嵌套的是列表這種引用類型時,你可以對列表內的數據進行修改,因為列表是可變的。

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 # 可以對嵌套的列表進行賦值操作 

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 來獲取和統計元組中的元素。

# 返回元組內匹配 value 的第一個元素的 index
T.index(value, [start, [stop]]) --> integer   

# 統計 value 在元組中出現的次數,不存在時,則返回 0
T.count(value) --> integer   

??注意:t.index 和 t.count 因為要遍歷列表所有元素,時間復雜度都是 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 不在元組中,則會報錯。
# 如果有多個,默認返回第一個(可以指定從哪個索引開始查找到某個索引結束,指定范圍區間)

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)    # 在指定的區間內查找
6

2. 命名元組

??命名元組是元組的子類,所以它也是無法進行修改的,它的特點是可以針元組的對字段進行命名。
??Tuple有一個兄弟,叫namedtuple。雖然都是tuple,功能更為強大。對于 namedtuple,你不必再通過索引值進行訪問,你可以把它看做一個字典通過名字進行訪問,只不過其中的值是不能改變的。

# 格式:
collections.namedtuple(typename, field_names, *, verbose=False, rename=False, module=None)   
# 返回一個新的元組子類,名為 typename 。
這個新的子類用于創建類元組的對象,可以通過域名來獲取屬性值,同樣也可以通過索引和迭代獲取值。

常用參數含義

  • typename: 一般和命名元組的名稱相同。
  • field_names: 可以是空白字符或逗號分隔的字段的字符串,可以是字段的列表

??namedtuple 存放在 collections 包中,所以需要先進行導入

>>> from collections import namedtuple    
>>> Point = namedtuple('Point', ['x', 'y'])  # 創建一個名為 Point 的命名元組類,其中含有兩個字段
>>> p = Point(11, 22)     # 創建一個實例,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 具有更好的可讀性,可以使代碼更易于維護。同時與字典相比,又更加的輕量和高效。但是有一點需要注意,就是 namedtuple 中的屬性都是不可變的。任何嘗試改變其屬性值的操作都是非法的。

In : from collections import namedtuple

In : Animal = namedtuple('animal', 'name age type')   
# 創建一個名為 Animal 的命名元組類,其中含有 name、age、type 三個字段

In : Tom = Animal(name='Tom', age=33, type='cat')   
# 創建一個實例并根據字段的關鍵字賦值。

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 中比較重要的數據類型,是以單引號 ' 或雙引號 " 括起來的任意文本,比如 '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 會被當作換行符進行打印
str4='hello\n world'    

# 前面使用了 r 對字符串進行整體轉義,所見即所得
str5=r'hello\n world'   

# 當然使用 \ 也可以對特殊符號進行脫義
str6='hellow\\nworld'   

# R 和 r 相同
str7=R'hello\nworld'    

3.1. 字符串的基本操作

??Python 的字符串是一個有序序列,所以他可以和列表一樣使用下標來訪問元素,但是由于它是不可變類型,所以無法對字符串中的某個字符進行修改,下面介紹下字符串的基本操作。

??單個字符并沒有特殊的類型,Python 中沒有字符的概念,嚴格來講,說字符是不準確的,字符串是由一個個長度為一的字符串組成的,雖然聽起來很別扭,但真的就是這樣!

3.1.1. 字符串的訪問

??字符串和列表是相似,都是順序的線性結構,所以它可以被索引,也可以被遍歷。字符串的索引類似數組的下標:

In : a = '1234567'

In : a[0] # 下標從 0 開始,0 表示第一個數
Out: '1'

In : a[3] # 表示第四個數
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 循環進行迭代
   ...:     print(i) 
   ...:     
1
2
3
4
5
6
7

In : list(a)# 可以被當作一個可迭代對象傳給 list,轉換為一個列表
Out: ['1', '2', '3', '4', '5', '6', '7']

3.1.2. 字符串的拼接

??當我們需要把多個字符串連接在一起,那么就需要對字符串進行拼接,python 提供了 join 方法,+ 號,以及 * 號,使我們方便的完成需求。

# 使用 join 對可迭代對象進行拼接,返回拼接后的字符串。
str.join(iterable) --> str   
  • join:str 可以為任意字符,包括空。可迭代對象中的元素必須是字符串類型
  • +:把兩個字符串直接進行連接,返回一個新的字符串
  • *:把字符串重復復制 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)      # 使用 - 進行拼接   
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. 字符串分割

??字符串中有關于字符分割功能的主要有兩類,split 系和 partition 系,他們分別適用于不用的場景。但用的比較多的是 split

  • split 系:將字符串按照分割符分隔成若干字符串,并返回列表
  • partition 系:將字符串按照分割符分割成 2 段,返回這 2 段和分隔符組成的三元組
# 從左至右對字符串 str 進行切割,分割符為 sep,默認為盡可能多的空字符,
# maxsplit 表示分割幾次,默認為 -1,全部進行分割,返回一個切割后的列表。
str.split(sep=None, maxsplit=-1) --> list of strings   

# 從左至右對字符串 str 進行切割,必須指定一個分割符 sep,返回一個三元組,
# 其中中間的元素為分割符,第一個和最后一個元素為按照分隔符分開后的前后兩個元素。
# 當分隔符無法對字符串進行分割時,返回的是 字符串,空,空,組成的三元組。
str.partition(sep) --> (head, sep, tail)   

# 例子:
In : s = "hello world I am Colin"

In : s.split() # 默認使用空格進行分割      
Out: ['hello', 'world', 'I', 'am', 'Colin']

In : s.split('o')      # 使用字母 o 進行分割
Out: ['hell', ' w', 'rld I am C', 'lin']   

In : s.split('o',1)    # 使用字母 o 進行分割,并且只分割 1 次    
Out: ['hell', ' world I am Colin']

In : s.split(sep='o',maxsplit=1)       # 也可以用關鍵字進行傳參
Out: ['hell', ' world I am Colin']

In : s.partition(' ')  # 使用 ' ' 進行分割,返回三元組
Out:('hello', ' ', 'world I am Colin')

In : s.partition('o')  # 用字母 o 進行分割,返回一個三元組
Out:('hell', 'o', ' world I am Colin')

# --------------------------------------------------------------
In : s = "helloworldIamColin" # 當分割符不存在時

In : s.split()     # 一定會返回一個列表,如果沒有被切分,那么會返回一個元素的列表
Out: ['helloworldIamColin']

# 一定會返回一個三元組,如果沒有被切分,那么會從字符串的最右邊切開,
# 形成一個三元組,和一個空字符組成的列表
In : s.partition(' ') 
Out:('helloworldIamColin', '', '')

In : s.partition('12')
Out:('helloworldIamColin', '', '')

??當然 split 類還包含了其他兩個方法:

# 功能與 split 相同,只不過從右往左切分
str.rsplit(sep=None, maxsplit=-1) --> list of strings   

# 按照行來切分,keepends 表示是否保留換行符,True 表示保留,False 表示不保留,默認為 False
str.splitlines([keepends]) --> list of strings    

# 例子:
In : s = 'I am struper Man' 

In : s.rsplit('a')     # 不指定分割次數,一般和 split 是一樣的效果
Out: ['I ', 'm struper M', 'n']

In : s.rsplit(sep='a',maxsplit=1)     #  當指分割 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() # 默認不保留分隔符
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函數,也是從右開始截取,需要注意的是,當分隔符無法對字符切分時,返回的是字符串,組成的三元組。

3.3. 字符串大小寫

  • upper:將字符串轉換為大寫字母
  • lower:將字符串轉換為
  • swapcase: 大小寫對調
  • capitalize:轉換成首字母大寫的單詞格式
  • title: 轉換成每個單詞首字母大寫的標題模式
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]):居中顯示,參數 width 表示整體寬度,fillchar 表示填充字符,默認填充字符為空格
  • ljust(width [, fillchar]):左對齊,width 表示整體寬度,fillchar 表示填充字符,默認填充字符為空格
  • rjust(width [, fillchar]):右對齊,width 表示整體寬度,fillchar 表示填充字符,默認填充字符為空格
  • zfill(width):居右顯示,參數 width 表示整體寬度,左邊用 0 進行填充
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. 字符串修改

??前面說字符串是不可變的,為什么這里又說字符串的修改?請繼續往下看

# 對字符串 str 進行查找,將指定的 old 字符串轉換為 new 字符串,count 表示替換的次數,默認表示重復替換所有
str.replace(old, new [, count]) --> str   

# 從字符串 str 兩端去除指定的字符集 chars 中的所有字符,
# chars 默認是所有空白字符(\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,默認是任意多個空白字符
Out: 'Hello World'

In : s.strip(' \n\tHd')   # 如果指定了 chars,那么就挨個使用 char 進行匹配去除
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') # 默認從頭到尾進行替換
Out: ' \n\t HellO WOrld \n\r'

In : s.replace('o', 'O', 1) # 指定替換 1 次      
Out: ' \n\t HellO World \n\r'  

3.6. 字符串查找

??我們有很多的時候要判斷關鍵字是否存在一個字符串中,那么我們就需要在字符串中 遍歷 查找,是否有匹配的字符串。python 提供了 findrfindindexcount 等函數用于完成需求。

 # 在指定的區間[start, end),從左至右,查找子串 sub 。找到返回索引,沒找到返回 -1
str.find(sub [, start [, end]]) --> int 

# 在指定的區間[start, end),從右至左,查找子串 sub 。找到返回索引,沒找到返回 -1
str.rfind(sub [, start [, end]]) --> int  

# 在指定的區間[start, end),從左至右,查找子串 sub 。找到返回索引,沒找到拋出異常 ValueError
str.index(sub [, start [, end]]) --> int  

# 在指定的區間[start, end),從右至左,查找子串 sub 。找到返回索引,沒找到拋出異常 ValueError
str.rindex(sub[, start[, end]]) --> int  

# 在指定的區間[start, end),從左至右,統計子串 sub 出現的次數,默認為整個字符串。沒有找到返回 0
str.count(sub [, start [, end]]) --> int  

??find 、index 和 count 方法由于是遍歷查找,所以時間復雜度都是 O(n), 會隨著字符串序列的數據規模的增大,而效率下降。


In : s = 'abc abc abc'    

In : s.find('a')  
Out: 0

In : s.find('a',1,-1)   # 指定區間,注意這里 -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 表示起始和終止,最好不要使用負數表示區間

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 的字符串對象提供了兩個函數,用于對字符串的起始位和結尾位來進行匹配,它們是 startswithendswith

# 在指定的區間[start, end),字符串是否是 prefix 開頭,默認為 0,即整個字符串 str, 返回 bool 類型。
str.startswith(prefix [, start [, end]]) --> bool       

# 在指定的區間[start, end),字符串是否是 suffix 結尾,默認為 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' 是否是結尾
Out: False     # 這里 -1 不包含,所以返回 False

In : s.endswith('bc',3,7) 
Out: True

In : s.startswith('abc')  
Out: True

In : s.endswith('bc')     
Out: True 

??除了判斷開始和結尾,Python 的字符串還提供了部分函數,用來判斷字符串內的元素類型,比如判斷字符串是否是純數字組成?是否是純字母組成等,這些函數的返回值統一都為bool型,可以作為if 語句的條件表達式

str.isalpha()      # 是否是字母
str.isalnum()      # 是否是字母和數字組成
str.isdigit()      # 是否全是十進制數字,int
str.isdecimal()    # 判斷是否是數字類型,包含 float,但不包含負數
str.islower()      # 判斷字符串是否全是小寫字母
str.isupper()      # 判斷字符串是否全是大寫字母
str.isspace()      # 是否是空白字符
str.isnumberic()   # 判斷是否是正整數
str.isidentifier() # 是否是一個合規的變量標識符

3.8. 字符串格式化

??字符串格式化是我們需要重點掌握的東西,在早期的 Python 中使用的是 C 語言風格的字符串替換,使用起來比較難看,不符合 python 的風格(純屬筆者猜測)。后來 Python 推薦使用內置的 format 函數來對字符串進行格式化。
??字符串格式化是一種拼接字符串輸出樣式的手段,更靈活方便,之前我們使用 join+ 來對字符串進行拼接。

  • join:只能使用分隔符,且要求被拼接的是可迭代對象且元素必須是字符串類型
  • +:使用起來比較方便,但是非字符串需要先轉換為字符串類型才可以進行拼接。

3.8.1. C 語言格式化

??在 Python 2.5 版本以前,只能使用 printf-style formatting 風格的 print 輸出,這種風格來自于 C 語言的 printf 函數,它有如下格式要求。(建議使用 format)

  1. 占位符:使用 % 和格式字符串組成,例如 %s%d 等。s 調用 str() ,r 會調用 repr()。所有對象都可以被這兩個轉換
  2. 占位符中還可以插入修飾字符,例如 %03d 表示打印 3 個位置,不夠的話,前面補 0
  3. format % value 格式字符串和被格式字符串之間使用 % 分割
  4. values 只能是一個對象,或是一個與格式字符串占位符數量相等的元組,或一個字典
In : 'I am %03d' % 20  # 表示 3 為數字,不夠的話高位補 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 為,小數點后精度為 2 位,當數字大時整體長度會被撐開,
# x 表示 16 進制,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() 函數來對字符串進行格式化。

# 函數的一般格式,{} 表示占位符,使用 format 中的參數進行傳遞
'{}{XXX}'.format(*args, **kwargs)  --> str   

??format 非常靈活,下面是基本使用方法說明:

  1. args 是可變位置參數,是一個元組
  2. kwargs 是可變關鍵字參數,是一個字典
  3. 花括號 表示 占位符
  4. {} 表示按照順序匹配 位置參數{n} 表示取位置參數中 索引為 n 的值
  5. {xxx} 表示在關鍵字參數中搜索名稱一致的值,kwargs 必須放在 可變位置參數的后面
  6. {{}} 表示打印花括號
# 按照位置格式化,第一個元素給第一個括號,第二個元素給第二個括號      
In : '{}:{}'.format('10.0.0.13','8888')       
Out: '10.0.0.13:8888'    # 

# 命名格式化,host 表示只獲取關鍵字為 host 的值來填充,
# 其他沒有指定關鍵字的占位符,則按照位置參數進行傳遞,并格式化顯示     
In : '{host}:{}:{}'.format('10.0.0.13','8888',host='Colin')   
Out: 'Colin:10.0.0.13:8888'

# 訪問元素的方式進行字符串格式化(不常用)
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. 對齊

??字符串還提供了多種的對齊方式,便于我們對輸出內容做一個簡單的優化。

  • <:左對齊(默認)
  • >:右對齊
  • ^: 居中對齊

??對齊方式需要在占位符內使用 :號 進行分割

#   打印字符串,這個字符串占 5 位,默認靠左對齊,其他位使用空格填充
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 進行填充 
In : '{:0^5}'.format('c')     
Out: '00c00'

# 居中對齊,其它位使用 * 進行填充
In : '{:*^5}'.format('c')
Out: '**c**'

??當填充符為數字的時候,可以與寬度寫在一起,比如 '{:0<5}'.format('3') 可以寫成 '{:<05}'.format('3'),而 '{:0^5}'.format('3') 可以寫成 '{:^05}'.format('3')

3.8.4. 浮點數與進制

??雖然用的不多,還是這里還是舉例說明一下進制和浮點數的使用方法(注意寬度可以被撐破)

  • d: 表示十進制
  • x: 表示十六進制
  • o: 表示八進制
  • b: 表示二進制
  • F: 表示浮點型
  • #: 表示添加進制前綴
  • *[1,2,3]: 表示把列表中的元素解構出來:*[1,2,3] --> 1,2,3
# 輸出時轉換進制
In : "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42)
Out: 'int: 42; hex: 2a; oct: 52; bin: 101010'

# 加上進制前綴
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)# 默認按照字符串打印 
Out: '1.5518455739153598' 
 
In : "{:f}".format(1.5518455739153598)      # f 表示填充位為小數,小數是有精度的
Out: '1.551846' 
 
In : "{:02f}".format(1.5518455739153598)    # 表示小數的長度為 2,但是如果小數的位數超過 2,會直接撐開   
Out: '1.551846' 
 
In : "{:10f}".format(1.5518455739153598)    # 表示小數的長度為 10,默認是右對齊 
Out: '  1.551846' 
 
In : "{:<10f}".format(1.5518455739153598)   # 左對齊 
Out: '1.551846  ' 
 
In : "{:.2f}".format(1.5518455739153598)    # .2f 表示小數點后取兩位的浮點型 
Out: '1.55' 
 
In : "{:3.2f}".format(123456.123456)   # 總長 3 位,小數點后保留 2 位,若整數位長度超出,則撐開 
Out: '123456.12' 
 
In : "{:2.2%}".format(1.5518455739153598)   # 使用百分比顯示
Out: '155.18%'

4. bytes、bytearray

??Python3 引入兩個新類型:

  1. bytes:不可變字節序列
  2. bytearray:字節數組,可變

字符串與 bytes

  • 字符串是字符組成的有序序列,字符可以使用編碼來理解
  • bytes 是字節組成的有序的不可變序列
  • bytearray 是字節組成的有序的可變序列

編碼與解碼

  • 字符串按照不同的字符集編碼 encode 返回字節序列 bytes
    • str.encode(encoding='utf-8', errors='strict') --> bytes
  • 字節序列按照不同的字符集解碼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當歌'

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當歌'

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當歌'

4.1. ASCII

??ASCII(American Standard Code for Information Interchange,美國信息交換標準代碼)是基于拉丁字母的一套單字節編碼系統,編碼范圍從 0 到 127

?? 熟記常用字符的 ASCII 碼_

Char Decimal(十進制) Hex(十六進制)
\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) 指定字節的 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 (從一個字節序列或者 buffer 復制出一個新的不可變的 bytes 對象)
  • 使用 b 前綴定義
    • 只允許基本 ASCII 使用字符形式 b'abc9'
    • 使用 16 進制表示 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 進制的形式,'6162 6a 6b',空格將被忽略
In : bytes.fromhex('6162 09 6a 6b00')
Out: b'ab\tjk\x00'
  • hex():返回16進制表示的字符串
In : 'abc'.encode().hex()
Out: '616263'
  • 索引:b'abcdef'[2] 返回該字節對應的數,int類型
In : b'abcdef'[2]
Out: 99

4.4. bytearray 定義

  • bytearray() 空 bytearray
  • bytearray(int) 指定字節的 bytearray,被 0 填充
  • bytearray(iterable_of_ints) --> bytearray ([0,255]的 int 組成的可迭代對象)
  • bytearray(string, encoding[, errors]) --> bytearray (近似 string.encode(),不過返回可變對象)
  • bytearray(bytes_or_buffer) 從一個字節序列或者 buffer 復制出一個新的可變的 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 進制的形式,'6162 6a 6b',空格將被忽略
In : bytearray.fromhex('6162 09 6a 6b00')
Out: bytearray(b'ab\tjk\x00')
  • hex():返回 16 進制表示的字符串
In : bytearray('abc'.encode()).hex()
Out: '616263'
  • 索引:bytearray(b'abcdef')[2] 返回該字節對應的數,int類型
  • append(int) 尾部追加一個元素
  • insert(index, int) 在指定索引位置插入元素
  • extend(iterable_of_ints) 將一個可迭代的整數集合追加到當前 bytearray
  • pop(index=-1) 從指定索引上移除元素,默認從尾部移除
  • remove(value) 找到第一個 value 移除,找不到拋 ValueError 異常
  • 注意:上述方法若需要使用 int 類型,值在 [0, 255]
  • clear() 清空 bytearray
  • reverse() 翻轉 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. 字節序

  • 大端模式,big-endian;小端模式,little-endian
  • Intel X86 CPU使用小端模式
  • 網絡傳輸更多使用大端模式
  • Windows、Linux使用小端模式
  • Mac OS使用大端模式
  • Java虛擬機是大端模式
LSB_MSB.png

??C2 認為是尾巴。尾巴放在低地址端,就是小端模式 LSB:Least Significant Bit,最低有效位;尾巴放在大地址端,就是大端模式 MSB:Most Significant Bit,最高有效位。

4.7. int 和 bytes

  • int.from_bytes(bytes, byteorder)
    • 將一個字節數組表示成整數
  • int.to_bytes(length, byteorder)
    • byteorder 字節序
    • 將一個整數表達成一個指定長度的字節數組
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 都屬于線性結構,線性結構其他的特點還有:

  • 可迭代 (for ... in)
  • len() 可以獲取長度
  • 可以通過下標進行訪問(有序)
  • 都可以被切片

??那什么是切片?我們說通過索引區間訪問線性結構一段數據的方法就叫做切片,需要注意的是 切片操作會引起內存復制,當對一個過于龐大的線性結構進行切片的時候,請慎重考慮內存使用率的問題。切片的表達方式和基本特點有:

  1. 格式:sequence[start:stop:[,step=1]] 返回 [start, stop, step=1)前閉后開 子序列。
  2. 支持負索引。注意方向問題
  3. 當 start 為 0 或 stop 為末尾時,可以省略。[:] 表示復制原線性結構數據,等效于 copy() 方法(注意當對象為 list 時,屬于 淺 copy
  4. 超過上界(右邊界),則取到末尾;超過下界(左邊界),則取到開頭。
  5. 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 左邊,所以沒辦法取出,如果實在想要倒著取,那么需要使用負步長
Out: '' 

In : a[10:-100:-1]   # 負步長就可以形成開閉區間,注意是從起始位開始按照 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')

注意:

  • 切片并不會對原數據進行修改,會返回新的數據
  • 如果不是用變量接受,那么就會被標記為待回收
  • 由于是新生成的數據,所以 內存地址 和原數據內存地址 一定不相同

5.1. 切片賦值

??既然可以進行切片,那么就會引申出來,是否可以進行切片賦值,什么是切片賦值?它該如何表示?下面以列表例進行說明。

  • 切片操作寫在等號的左邊
  • 被插入的可迭代對象在等號右邊
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

仔細看上面示例代碼會發現幾個問題:

  1. lst[1:3] = 1 切片賦值會失敗,因為 切片賦值 賦的值必須是 一個可迭代對象
  2. 切片賦值改變了原數據
  3. 字符串、元組這類不可變的元素,無法使用切片賦值

??當我們使用切片時,它會產生新的內存地址來存放生成的新列表,但是如果把切片操作放在賦值操作的左邊時,那么就相當于引用了原列表的 [start:stop] 的索引,這種操作是不會生成新的內存空間的,換句話來講就是直接對原列表進行了 list.insert 操作.

In : lst 
Out: [0, 100, 200, 3, 4, 5, 6, 7, 8, 9]

In : lst[1:3] = []          # 這種操作相當于在 [1:3) 的位置上進行了 list.remove

In : lst 
Out: [0, 3, 4, 5, 6, 7, 8, 9]

In : lst[1:3] = [100,200]   # 這種操作相當于在 [1:3) 的位置上進行了 list.insert

In : lst 
Out: [0, 100, 200, 5, 6, 7, 8, 9]

??我們知道 list 在進行 insert 和 remove 時的時間復雜度都是 O(n),在進行切片賦值時的時間復雜度也是一樣,所以建議不要使用這種方法。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容