# MicroPython on ESP8266 (二) : 數值型態測試
MicroPython 教學文件 :
# MicroPython tutorial for ESP8266 (官方教學)
# http://docs.micropython.org/en/latest/micropython-esp8266.pdf
# http://docs.micropython.org/en/latest/pyboard/library/usocket.html#class-socket
# http://docs.micropython.org/en/v1.8.7/esp8266/library/usocket.html#module-usocket
# https://gist.github.com/xyb/9a4c8d7fba92e6e3761a (驅動程式)
MicroPython 教學文件 :
# MicroPython tutorial for ESP8266 (官方教學)
# http://docs.micropython.org/en/latest/micropython-esp8266.pdf
# http://docs.micropython.org/en/latest/pyboard/library/usocket.html#class-socket
# http://docs.micropython.org/en/v1.8.7/esp8266/library/usocket.html#module-usocket
# https://gist.github.com/xyb/9a4c8d7fba92e6e3761a (驅動程式)
Python 常用的序列型別有下列三種, 均繼承自 sequence 這個抽象型別, 它們的元素都是照順序存放的 :
- list (串列)
- tuple (元組)
- str (字串)
Python 有五種容器型別 : str, list, tuple, dict, 以及 set, 容器皆以 cell 為基本儲存單位, 除了 str 只能儲存 unicode 字元外, 其他四種都可以儲存不同型態 (異質) 的資料.
一. 字串 (str) :
1. 字串的建立 :
Python 3 的字串全面採用 Unicode 表示, 不必像 Python 2.x 那樣在處理 Unicode 字串時還要在前面冠一個 "u". Python 的字串使用成對的單引號或雙引號括起來, 例如 :
>>> "Hello World!"
'Hello World!'
>>> 'Hello World'
'Hello World'
>>> print("Hello World!")
Hello World!
>>> print('Hello World!')
Hello World!
如果字串中必須用到引號本身, 可以用另一種引號作為外引號括起來, 例如 :
>>> print("It's mine")
It's mine
>>> print("he said:'Go!'") #雙引號當外引號
he said:'Go!'
>>> print('he said:"Go!"') #單引號當外引號
he said:"Go!"
或者可以使用跳脫 (Escape) 字元 "\" 來轉義 (改變字元原有意義), 原本引號是字串的開始或結束字元, 前面加倒斜線將其改變為引號本身 :
>>> print('It\'s mine')
It's mine
>>> print('he said:\'Go!\'')
he said:'Go!'
>>> print("he said:\"Go!\"")
he said:"Go!"
Python 的跳脫字元包括 \' 與 \" 總共有 12 個如下 :
這些跳脫字元大都是 ASCII 字元編碼中的控制字元, 例如 :
>>> print('123\\456\n\r789') #印出倒斜線與跳行
123\456
789
>>> print('123\\456\n789') #只用 \n 即可跳行
123\456
789
>>> print('123\\456\r789') #\r 只有回車功能, 不會跳行
789\456
可見跳行可以用 \n\r 或者單用 \n 皆可, \r 只是像打字機那樣的單純回車 (carrage return) 而已, 所以上面最後一例 \r 會讓列印位置回到最前面印出 789, 就把原先已經印出的 123 蓋掉了.
>>> print('123\t456\t789') #水平定位
123 456 789
>>> print('123\v456\v789') #垂直定位
123
456
789
換頁字元 \f 會刷新頁面 (換上新頁), 從最上面開始列印, 響鈴字元 \a 會讓系統發出噹的一聲, 而退位字元會往回一格列印, 蓋掉前一字元, 例如下面範例中開頭的 \f 會換新頁, 從第一列開始印出 0, 接著響鈴並印出 123, 再響鈴後印出 456, 然後 \b 會倒退一格到 6 的位置, 印出 789, 所以 6 就被蓋掉不見了 :
>>> print('\f0\a123\a456\b789')
012345789
下面範例測試 8 進位與 16 進位的跳脫字元表示法, 字母 A 的 ASCII 碼以 8 進制表示為 101, 以 16 進制表示則為 41. 注意 16 進制必須用小寫 x, 不可用大寫 X :
>>> '\101'
'A'
>>> '\x41'
'A'
Python 有兩個內建函數用來處理 ASCII 碼 :
注意, ord() 的參數只能傳入一個字元, 且傳回值是 10 進位的 ASCII 碼, 要取得 8 進制與 16 進制 ASCII 碼須使用 oct() 與 hex() 轉換, 例如 :
>>> ord('A'), oct(ord('A')), hex(ord('A'))
(65, '0o101', '0x41')
>>> ord('\n'), oct(ord('\n')), hex(ord('\n'))
(10, '0o12', '0xa')
>>> chr(65), chr(0o101), chr(0x41)
('A', 'A', 'A')
>>> ord('AB') #ord 只能傳入一個字元
Traceback (most recent call last):
File "<stdin>", line 1, inTypeError: ord() expected a character, but string of length 2 found
當字串中含有大量跳脫字元時會使可讀性變差, 這時可以用 Python 的原始字串 (raw string) 來表示, 在字串的開頭引號前面加個 r 就表示引號內為原始字串, 例如 :
2. 長字串的跨行串接
1. 字串的建立 :
Python 3 的字串全面採用 Unicode 表示, 不必像 Python 2.x 那樣在處理 Unicode 字串時還要在前面冠一個 "u". Python 的字串使用成對的單引號或雙引號括起來, 例如 :
>>> "Hello World!"
'Hello World!'
>>> 'Hello World'
'Hello World'
>>> print("Hello World!")
Hello World!
>>> print('Hello World!')
Hello World!
如果字串中必須用到引號本身, 可以用另一種引號作為外引號括起來, 例如 :
>>> print("It's mine")
It's mine
>>> print("he said:'Go!'") #雙引號當外引號
he said:'Go!'
>>> print('he said:"Go!"') #單引號當外引號
he said:"Go!"
或者可以使用跳脫 (Escape) 字元 "\" 來轉義 (改變字元原有意義), 原本引號是字串的開始或結束字元, 前面加倒斜線將其改變為引號本身 :
>>> print('It\'s mine')
It's mine
>>> print('he said:\'Go!\'')
he said:'Go!'
>>> print("he said:\"Go!\"")
he said:"Go!"
Python 的跳脫字元包括 \' 與 \" 總共有 12 個如下 :
跳脫字串 | 說明 |
\' | 單引號 |
\" | 雙引號 |
\\ | 倒斜線 |
\n | 換行 (LF) |
\r | 回車 (CR) |
\t | 水平定位 (TAB) |
\v | 垂直定位 (VT) |
\a | 響鈴 (BEL) |
\b | 退格 (BS) |
\f | 插入一頁 (FF) |
\x41 | 16 進位 ASCII 碼 A |
\101 | 8 進位 ASCII 碼 A |
這些跳脫字元大都是 ASCII 字元編碼中的控制字元, 例如 :
>>> print('123\\456\n\r789') #印出倒斜線與跳行
123\456
789
>>> print('123\\456\n789') #只用 \n 即可跳行
123\456
789
>>> print('123\\456\r789') #\r 只有回車功能, 不會跳行
789\456
可見跳行可以用 \n\r 或者單用 \n 皆可, \r 只是像打字機那樣的單純回車 (carrage return) 而已, 所以上面最後一例 \r 會讓列印位置回到最前面印出 789, 就把原先已經印出的 123 蓋掉了.
>>> print('123\t456\t789') #水平定位
123 456 789
>>> print('123\v456\v789') #垂直定位
123
456
789
換頁字元 \f 會刷新頁面 (換上新頁), 從最上面開始列印, 響鈴字元 \a 會讓系統發出噹的一聲, 而退位字元會往回一格列印, 蓋掉前一字元, 例如下面範例中開頭的 \f 會換新頁, 從第一列開始印出 0, 接著響鈴並印出 123, 再響鈴後印出 456, 然後 \b 會倒退一格到 6 的位置, 印出 789, 所以 6 就被蓋掉不見了 :
>>> print('\f0\a123\a456\b789')
012345789
下面範例測試 8 進位與 16 進位的跳脫字元表示法, 字母 A 的 ASCII 碼以 8 進制表示為 101, 以 16 進制表示則為 41. 注意 16 進制必須用小寫 x, 不可用大寫 X :
>>> '\101'
'A'
>>> '\x41'
'A'
Python 有兩個內建函數用來處理 ASCII 碼 :
函數 | 說明 |
ord(char) | 傳回字元 char 的 ASCII 碼 (10 進制) |
chr(code) | 傳回 ASCOII 碼 code 的字元 |
注意, ord() 的參數只能傳入一個字元, 且傳回值是 10 進位的 ASCII 碼, 要取得 8 進制與 16 進制 ASCII 碼須使用 oct() 與 hex() 轉換, 例如 :
>>> ord('A'), oct(ord('A')), hex(ord('A'))
(65, '0o101', '0x41')
>>> ord('\n'), oct(ord('\n')), hex(ord('\n'))
(10, '0o12', '0xa')
>>> chr(65), chr(0o101), chr(0x41)
('A', 'A', 'A')
>>> ord('AB') #ord 只能傳入一個字元
Traceback (most recent call last):
File "<stdin>", line 1, in
當字串中含有大量跳脫字元時會使可讀性變差, 這時可以用 Python 的原始字串 (raw string) 來表示, 在字串的開頭引號前面加個 r 就表示引號內為原始字串, 例如 :
>>> '\n'
'\n'
>>> r'\n' #引號內為原始字串, \ 會以 \\ 取代
'\\n'
>>> r'\\' #引號內為原始字串, \ 會以 \\ 取代
'\\\\'
>>> R'\n' #MicroPython 未實作大寫 R 的原始字串功能
Traceback (most recent call last):
File "<stdin>", line 1
SyntaxError: invalid syntax
注意, Cpython 可用 r 或 R, 但 MicroPython 沒有實作 R, 只能用 r :
C:\Users\Tony>py -2
Python 2.7.8 (default, Jun 30 2014, 16:03:49) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> R'\n'
'\\n'
>>> R'\\n'
'\\\\n'
原始字串在表示 Windows 的路徑時可以派上用場 (使用倒斜線做分隔符號), 例如下面範例中, 字串中的 \U 會被認為要跳脫, 但又無法解譯這個 \U 跳脫字元, 所以產生執行造成錯誤, 前面冠 r 將其變成原始字串後就可以取消跳脫功能了 :
>>> 'C:\Users\tony' #沒有 \U 這個跳脫字元
Traceback (most recent call last):
File "<stdin>", line 1
SyntaxError: invalid syntax
>>> r'C:\Users\tony' #用 r 避免跳脫
'C:\\Users\\tony'
>>> print('C:\Users\tony') #沒有 \U 這個跳脫字元
Traceback (most recent call last):
File "<stdin>", line 1
SyntaxError: invalid syntax
>>> print(r'C:\Users\tony') #用 r 取消跳脫
C:\Users\tony
2. 長字串的跨行串接
對於較長的字串, 為了可讀性可以用 \ 串接延續到下一行, 例如 :
>>> 'This is \
... a book. That is\
... a pen.'
'This is a book. That isa pen.'
注意, 這裡的倒斜線 \ 只是單純的跨行串接符號而已, 沒有跳行作用, 跳行須自行加入 \n 字元. 例如 :
>>>a='This is \
... a pen.\nThat is\
... a book.'
>>> a
'This is a pen.\nThat isa book.'
>>> print(a)
This is a pen.
That isa book.
除了用行尾倒斜線跨行串接長字串外, Python 還可以用三個連續引號來表示跨行的長字串 (單引號或雙引號均可), 不過連續引號並非只能在跨行時用, 單行也可以用. 例如:
>>> a='''Hello
... World!'''
>>> a
'Hello\n World!'
>>> print(a)
Hello
World!
>>> '''Hello World!'''
'Hello World!'
注意, 與上面用 \ 做跨行串接長字串不同的是, 使用三個連續引號時會保存輸入的格式, 這對處理像 JSON 或 HTML 那樣的長字串很方便. 例如上面 Hello 後是跳行, 這個 \n 字元會被認為是字串的一部分; 而上面用 \ 跨行串接長字串則只是單純串接, 並非跳行, 要跳行需自行加入 \n.
3. 字串的長度 :
由於字串繼承抽象型別 sized, 因此可以使用內建函數 len() 取得字串長度 (即 unicode 字元數) :
函數 | 說明 |
len(obj) | 傳回物件元素個數 |
注意, 跳脫 (轉義) 字元雖然看起來由兩個字元組成, 但實際上算是一個字元. 例如 :
>>> len('Hello')
5
>>> len('\n')
1
4. 字串的基本操作 :
字串的基本操作有三種 :
- 串接
- 複製
- 切片 (slicing)
>>> a='abc' '123' #字串常數可以前後直接串接
>>> a
'abc123'
>>> a='abc' + '123' #用 + 運算子串接
>>> a
'abc123'
但是如果有一個是變數的話就必須使用 + 運算子串接, 例如 :
>>> a='abc123'
>>> a '456' #字串變數不可直接串接
Traceback (most recent call last):
File "<stdin>", line 1
SyntaxError: invalid syntax
>>> a + '456'
'abc123456'
運算子 + 雖然身兼加號與自串串接兩種功能, 但 Python 是強型別語言, 不會像 Javascript 那樣進行隱藏的自動轉型, 必須強制轉型才可以, 例如 :
>>> '123' + 123 #Python 不會自動轉型
Traceback (most recent call last):
File "<stdin>", line 1, in
>>> int('123') + 123 #必須強制轉型
246
字串的複製使用 * 運算子, 例如 :
>>> 'abc123' * 3 #複製三次
'abc123abc123abc123'
>>> 'abc123\n' * 3 #含跳行字元複製三次
'abc123\nabc123\nabc123\n'
>>> print('abc123\n' * 3)
abc123
abc123
abc123
字串繼承自抽象型別 sequecnce, 由有序的 unicode 字元組成, 所以字串其實可以看做是不可變的字元串列. 雖然其內容為不可變, 但是可以利用中括號 [] 運算子擷取其元素 (字元), 或用切片 [start:end:step] 運算子擷取裡面的子字串成為新字串.
索引值由左至右從 0 起算, 0 代表字串的開始字元; 若由字串尾端 (由右往左) 的話, 則從 -1 起算, 即最後一個字元索引為 -1, 倒數第二字原為 -2 等等. 但要注意索引若超出界線將產生錯誤, 例如 :
>>> a='0123456789'
>>> a[0]
'0'
>>> a[-1]
'9'
>>> a[9], a[-1] #a[9] 與 a[-1] 是同一個字元
('9', '9')
>>> a[0], a[-10] #a[0] 與 a[-10] 是同一個字元
('0', '0')
>>> a[10] #索引超出界限產生錯誤
Traceback (most recent call last):
File "<stdin>", line 1
SyntaxError: invalid syntax
Python 的字串是不可變資料, 因此利用索引去更改字串內容將引發錯誤, 例如 :
>>> a='0123456789'
>>> a[0]
'0'
>>> a[0]='a' #字串內容不允許變更
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
使用切片從字串中取得子字串的語法為 [start:end:step], 其中 start 為開始索引, end 為結束索引, step 為步階 (即跳幾格取得下一個字元), 這三個索引以及冒號都是可以省略的, 但不能全部省略, 至少必須有一個冒號.
- [:] 會擷取整個字串
- [start:] 會擷取索引 start 到字串結尾
- [:end] 會擷取字串開頭至索引 end-1 (不包含索引 end)
- [start:end] 會擷取索引 start 至索引 end-1 (不包含索引 end)
- [start:end:step] 會擷取索引 start 至索引 end-1 (不包含索引 end), 跳 step 次
例如 :
>>> a='0123456789'
>>> a[:] #擷取整個字串
'0123456789'
>>> a[5:] #擷取索引 5 到字串尾
'56789'
>>> a[:5] #擷取字串首至索引 4
'01234'
>>> a[3:8] #擷取索引 3 到索引 7
'34567'
>>> a[3:8:2] #MicroPython 不支援步階大於 1
Traceback (most recent call last):
File "<stdin>", line 1, in
>>> a[3:8:1] #與 [3:8] 效果相同
'34567'
步階 step 大於 1 在 CPython 執行結果如下 :
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> a='0123456789'
>>> a[3:8:2] #索引 3~7, 跳 2 格
'357'
>>> a='0123456789'
>>> a[:20] #結束索引 20 已超限, 但不會出現錯誤
'0123456789'
>>> a[-20:] #結束索引 -20 已超限, 但不會出現錯誤
'0123456789'
切片也可以使用負數索引, 表示從字串尾 (索引 -1) 起算, 例如 :
>>> a='0123456789'
>>> a[-3:] #a[-3:] 即 a[7:]
'789'
>>> a[:-3] #a[:-3] 即 a[:7]
'0123456'
>>> a[-6:-3] #a[-6:-3] 即 a[4:7
'456'
間隔 step 也可以是負數, 表示由後往前 (或由右往左) 跳躍, 但是在 MicroPython 卻未實作負的間隔功能, 例如 :
>>> a='0123456789'
>>> a[::-1]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NotImplementedError: only slices with step=1 (aka None) are supported
>>>
這個 [::-1] 是指整個字串 [::] 從後面每次取一個 , 在 CPython 執行結果如下 :
C:\Users\Tony>python
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)]
on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> a='0123456789'
>>> a[::-1] #間隔 -1 表示從右到左每次取一個
'9876543210'
5. 字串物件的方法 :
(1). 大小寫操作
方法 | 說明 |
capitalize() | 將首字母大寫, 其餘小寫 (未實作) |
lower() | 將全部字元轉成小寫 |
upper() | 將全部字元轉成大寫 |
swapcase() | 將字元大寫變小寫, 小寫變大寫 (未實作) |
title() | 將每個單字的首字元大寫, 其餘小寫 (未實作) |
這五個方法在 MicroPython 只時做了 lower() 與 upper(), 例如 :
>>> a='This is a book. That is a pen.'
>>> a
'This is a book. That is a pen.'
>>> a.capitalize()
Traceback (most recent call last):
ppributeError: 'str' object has no attribute 'capitalize'
>>> a.lower()
'this is a book. that is a pen.'
>>> a #原字串不變
'This is a book. That is a pen.'
>>> a.upper()
'THIS IS A BOOK. THAT IS A PEN.'
>>> a.swapcase()
Traceback (most recent call last):
File "
>>> a.title()
Traceback (most recent call last):
File "
方法 | 說明 |
islower() | 字串中的英文字母都是小寫傳回真, 否則傳回假 |
isupper() | 字串中的英文字母都是大寫傳回真, 否則傳回假 |
istitle() | 字串中每個單字的首字元大寫其餘小寫傳回真, 否則傳回假 (未實作) |
isspace() | 字串只含有空白字元 ('\t','\v','\n','\r','\f',' ') 傳回真, 否則傳回假 |
isalpha() | 字串只含有英文字母傳回真, 否則傳回假 |
isdigit() | 字串只含有數字 (0~9) 傳回真, 否則傳回假 |
isdecimal() | 字串只含有 10 進位數字傳回真, 否則傳回假 (未實作) |
isalnum() | 字串只含有英文字母與數字傳回真, 否則傳回假 (未實作) |
isidentifier() | 字串是否為合法的識別字 (未實作) |
isprintable() | 字串只含有可見字元 (未實作) |
這十個方法在 MicroPython 只實作了 5 個, istitle(), isdecimal(), isalnum(), isidentifier(), 以及 isprintable() 這 5 個未實作. 例如 :
>>> 'abc123'.islower()
True
>>> 'Abc123'.islower()
False
>>> 'Hello World'.istitle()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'istitle'
>>> '\t\v\n\r\f '.isspace() #最後一個字元是空格
True
>>> '\t\v\n\r\f \a'.isspace() #響鈴字元 '\a' 不是空白 (white space)
False
>>> 'abcxyzABCXYZ'.isalpha()
True
>>> 'abcxyzABCXYZ123'.isalpha()
False
>>> '0123456789'.isdigit()
True
>>> '0123456789abc'.isdigit()
False
>>> '0123456789'.isdecimal()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'isdecimal'
>>> '0123456789abcABC'.isalnum()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'isalnum'
>>> 'str'.isidentifier()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'isidentifier'
>>> 'abc123'.isprintable()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'isprintable'
(3). 尋找子字串 :
上面七個方法都有備選的第二與第三參數, 不過在 MicroPython 中, startswith() 與 endswith() 只實作了一個參數的用法, 無法指定切片範圍去尋找. 其次, index()/rindex() 功能與 find()/rfind() 一樣, 差別是沒找到時, index()/rindex() 會傳回 -1, 而 find()/rfind() 則是產生 ValueError 錯誤, 例如 :
>>> '0123456789'.find('345') #在索引 3 找到 '345'
3
>>> '0123456789'.find('345',2) #從索引 2 開始找 (有找到)
3
>>> '0123456789'.find('345',4) #從索引 4 開始找 (沒找到)
-1
>>> '0123456789'.find('345',2,5) #切片 [2:5] 不包括索引 5 故沒找到
-1
>>> '0123456789'.find('345',2,6) #切片 [2:6] 有包括索引 5 故有找到
3
>>> '0123456345'.find('345') #有兩組匹配, 但只傳回第一組開始索引
3
>>> '0123456789'.rfind('345') #第 1 組即最後一組
3
>>> '0123456345'.rfind('345') #有兩組匹配, 但只傳回最後一組開始索引 7
7
>>> '0123456345'.rfind('345',2) #從索引 2 開始找
7
>>> '0123456345'.rfind('345',2,7) #在切片 [2:7] 中只找到第一組
3
>>> '0123456345'.rfind('345',2,5) #在切片 [2:5] 中找不到傳回 -1
-1
>>> '0123456789'.index('345') #在索引 3 找到 '345'
3
>>> '0123456789'.index('345',2,7) #切片 [2:7] 有包括索引 5 故有找到
3
>>> '0123456789'.index('345',4,7) #切片 [4:7] 不包括索引 3 故沒找到 (傳回錯誤)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: substring not found
>>> '0123456345'.index('345') #與 find() 一樣只傳回第一組開始索引
3
>>> '0123456789'.rindex('345') #在索引 3 找到 '345'
3
>>> '0123456789'.rindex('345',2) #從索引 2 開始找 (有找到)
3
>>> '0123456789'.rindex('345',4,7) #切片 [4:7] 不包括索引 3 故沒找到 (傳回錯誤)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: substring not found
>>> '0123456345'.rindex('345') #與 rfind() 一樣只傳回最後一組開始索引
7
>>> '0123456789'.count('345') #找到一組
1
>>> '0123456345'.count('345') #找到兩組
2
>>> '0123456789'.count('345',2) #從索引 2 開始找 (找到 1 組)
1
>>> ''0123456789'.count('345',4,7) #切片 [4:7] 不包括索引 3 故沒找到
0
>>> '0123456789'.startswith('0123')
True
>>> '0123456789'.startswith('345',3)
True
>>> '0123456789'.startswith('345',2)
False
>>> '0123456789'.startswith('345',3,6)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: function expected at most 3 arguments, got 4 #奇怪的錯誤訊息
>>> '0123456789'.endswith('789')
True
>>> '0123456789'.endswith('789',5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NotImplementedError: start/end indices #endswith() 未實作多參數
>>> '0123456789'.endswith('789',5,9)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: function expected at most 3 arguments, got 4 #奇怪的錯誤訊息
(4). 字串取代 :
注意, 這個方法會將字串中符合的子字串全部替換掉.
例如 :
>>> 'abc123abc123'.replace('abc','xyz') #將字串中的 'abc' 以 'xyz' 取代
'xyz123xyz123'
>>> 'abc123abc123'.replace('abc','xyz',1) #限制取代次數 1 次
'xyz123abc123'
>>> 'abc123abc123'.replace('abc','xyz',0) #取代次數 0 表示不取代
'abc123abc123'
>>> 'abc123abc123'.replace('abc','xyz',3) #取代次數超過沒作用
'xyz123xyz123'
(5). 字串去除 :
注意, 若傳入參數指定欲刪除的字元, 預設刪除六種空白字元 (white space) : \t\v\n\r\f 與空格.
例如 :
>>> ' abc '.strip() #預設刪除 white space (\t\v\n\r\f 與空格)
'abc'
>>> 'abc123'.strip('a3') #刪除首尾的 'a' 或 '3'
'bc12'
>>> 'abc123'.strip('c') #刪除首尾的 'c' (沒有)
'abc123'
>>> 'abc123'.strip('32ba') #刪除首尾的 '3' 或 '2' 或 'b' 或 'a'
'c1'
>>> '\t\v\n\r\f abc\n123 \t\v\n\r\f'.strip() #刪除首尾的 white space
'abc\n123'
(6). 字串填充 :
字串填充功能在 MicroPython 全部未實作. 例如 :
>>> 'abc'.center(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'center'
>>> 'abc'.ljust(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'ljust'
>>> 'abc'.rjust(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'rjust'
>>> 'abc'.zfill(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'zfill'
>>> 'a\tbc'.expandtabs(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'expandtabs'
這五個方法在 CPython 執行結果如下 :
C:\Users\Tony>python
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> 'abc'.center(10) #欄寬 10 格, 前後補空格
' abc '
>>> 'abc'.ljust(10) #欄寬 10 格, 後面補空格
'abc '
>>> 'abc'.rjust(10) #欄寬 10 格, 前面補空格
' abc'
>>> 'abc'.zfill(10) #欄寬 10 格, 前面補 0
'0000000abc'
>>> 'a\tbc'.expandtabs(10) #實際 9 個空格
'a bc'
>>> 'a\tbc'.expandtabs(3) #實際 2 個空格
'a bc'
>>> 'a\tbc'.expandtabs(2) #實際 1 個空格
'a bc'
>>> 'a\tbc'.expandtabs(1) #實際 1 個空格
'a bc'
觀察 expandtabs() 傳入不同參數結果, 發現傳入 1 與 2 實際空格為 1, 傳入 3 以上實際空格為 tabsize-1, 與我預期者不同, 不知作何解釋.
(7). 字串切割 :
這五個方法在 MicroPython 僅實作了 split() 與 rsplit() 這兩個, 例如 :
>>> a='123,456,789'
>>> a.partition(',') #未實作 partition()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'partition'
>>> a.rpartition(',') #未實作 rpartition()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'rpartition'
>>> a.split(',') #以 ',' 分拆整個字串, 拆開後以串列傳回
['123', '456', '789']
>>> a.split(',',2) #指定最多拆 2 次
['123', '456', '789']
>>> a.split(',',1) #指定最多拆 1 次
['123', '456,789']
>>> a.rsplit(',') #從右邊往左拆
['123', '456', '789']
>>> a.rsplit(',',1) #指定最多拆 1 次
['123,456', '789']
>>> a='123\n456\n789\n' #含有跳行字元的字串
>>> print(a)
123
456
789
>>> a.splitlines() #未實作 splitlines()
Traceback (most recent call last):
File "AttributeError: 'str' object has no attribute 'splitlines'
如果有連續兩個分割字串, 則會分割出空字串, 例如 :
>>> a='123,,456,,789' #連續的分割字串 ,
>>> a.split(',')
['123', '', '456', '', '789']
上面三個 MicroPython 未實作的方法在 CPython 執行結果如下 :
C:\Users\Tony>python
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> a='123,456,789'
>>> a='123,456,789'
>>> a.partition(',') #以第一個 ',' 為界拆成 3 份
('123', ',', '456,789')
>>> a.rpartition(',') #以最後一個 ',' 為界拆成 3 份
('123,456', ',', '789')
>>> a='123\n456\n789\n'
>>> a.splitlines() #預設不保留跳行字元
['123', '456', '789']
>>> a.splitlines(True) #保留跳行字元
['123\n', '456\n', '789\n']
(8). 字串組合 :
方法 | 說明 |
find(sub [,start [, end]]) | 尋找子字串 sub, 找到傳回第一組之起始索引, 否則傳回 -1 |
rfind(sub [,start [, end]]) | 尋找子字串 sub, 找到傳回最後一組之起始索引, 否則傳回 -1 |
index(sub [,start [, end]]) | 與 find 相同, 但找不到子字串時會產生 valueError 錯誤 |
rindex(sub [,start [, end]]) | 與 rfind 相同, 但找不到子字串時會產生 valueError 錯誤 |
count(sub [,start [, end]]) | 在字串中尋找子字串 sub, 傳回子字串出現的次數 |
startswith(pfx [,start [, end]]) | 若字串以子字串 pfx 開頭傳回真, 否則傳回假 |
endswith(sfx [,start [, end]]) | 若字串以子字串 sfx 結尾傳回真, 否則傳回假 |
上面七個方法都有備選的第二與第三參數, 不過在 MicroPython 中, startswith() 與 endswith() 只實作了一個參數的用法, 無法指定切片範圍去尋找. 其次, index()/rindex() 功能與 find()/rfind() 一樣, 差別是沒找到時, index()/rindex() 會傳回 -1, 而 find()/rfind() 則是產生 ValueError 錯誤, 例如 :
>>> '0123456789'.find('345') #在索引 3 找到 '345'
3
>>> '0123456789'.find('345',2) #從索引 2 開始找 (有找到)
3
>>> '0123456789'.find('345',4) #從索引 4 開始找 (沒找到)
-1
>>> '0123456789'.find('345',2,5) #切片 [2:5] 不包括索引 5 故沒找到
-1
>>> '0123456789'.find('345',2,6) #切片 [2:6] 有包括索引 5 故有找到
3
>>> '0123456345'.find('345') #有兩組匹配, 但只傳回第一組開始索引
3
>>> '0123456789'.rfind('345') #第 1 組即最後一組
3
>>> '0123456345'.rfind('345') #有兩組匹配, 但只傳回最後一組開始索引 7
7
>>> '0123456345'.rfind('345',2) #從索引 2 開始找
7
>>> '0123456345'.rfind('345',2,7) #在切片 [2:7] 中只找到第一組
3
>>> '0123456345'.rfind('345',2,5) #在切片 [2:5] 中找不到傳回 -1
-1
>>> '0123456789'.index('345') #在索引 3 找到 '345'
3
>>> '0123456789'.index('345',2,7) #切片 [2:7] 有包括索引 5 故有找到
3
>>> '0123456789'.index('345',4,7) #切片 [4:7] 不包括索引 3 故沒找到 (傳回錯誤)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: substring not found
>>> '0123456345'.index('345') #與 find() 一樣只傳回第一組開始索引
3
>>> '0123456789'.rindex('345') #在索引 3 找到 '345'
3
>>> '0123456789'.rindex('345',2) #從索引 2 開始找 (有找到)
3
>>> '0123456789'.rindex('345',4,7) #切片 [4:7] 不包括索引 3 故沒找到 (傳回錯誤)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: substring not found
>>> '0123456345'.rindex('345') #與 rfind() 一樣只傳回最後一組開始索引
7
>>> '0123456789'.count('345') #找到一組
1
>>> '0123456345'.count('345') #找到兩組
2
>>> '0123456789'.count('345',2) #從索引 2 開始找 (找到 1 組)
1
>>> ''0123456789'.count('345',4,7) #切片 [4:7] 不包括索引 3 故沒找到
0
>>> '0123456789'.startswith('0123')
True
>>> '0123456789'.startswith('345',3)
True
>>> '0123456789'.startswith('345',2)
False
>>> '0123456789'.startswith('345',3,6)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: function expected at most 3 arguments, got 4 #奇怪的錯誤訊息
>>> '0123456789'.endswith('789')
True
>>> '0123456789'.endswith('789',5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NotImplementedError: start/end indices #endswith() 未實作多參數
>>> '0123456789'.endswith('789',5,9)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: function expected at most 3 arguments, got 4 #奇怪的錯誤訊息
(4). 字串取代 :
方法 | 說明 |
replace(old, new [, count]]) | 將子字串 old 全部用 new 替換, 或指定替換 count 個 |
注意, 這個方法會將字串中符合的子字串全部替換掉.
例如 :
>>> 'abc123abc123'.replace('abc','xyz') #將字串中的 'abc' 以 'xyz' 取代
'xyz123xyz123'
>>> 'abc123abc123'.replace('abc','xyz',1) #限制取代次數 1 次
'xyz123abc123'
>>> 'abc123abc123'.replace('abc','xyz',0) #取代次數 0 表示不取代
'abc123abc123'
>>> 'abc123abc123'.replace('abc','xyz',3) #取代次數超過沒作用
'xyz123xyz123'
(5). 字串去除 :
方法 | 說明 |
strip([chars]) | 去除字串首尾的指定字元集合 chars, 預設刪除空白 |
lstrip([chars]) | 去除字串開頭的指定字元集合 chars, 預設刪除空白 |
rstrip([chars]) | 去除字串結尾的指定字元集合 chars, 預設刪除空白 |
注意, 若傳入參數指定欲刪除的字元, 預設刪除六種空白字元 (white space) : \t\v\n\r\f 與空格.
例如 :
>>> ' abc '.strip() #預設刪除 white space (\t\v\n\r\f 與空格)
'abc'
>>> 'abc123'.strip('a3') #刪除首尾的 'a' 或 '3'
'bc12'
>>> 'abc123'.strip('c') #刪除首尾的 'c' (沒有)
'abc123'
>>> 'abc123'.strip('32ba') #刪除首尾的 '3' 或 '2' 或 'b' 或 'a'
'c1'
>>> '\t\v\n\r\f abc\n123 \t\v\n\r\f'.strip() #刪除首尾的 white space
'abc\n123'
(6). 字串填充 :
方法 | 說明 |
center(width [,fillchar]) | 將字串居中擴展為 width 個字元, 左右以 fillchar 填充, 預設為空格 (未實作) |
ljust(width [,fillchar]) | 將字串靠左擴展為 width 個字元, 右方以 fillchar 填充, 預設為空格 (未實作) |
rjust(width [,fillchar]) | 將字串靠右擴展為 width 個字元, 左方以 fillchar 填充, 預設為空格 (未實作) |
zfill(width) | 在字串左方補 0 使總長度擴展為 width 字元 (未實作) |
expandtabs([tabsize]) | 將字串中的 tab 字元以 tabsize 個空格取代, 預設 8 格 (未實作) |
字串填充功能在 MicroPython 全部未實作. 例如 :
>>> 'abc'.center(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'center'
>>> 'abc'.ljust(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'ljust'
>>> 'abc'.rjust(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'rjust'
>>> 'abc'.zfill(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'zfill'
>>> 'a\tbc'.expandtabs(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'expandtabs'
這五個方法在 CPython 執行結果如下 :
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> 'abc'.center(10) #欄寬 10 格, 前後補空格
' abc '
>>> 'abc'.ljust(10) #欄寬 10 格, 後面補空格
'abc '
>>> 'abc'.rjust(10) #欄寬 10 格, 前面補空格
' abc'
>>> 'abc'.zfill(10) #欄寬 10 格, 前面補 0
'0000000abc'
>>> 'a\tbc'.expandtabs(10) #實際 9 個空格
'a bc'
>>> 'a\tbc'.expandtabs(3) #實際 2 個空格
'a bc'
>>> 'a\tbc'.expandtabs(2) #實際 1 個空格
'a bc'
>>> 'a\tbc'.expandtabs(1) #實際 1 個空格
'a bc'
觀察 expandtabs() 傳入不同參數結果, 發現傳入 1 與 2 實際空格為 1, 傳入 3 以上實際空格為 tabsize-1, 與我預期者不同, 不知作何解釋.
(7). 字串切割 :
方法 | 說明 |
partition(sep) | 以 sep 為界由左至右分割字串為三部分, 傳回 sep 居中的 tuple (未實作) |
rpartition(sep) | 以 sep 為界由右至左分割字串為三部分, 傳回 sep 居中的 tuple (未實作) |
split(sep [,maxsplit]) | 以 sep 為界由左至右分割字串 maxsplit 次, 結果以 list 傳回 |
rsplit(sep [,maxsplit]) | 以 sep 為界由右至左分割字串 maxsplit 次, 結果以 list 傳回 |
splitlines([keepends]) | 以 \n 為界分割字串, 預設不保留跳行字元 (keepends=False) (未實作) |
這五個方法在 MicroPython 僅實作了 split() 與 rsplit() 這兩個, 例如 :
>>> a='123,456,789'
>>> a.partition(',') #未實作 partition()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'partition'
>>> a.rpartition(',') #未實作 rpartition()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'rpartition'
>>> a.split(',') #以 ',' 分拆整個字串, 拆開後以串列傳回
['123', '456', '789']
>>> a.split(',',2) #指定最多拆 2 次
['123', '456', '789']
>>> a.split(',',1) #指定最多拆 1 次
['123', '456,789']
>>> a.rsplit(',') #從右邊往左拆
['123', '456', '789']
>>> a.rsplit(',',1) #指定最多拆 1 次
['123,456', '789']
>>> a='123\n456\n789\n' #含有跳行字元的字串
>>> print(a)
123
456
789
>>> a.splitlines() #未實作 splitlines()
Traceback (most recent call last):
File "
如果有連續兩個分割字串, 則會分割出空字串, 例如 :
>>> a='123,,456,,789' #連續的分割字串 ,
>>> a.split(',')
['123', '', '456', '', '789']
C:\Users\Tony>python
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> a='123,456,789'
>>> a='123,456,789'
>>> a.partition(',') #以第一個 ',' 為界拆成 3 份
('123', ',', '456,789')
>>> a.rpartition(',') #以最後一個 ',' 為界拆成 3 份
('123,456', ',', '789')
>>> a='123\n456\n789\n'
>>> a.splitlines() #預設不保留跳行字元
['123', '456', '789']
>>> a.splitlines(True) #保留跳行字元
['123\n', '456\n', '789\n']
(8). 字串組合 :
方法 | 說明 |
join(iterable) | 以字串為分隔字元串接 iterable 物件各元素為新字串後傳回 |
此 join() 函數使用上較特別, 是以分隔字元當操作母體, 以要串接的可迭代物件 (如串列, 元組等) 當參數, 例如 :
>>> a=['123','456','789'] #要組合的對象為串列元素
>>> ''.join(a) #以空字串串接
'123456789'
>>> ' '.join(a) #以空格串接
'123 456 789'
>>> '-'.join(a) #以 '-' 串接
'123-456-789'
>>> ','.join(a) #以 ',' 串接
'123,456,789'
>>> a=('123','456','789') #要組合的對象為元組元素
>>> ''.join(a) #以空字串串接
'123456789'
>>> ' '.join(a) #以空格串接
'123 456 789'
>>> '-'.join(a) #以 '-' 串接
'123-456-789'
>>> ','.join(a) #以 ',' 串接
'123,456,789'
(9). 字串格式化 :
Python 的字串最早是採用像 C 語言那樣以 % 運算子來格式化 (這也是餘數運算子), 較新的方式是使用 format() 函數. % 運算子搭配格式指定子後嵌入字串中, 就可以利用字串後面以 % 帶領的物件變數或 tuple 變數將值映射到對應的位置, 其組成方式如下 :
%[flag][width][.precision][specifier]
中括號表示每個組成成分都是可有可無的. 其中 [flag] (旗標) 有五個字元可用 :
旗標 | 說明 |
'#' | 顯示另一種格式, 例如 16 進制的 ff 改為 0xff |
'0' | 數值前面補 '0' |
'-' | 靠左對齊 (若與 '0' 旗標同時出現會蓋掉欲補之 '0') |
' ' | 空格旗標 : 在正數前面補一個空格 |
'+' | 前面補 '+' (若與空格旗標同時出現會蓋掉欲補之空格) |
[width] 用來設定要顯示的資料欄寬 (即字元個數); [.precision] 用來設定浮點數的精確度, 以一個小數點後面帶一個整數, 表示要精確到小數點後幾位 (CPython 預設 6 位); 而 [specifier] 用來設定資料要用何種格式輸出, 共有 15 種格式如下表 :
格式 | 說明 |
'd' | 有號 10 進位整數 |
'i' | 有號 10 進位整數 (同 'd') |
'o' | 有號 8 進位整數 |
'x' | 有號 16 進位整數 (小寫) |
'X' | 有號 16 進位整數 (大寫) |
'f' | 小數格式的浮點數 |
'F' | 小數格式的浮點數 |
'e' | 指數格式的浮點數 |
'E' | 指數格式的浮點數 |
'g' | 自動變換格式的浮點數, 指數 < -4 用指數表示 (小寫) |
'G' | 自動變換格式的浮點數, 指數 < -4 用指數表示 (大寫) |
'c' | 顯示一個字元 |
's' | 顯示一個字串 |
'r' | 顯示一個用 repr() 轉換的字串 |
'%' | 顯示字元 '%' |
其中 'd' 與 'i' 是完全一樣的功能. 例如 :
>>> '%d' %1234567890 #10 進位整數
'1234567890'
>>> '%i' %1234567890 #與 %i 相同
'1234567890'
>>> print("Hello %s" %'Tony') #字串
Hello Tony
>>> '%d %i %o %x %X' %(255, 255, 255, 255, 255) #10/8/16 進位整數
'255 255 377 ff FF'
>>> '%f %F %e %E' %(0.123456789, 0.123456789, 0.123456789, 0.123456789) #浮點數
'0.123457 0.123457 1.234568e-01 1.234568E-01'
>>> '%g %G' %(1.2345678e-4, 1.23456789e-4) #浮點數 (自動判斷格式)
'0.000123457 0.000123457'
>>> '%g %G' %(1.2345678e-5, 1.23456789e-5) #浮點數 (自動判斷格式)
'1.23457e-05 1.23457E-05'
>>> '%c %c' %(65, 'A') #字元也可用整數
'A A'
>>> '%c %c %r' %(65, 'A', 'A') #%r 會加上引號
"A A 'A'"
Python 的物件都可以轉換成字串, %s 格式也可以用在 list 與 tuple 等物件, 例如 :
>>> '%s %s' %([1,2,3], (4,5,6)) #list 與 tuple 被轉成字串輸出了
'[1, 2, 3] (4, 5, 6)'
旗標 '#' 用來以另類 (alterbative) 格式顯示資料, 例如在顯示 16 進位數值時會冠上 '0x' 或 '0X'; 顯示 8 進位數值時會冠上 '0o' :
'0xff 0XFF 0o377'
>>> '%x %X %o' %(255, 255, 255)
'ff FF 377'
旗標 '0' 會在數值資料前面補 0 (不可用字串), 例如 :
>>> '%05d' %123 #欄寬 5, 前面補 0
'00123'
>>> '%05d' %123456 #超過欄寬當然不補 0
'123456'
>>> '%05x' %0xabc #16 進制整數
'00abc'
>>> '%05d' %34.567 #小數會被捨去
'00034'
旗標 '-' 會將資料向左對齊, 與旗標 '0' 同時使用時, 在 CPython 是旗標 '-' 優先, 旗標 '0' 無作用, 但在 MicroPython 卻是向左靠齊後又在後面補 0, 例如 :
>>> '%-5d' %123 #向左靠齊
'123 '
>>> '%-05d' %123 #向左靠齊後右邊補 0
'12300'
>>> '%0-5d' %123 #向左靠齊後右邊補 0
'12300'
>>> '%0-5d' %123456
'123456'
而在 CPython 執行結果如下 :
C:\Users\Tony>python
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> '%0-5d' %123 #旗標 '-' 優先, 即向左靠齊不補 0
'123 '
>>> '%-05d' %123 #旗標 '-' 優先, 即向左靠齊不補 0
'123 '
>>> '%-05d' %123456
'123456'
旗標 '+' 則會在數值前面冠上正負號, 例如 :
>>> '%5d' %123
' 123'
>>> '%+5d' %123 #強制冠正負號
' +123'
>>> '%+5d' %-123 #強制冠正負號
' -123'
>>> '%5d' %-123 #負數不用旗標 '+' 本來就會有負數
' -123'
除了用 % 運算子做字串格式化外, Python 的 str 物件還提供了比 % 功能更強大的格式化函數 format(), 此函數也是建立在 % 運算子基礎上, 其置換欄位採用大括號 {}, 裡面可用 0 起始的索引指定套用的參數索引, 如果沒有指定索引, 就依據參數出現順序一一套用, 如果要顯示大括號本身, 就用 {{}}, 例如 :
>>> '{0} {1} {2}'.format(123, 4.567, 'abc') #依指定之索引順序套用參數
'123 4.567 abc'
>>> '{} {} {}'.format(123, 4.567, 'abc') #依參數出現順序套用
'123 4.567 abc'
>>> '{2} {0} {1}'.format(123, 4.567, 'abc') #依指定之索引套用參數
'abc 123 4.567'
大括號內除了使用索引來定位要套用的參數外, 也可以像字典那樣使用 key, 這樣有 key 的參數在 format() 內可以放在任何位置, 但無 key 參數一定要放在對應位置, 例如 :
>>> '{} {name} {greetings}'.format('Hello!', name='Tony', greetings='You are welcome!')
>>> '{} {name} {greetings}'.format('Hello!', greetings='You are welcome!', name='Tony')
'Hello! Tony You are welcome!'
>>> '{} {name} {greetings}'.format(greetings='You are welcome!', name='Tony', 'Hello!')
Traceback (most recent call last):
File "
如果要印出的是 list 或 tuple 等序列性物件, 也可以在大括號的索引後使用中括號索引來擷取物件內的元素, 但是 MicroPython 還沒有實作這種用法, 例如 :
>>> name=['tony','peter']
>>> gender=('male','femal')
>>> '{0[1]} {1[1]}'.format(name, gender) #印出 name[1] 與 gender[1] (未實作)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NotImplementedError: attributes not supported yet
>>> '{0} {1}'.format(name[1], gender[1]) #索引放在 format() 裡就 OK
'peter femal'
Microsoft Windows [版本 10.0.14393]
(c) 2016 Microsoft Corporation. 著作權所有,並保留一切權利。
C:\Users\Tony>python
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> name=['tony','peter']
>>> gender=('male','femal')
>>> '{0[1]} {1[1]}'.format(name, gender) #在 {} 內使用序列物件索引
'peter femal'
>>> '{1[1]} {0[1]}'.format(name, gender) #{} 索引順序調換
'femal peter'
>>> '{[1]} {[1]}'.format(name, gender) #不指定 {} 索引就依對應關係
'peter femal'
>>> '{0[3]} {1[1]}'.format(name, gender) #索引超出界限了
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
這裡 {} 內的第一個數字是 {} 的索引, 而 [] 內的則是物件元素的索引.
Python 的串列是有序可變的物件集群 (Collections), 可以儲存任何資料型態, 包括串列本身. 其功能比傳統的陣列更強大, 因為傳統語言如 C 或 Java 的陣列只能儲存相同的資料型態. Python 的串列比較像 Java 的 ArrayList 類別. 串列與集合 (set) 不同之處是, 串列是有序的, 而集合是無序的, 且串列同一個元素可以出現一次以上, 而集合的元素則必須是唯一的.
1. 建立串列 :
建立串列的方法不只一種, 但主要是使用 [] 運算子, 例如 :
>>> a=[] #建立一個空的串列
>>> type(a) #型態為 list
<class 'list'>
>>> a=[0,1,2,3,4,5] #建立一個數值串列
>>> a
[0, 1, 2, 3, 4, 5]
>>> print([1.728, 3.14, 6.02e23]) #印出一個數值串列
[1.728, 3.14, 6.02e+23]
>>> a=['a', 'b', 'c'] #建立字串串列
>>> a
['a', 'b', 'c']
>>> a=[123, 3.14, "abc", True] #建立異質元素的串列
>>> a
[123, 3.14, 'abc', True]
由於串列是一種容器型別, 其元素可以是任何資料型態, 包括串列本身, 例如 :
>>> a=[(1,2,3),[4,5,6],{'x':7,'y':8,'z':9},{'a','b','c'}] #元素包括 tuple, list, dict, 與 set
>>> a
[(1, 2, 3), [4, 5, 6], {'x': 7, 'z': 9, 'y': 8}, {'b', 'c', 'a'}]
第二種建立串列的方法是使用內建函數 list(), 只能傳入一個元素當作參數 (tuple 或字串), 例如 :
>>> a=list()
>>> type(a)
>>> a
[123, 3.14, 'abc', True]
>>> list(a)
['a', 'b', 'c', '1', '2', '3'] #字串被轉成字元串列
傳入不可變 (immutable) 的元組 (tuple) 會將其轉成可變的串列 :
>>> a=(1,2,3) #元組
>>> list(a)
[1, 2, 3] #將元組變成串列
>>> a={'x':1,'y':2,'z':3} #字典
>>> list(a)
['x', 'z', 'y'] #傳回字典的鍵組成之串列
>>> a={1,2,3} #集合
>>> list(a)
[3, 1, 2]
第三種建立串列的方法是使用串列物件的 append() 方法, 例如 :
>>> a=[]
>>> a.append(123)
>>> a.append(3.14)
>>> a.append('abc')
>>> a.append(True)
>>> a
[123, 3.14, 'abc', True]
另外, 有一些內建函數其傳回值是串列, 例如字串的 split() 函數 :
>>> date="2017-05-05"
>>> date.split('-')
['2017', '05', '05']
>>> r=range(10) #預設 start=0
>>> r
range(0, 10)
>>> type(r) #range() 會傳回 range 型別物件
<class 'range'>
>>> list(r) #將 range 轉成 list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(range(3,9)) #間隔預設為 1
[3, 4, 5, 6, 7, 8]
>>> list(range(0,10,2)) #間隔=2
[0, 2, 4, 6, 8]
>>> list(range(0,-10,-2)) #間隔為負數時, stop 須小於 start
[0, -2, -4, -6, -8]
>>> list(range(0)) #0:0 為空串列
[]
>>> list(range(1,0)) #1:0 為空串列
[]
2. 串列的基本操作 :
串列的基本操作有下面 7 種 :
- 串列內容更改
- 串接 (使用 + 或 += 運算子)
- 複製 (使用 * 運算子)
- 切片 (使用 [] 運算子)
- 刪除元素 (使用 del 指令)
- 查詢元素 (使用 in 與 not in 運算子)
- 多重指定
>>> a=[1,2,3]
>>> b=a #b 也指向 a 的參考 (兩個內容一樣)
>>> a[0]='a' #更改 a[0] 元素
>>> a
['a', 2, 3] #a[0] 被更改了
>>> b
['a', 2, 3] #b[0] 也同時被改了 (相同實體)
>>> b[0]='b' #更改 b[0]
>>>b
['b', 2, 3]
>>> a
['b', 2, 3] #a[0] 也同時被改了 (相同實體)
注意, 變數是指向物件實體的參考, b=a 表示 b 變數的參考也是指向 a, 所以兩者都指向同一實體, 改任何一個另一個也同時被改了.
多個串列可用 + 或 += 運算子串接為新的串列 (另一個方法是使用 extend), 例如 :
>>> [1,2,3] + ['a','b','c']
[1, 2, 3, 'a', 'b', 'c'] #產生新串列
>>> a=[1,2,3]
>>> b=['a','b','c']
>>> a += b #即 a=a+b, a 指向串接後的新串列
>>> a
[1, 2, 3, 'a', 'b', 'c']
一個串列要複製其元素可使用 * 運算子 :
>>> [1,2,3]*3
[1, 2, 3, 1, 2, 3, 1, 2, 3] #元素複製 3 次
但是 MicroPython 卻不支援複合運算 *= :
>>> a=[1,2,3]
>>> a *= 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported types for : 'list', 'int'
這在 CPython 執行結果如下 :
C:\Users\Tony>python
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> a=[1,2,3]
>>> a *= 3
>>> a
[1, 2, 3, 1, 2, 3, 1, 2, 3]
串列繼承 sequence 型別, 其元素是按照順序排列的, 因此可以用索引來擷取串列的單一元素, 而用切片 (slice) 則可以擷取多個元素. 如同字串, 其索引由左至右為 0 起始的連續整數 (索引必須是整數, 不可以為浮點數), 由右至左為 -1 起始 (即倒數第一個元素索引為 -1), 索引超出界限會產生 IndexError, 例如 :
>>> a=[0,1,2,3,4,5]
>>> a[0]
0
>>> a[1]
1
>>> a[2]
2
>>> a[1.5] #索引須為整數, 不可以為浮點數
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: list indices must be integers, not float
>>> a[-1]
5
>>> a[-2]
4
>>> a[-3]
3
>>> a[6] #索引超出界限
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> a[-6]
0
>>> a[-7] #索引超出界限
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
與字串一樣, 可以用切片 (slice) 來擷取串列中的多個元素 (傳回子串列), 格式如下 :
[start:end:step] 會擷取索引 start 至索引 end-1 (不包含索引 end), 跳 step 次
例如 :
[start:end:step] 會擷取索引 start 至索引 end-1 (不包含索引 end), 跳 step 次
例如 :
>>> a=[0,1,2,3,4,5]
>>> a[:] #擷取整個串列
[0, 1, 2, 3, 4, 5]
>>> a[3:] #索引 3 至結尾
[3, 4, 5]
>>> a[:3] #開頭至索引 2 (不包含 end)
[0, 1, 2]
>>> a[2:4] #索引 2 至 3 (不包含 end)
[2, 3]
>>> a[0:5:2] #索引 0 至 5 間隔 2
[0, 2, 4]
>>> a[0:5:3] #索引 0 至 5 間隔 3
[0, 3]
>>> a=[0,1,2,3,4,5]
>>> del a[3] #刪除 a[3]
>>> a
[0, 1, 2, 4, 5]
>>> a[3] #a[3] 由後面的 4 遞補了
4
>>> del a[-1] #負索引 : 刪除倒數第 1 個元素
>>> a
[0, 1, 2, 4]
注意, del 既非內建函數, 亦非串列的方法, 它是 Python 指令 del, 不只可用來刪除串列元素, 也可用來刪除物件以釋放記憶體, 例如 :
>>> a=[1,2,3]
>>> a
[1, 2, 3]
>>> del a #從記憶體中刪除 a 變數
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined #變數 a 的記憶體已經被釋放了
若要查詢串列中是否含有某元素可用 in 與 not in 運算子, 傳回值為 True/False, 語法如下 :
運算元 in 串列
運算元 not in 串列
例如 :
>>> 'a' in ['a','b','c']
True
>>> 'a' not in ['a','b','c']
False
>>> 'abc' not in ['a','b','c']
True
>>> 'abc' in ['a','b','c']
False
串列也常被用在多重指定 (又稱為開箱 unpacking), 但是等號兩邊變數與元素個數必須相同, 否則會產生錯誤, 例如 :
>>> x,y,z=['a','b','c'] #多重指定
>>> x
'a'
>>> y
'b'
>>> z
'c'
>>> w,x,y,z=['a','b','c'] #等號兩邊個數不一致
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: need more than 3 values to unpack
>>> x,y=['a','b','c'] #等號兩邊個數不一致
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
上面提到的 range() 函數也可以用在多重指定賦值, 例如 :
>>> a,b,c=range(3) #列舉 0,1,2 給 a,b,c
>>> a
0
>>> b
1
>>> c
2
>>> type(a)
<class 'int'>
>>> a,b,c=range(5) #但不可超出所需要之列舉
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 3)
3. 用內建函數操作串列 :
下列的內建函數可用在串列的操作, 它們會傳回新的串列 :
函數 | 說明 |
len(obj) | 傳回物件元素個數 |
min(obj) | 傳回物件中數值最小的元素 |
max(obj) | 傳回物件中數值最大的元素 |
sum(obj) | 傳回物件所有元素之和 |
sorted(obj) | 傳回由小到大排列之物件 |
reversed(obj) | 傳回與原串列元素順序相反之迭代物件 |
next(iterator) | 傳回迭代物件的下一個元素 |
zip(obj1, obj2) | 傳回兩個物件元素一對一配對 tuple 組成的串列 |
函數 len() 會傳回串列中元素的個數, 例如 :
>>> len([1,2,3,4,5])
5
>>> len([123, 3.14, "abc", True])
4
函數 min(), max(), 與 sum() 是用在串列元素為數值的情況, 分別傳回元素的最小值, 最大值, 以及全部元素和 :
>>> min([1,2,3])
1
>>> max([1,2,3])
3
>>> sum([1,2,3])
6
不過 min() 與 max() 也可以用在元素全部為字串的情況, 這時是逐一比較字串中的 ASCII 碼 :
>>> max(['a','b','c']) #'c' 的 ASCII 碼較大
'c'
>>> min(['a','b','c']) #'a' 的 ASCII 碼較小
'a'
>>> max(['aa','aA','Aa','AA']) #'aa' 的 ASCII 碼較小
'aa'
>>> min(['aa','aA','Aa','AA']) #'AA' 的 ASCII 碼較小
'AA'
但是, 不論 min(), max(), 還是 sum() 都無法處理元素為數字與字串混雜的串列, 因為 Python 不知道要如何比較 :
>>> min([1,'b','c']) #無法對數字與字串進行比較
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported types for __lt__: 'str', 'int'
>>> sum([1,'b',3]) #無法對數字與字串進行加總
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported types for __add__: 'int', 'str'
函數 sorted() 會將串列元素由小至大排序後傳回新串列, reversed() 則由大至小排序, 原串列不受影響 (不是 in-place 運算), 例如 :
>>> a=[5,1,0,3,2,4]
>>> sorted(a) #由小至大排序
[0, 1, 2, 3, 4, 5]
>>> a
[5, 1, 0, 3, 2, 4] #原串列不受影響
>>> a=[5,1,0,3,2,4]
>>> sorted(a) #由小至大排序
[0, 1, 2, 3, 4, 5]
>>> a
[5, 1, 0, 3, 2, 4] #原串列不受影響
sorted() 也可以對字串串列排序, 依據 ASCII 碼的由小至大先後排列, 因此數字會比字母優先 (因 0~9 之 ASCII 為 48~57), 大寫字母 (ASCII 為 65~90) 又比小寫字母 (ASCII 為 97~122) 優先, reversed() 則反過來, 不過 reversed() 函數傳回的不是串列, 而是一個迭代物件 (iterator), 可用 next() 函數取得下一個元素, 也可以用 list() 將其轉成串列, 例如 :
>>> a=['a','3','B','1','c','A','b','2','C']
>>> sorted(a)
['1', '2', '3', 'A', 'B', 'C', 'a', 'b', 'c'] #數字先, 其次大寫, 最後是小寫
>>> a=['aA','aa','AA','Aa','BB','Bb','bB','bb']
>>> sorted(a)
['AA', 'Aa', 'BB', 'Bb', 'aA', 'aa', 'bB', 'bb'] #第一個字母先排序, 再排序第二個字母
>>> a
['aA', 'aa', 'AA', 'Aa', 'BB', 'Bb', 'bB', 'bb'] #原串列內容不便 (因不是 in-place)
>>> reversed(a) #reversed() 傳回的是 iterator 物件, 不是串列
['bb', 'bB', 'Bb', 'BB', 'Aa', 'AA', 'aa', 'aA'] #順序跟原串列相反
>>> a
['aA', 'aa', 'AA', 'Aa', 'BB', 'Bb', 'bB', 'bb'] #原串列內容不便 (因不是 in-place)
>>> a=[1,2,3]
>>> r=reversed(a)
>>> r
<reversed> #傳回迭代物件
>>> next(r) #取出迭代元素
3
>>> next(r)
2
>>> next(r)
1
>>> next(r) #迭代物件已空, 出現錯誤
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration:
>>> r
<reversed> #迭代物件還在, 但內容已空
>>> list(r) #用 list() 轉成串列, 是空串列
[]
>>> a=['a',3,'B',1,'c','A','b',2,'C'] #元素有數字也有字串
>>> sorted(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported types for __lt__: 'str', 'int'
但是傳給 reversed() 卻不會產生錯誤, 可以正確地將元素順序反轉
>>> a=['a',3,'B',1,'c','A','b',2,'C'] #混和字串與數字元素的串列
>>> r=reversed(a) #reversed() 不會出現錯誤
>>> r
<reversed>
>>> list(r) #將迭代物件轉成串列
['C', 2, 'b', 'A', 'c', 1, 'B', 3, 'a'] #順序與原串列相反
最後來測試 zip(), 此函數接受兩個元素個數相等的串列, zip() 會將相對應元素兩兩配成一個 tuple, 然後組成一個串列傳回, 例如 :
>>> a=[1,2,3]
>>> b=['a','b','c']
>>> c=zip(a,b) #把對應元素 (1,'a') 等送作堆
>>> c
<zip> #傳回 zip 物件 (也是迭代物件)
>>> type(c)
<class 'zip'>
>>> list(c) #將 zip 物件轉成串列
[(1, 'a'), (2, 'b'), (3, 'c')]
>>> next(c) #轉成串列會完成迭代, 迭代物件將變空
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration:
>>> c=zip(a,b) #重新產生 zip 物件
>>> next(c) #用 next() 迭代取出下一個迭代元素
(1, 'a')
>>> next(c)
(2, 'b')
>>> next(c)
(3, 'c')
>>> list(c) #迭代 3 次就成空了
[]
3. 串列物件的方法 :
Python 的串列物件也提供了幾個方法來操作陣列 :
方法 | 說明 |
append(obj) | 將一個元素添加至串列尾端 |
extend(seq) | 將一個序列物件添加至串列尾端 |
insert(index, obj) | 將一個元素 obj 添加至串列中的指定索引 index 前面 |
remove(obj) | 從串列中刪除指定之元素 |
pop(index) | 取出並傳回指定索引之元素 (預設索引 -1) |
sort() | 將串列元素排序 (由小到大) |
reverse() | 將串列元素反向排序 (由大到小) |
count(obj) | 傳回串列中出現 obj 元素的次數 |
index(obj) | 傳回元素 obj 在串列中的索引 |
copy() | 複製串列元素 |
clear() | 刪除串列中的全部元素 |
注意, 這些方法都是就地 (in-place) 運作的, 亦即這些方法是直接在串列上操作, 而非在複本中操作. 除了 pop() 外都沒沒有傳回值 (或者說傳回 None), 因此不要把傳回值設給原串列, 這樣會讓原串列變成 None.
例如 :
append() 的作用是將傳入的元素加入串列的尾端, 串列的元素可以是任何型態物件 :
>>> a=['a','b','c']
>>> a.append('d') #在尾端加入 'd'
>>> a
['a', 'b', 'c', 'd']
>>> a.append([1,2]) #在尾端加入串列
>>> a
['a', 'b', 'c', 'd', [1, 2]]
>>> a.append((3,4)) #在尾端加入元組
>>> a
['a', 'b', 'c', [1, 2], (3, 4)]
>>> a=[1,2,3]
>>> b=['a','b','c']
>>> a.extend(b) #b 串接到 a 後面
>>> a
[1, 2, 3, 'a', 'b', 'c']
>>> b
['a', 'b', 'c']
>>> b.extend(a) #a 串接到 b 後面
>>> b
['a', 'b', 'c', 1, 2, 3, 'a', 'b', 'c']
串列串接也可以用 + 或 += 運算子, 例如 :
>>> a=[1,2,3]
>>> b=['a','b','c']
>>> a=a + b #b 串接到 a 後面
>>> a
[1, 2, 3, 'a', 'b', 'c']
>>> b
['a', 'b', 'c']
>>> b += a #a 串接到 b 後面
>>> b
['a', 'b', 'c', 1, 2, 3, 'a', 'b', 'c']
insert() 是在指定索引前面加入元素, 如果索引超出界線不會出現錯誤, 而是自動放在最後面. 索引也可以是負值, -1 是倒數第一個 :
>>> a=['a','b','c']
>>> a.insert(2,1) #在索引 2 前面加入 1
>>> a
['a', 'b', 1, 'c'] #加在原索引 2 元素 'c' 前面
>>> a.insert(6,'e') #指定索引 6 超出界限, 會被放在最後面
>>> a
['a', 'b', 1, 'c', 'e']
>>> a.insert(-2,2) #在倒數第 2 個 'c' 前插入 2
>>> a
['a', 'b', 1, 2, 'c', 'e']
remove() 則是從串列中刪除指定之元素, 若串列中沒有該元素會產生錯誤 :
>>> a=['a','b','c']
>>> a.remove('b') #刪除元素 'b'
>>> a
['a', 'c']
>>> a.remove('d') #刪除一個不存在的元素會產生錯誤
Traceback (most recent call last):
File "<stdin>", line 1, in
pop() 函數會從串列中取出指定索引之元素, 並從串列中刪除此元素後將其傳回, 這是串列方法中唯一有傳回值者. 如果沒有指定索引, 預設為 -1, 亦即取出最後一個元素傳回. 若索引超出界限將產生錯誤, 例如 :
>>> a=[0,1,2,3,4,5]
>>> a.pop() #取出末端元素 5
5
>>> a
[0, 1, 2, 3, 4]
>>> a.pop(-1) #取出末端元素 4
4
>>> a
[0, 1, 2, 3]
>>> a.pop(2) #取出索引 2 元素 2
2
>>> a
[0, 1, 3]
>>> a.pop(5) #取出引 5 元素 (超出界限)
Traceback (most recent call last):
File "<stdin>", line 1, in
sort() 函數會將串列元素做升冪排序, 如果傳入參數 reverse=True 的話就會做降冪排序.
>>> a=[5,1,3,2,0,4]
>>> a.sort()
>>> a
[0, 1, 2, 3, 4, 5]
>>> a.sort(reverse=True)
>>> a
[5, 4, 3, 2, 1, 0]
如果串列的元素是字串, 則排序是依據 ASCII 碼做升冪排序, 因此數字會比字母優先 (因 0~9 之 ASCII 為 48~57), 大寫字母 (ASCII 為 65~90) 又比小寫字母 (ASCII 為 97~122) 優先, reversed() 則反過來,
>>> a=['a','3','B','1','c','A','b','2','C']
>>> a.sort()
>>> a
['1', '2', '3', 'A', 'B', 'C', 'a', 'b', 'c'] #字串依據 ASCII 碼升冪排序
若傳入 reverse=True 則做降冪排序 :
>>> a=['a','3','B','1','c','A','b','2','C']
>>> a.sort(reverse=True) #字串依據 ASCII 碼排序
>>> a
['c', 'b', 'a', 'C', 'B', 'A', '3', '2', '1']
與內建函數 sorted() 一樣, 不要對混和數字與字串的串列排序, 這樣會產生錯誤, 例如 :
>>> a=['a',3,'B',1,'c','A','b',2,'C'] #串列元素有數值也有字串
>>> a.sort()
Traceback (most recent call last):
File ">stdin>", line 1, in >module>
TypeError: unsupported types for __lt__: 'str', 'int'
>>> a=['a',3,'B',1,'c','A','b',2,'C'] #串列元素有數值也有字串
>>> a.sort()
Traceback (most recent call last):
File ">stdin>", line 1, in >module>
TypeError: unsupported types for __lt__: 'str', 'int'
注意, 串列物件的 sort() 方法與內建函數 sorted() 最大的不同是, sort() 是就地 (in-place) 操作, 直接在串列物件上排序, 執行後串列元素的順序被改變, 沒有傳回值; 而 sorted() 函數是在一個副本上排序, 執行後傳回此副本的參考, 元串列不受影響.
count() 方法會傳回指定之元素在串列中出現的次數 (整數), 例如 :
>>> a=[1,2,3,3,3,2]
>>> a.count(1)
1
>>> a.count(2)
2
>>> a.count(3)
3
>>> a=['a','b','c',1,2,3,'a','b']
>>> a.count('a')
2
>>> a.count('b')
2
>>> a.count('c')
1
>>> a.count('d') #無此元素
0
index() 方法會傳回傳入元素在串列中的索引, 例如 :
>>> a=[0,1,2,3,4,5]
>>> a.index(0)
0
>>> a.index(3)
3
>>> a.index(5)
5
copy() 方法會將串列複製一份副本, 並傳回此副本的參考. 這跟用切片的 [:] 效果是一樣的, 都是產生一個新串列, 例如 :
>>> a=[1,2,3]
>>> b=a.copy() #傳回 a 串列副本的參考, 指定給串列 b
>>> b
[1, 2, 3]
>>> b == a #用 == 比較兩者內容相同
True
>>> b is a #用 is 比較兩者參考不同 (不同物件)
False
>>> c=a[:] #用切片複製串列
>>> c == a #用 == 比較 a,c 兩者內容相同
True
>>> c == b #用 == 比較 b,c 兩者內容相同
True
>>> c is a #用 is 比較 a,c 兩者參考不同 (不同物件)
False
>>> c is b #用 is 比較 b,c 兩者參考不同 (不同物件)
False
>>> b[0]='b' #更改 b 串列內容
>>> c[0]='c' #更改 c 串列內容
>>> b
['b', 2, 3]
>>> c
['c', 2, 3]
>>> a #串列 a,b,c 互不影響
[1, 2, 3]
clear() 會清除串列內所有元素, 使其成為一個空字串, 例如 ;
>>> a=[1,2,3]
>>> a
[1, 2, 3]
>>> a.clear()
>>> a
[] #變成空串列
字串有 2 個方法與串列密切相關 : join() 與 split(), 兩者為反運算, join() 是將一個串列以一個膠合字串串接成一個新字串後傳回; 而 split() 則是以一個分拆字串為界, 將一個字串拆成數個子字串組成的串列後傳回, 例如 :
>>> a=['123','456','789']
>>> b='-'.join(a) #以 '-' 串接
>>> b
'123-456-789'
>>> c=b.split('-',1) #以 '-' 自左向右分拆 1 次
>>> c
['123', '456-789']
>>> c=b.split('-') #以 '-' 自左向右全部分拆
>>> c
['123', '456', '789']
>>> c=b.rsplit('-') #以 '-' 自右向左全部分拆
>>> c
['123', '456', '789']
>>> c=b.rsplit('-',1) #以 '-' 自右向左分拆 1 次
>>> c
['123-456', '789']
三. 元組 (tuple) :
元組是串列的不可變版 (可視為常數串列), 其物件建立後內容即不可變更, 亦即, 在上述串列中會改變物件內容的指定運算不能使用, 而且物件方法也只有 index() 與 count() 兩個而已. 既然已經有串列這麼好用的型別了, 為何 Python 又要定義 tuple 型別呢? 理由如下 :
- tuple 比 list 占用的記憶體較少
- 在元素必須固定不可以被變更場合 tuple 最保險
- 函數的引數是以 tuple 形式傳入的
- tuple 很容易轉成字典 dict
- 具名元組 (named tupe) 可作為簡化之物件用
通常元組使用 () 運算子來標示, 元素之間用半形逗號隔開, 即使只有一個元素, 也必須在結尾加上逗號. 事實上, () 運算子是非必要的, Python 是用逗號來辨別這是一個 tuple, 例如 :
>>> name=('peter',) #元組只有一個元素時結尾務必有逗號
>>> type(name)
<class 'tuple'>
>>> name='peter', #即使不用 (), 只要有逗號就會被認為是 tuple
>>> type(name)
<class 'tuple'>
>>> name=('peter') #沒有結尾逗號會被認為是字串
>>> name
'peter'
>>> type(name)
<class 'str'>
可見真正定義一個元組的是逗號而非小括弧 (), 用小括弧把元組的元素包起來只是讓我們更容易識別這是一個 tuple 而已 (當然若使用中括號就被視為串列, 大括弧表示集合或字典). 如果元組有多個元素, 則結尾的逗號可有可無 (因為已經至少有一個逗號足以識別為 tuple 了), 例如 :
>>> name='peter','amy','kelly' #多於一個元素時結尾逗號可省略
>>> type(name)
<class 'tuple'>
>>> name
('peter', 'amy', 'kelly')
>>> name='peter','amy','kelly', #結尾有逗號當然沒問題
>>> name
('peter', 'amy', 'kelly')
>>> type(name)
<class 'tuple'>
>>> name=('peter','amy','kelly') #用小括弧宣揚其 tuple 身分
>>> name
('peter', 'amy', 'kelly')
>>> type(name)
<class 'tuple'>
>>> name=('peter','amy','kelly',) #結尾有逗號當然沒問題
>>> name
('peter', 'amy', 'kelly')
>>> type(name)
<class 'tuple'>
>>>
元組乃是常數串列, 所以無法使用 append() 方法從空的元組建立 tuple.
第二種建立 tuple 的方法是使用內建函數 tuple(), 它會將其他型別物件如字串, 串列, 字典, 以及集合轉成元組, 例如 :
>>> tuple('abc') #字串轉元組:每個字元會被打散成字元 tuple
('a', 'b', 'c')
>>> tuple(['a','b','c']) #串列轉元組
('a', 'b', 'c')
>>> tuple({'a':1,'b':2,'c':3}) #字典轉元組
('b', 'c', 'a')
>>> tuple({'a','b','c'}) #集合轉元組
('b', 'c', 'a')
2. 元組的基本操作 :
由於元組是常數串列, 所以元組的可操作方式比串列少, 總之要更改 tuple 內容的操作是不允許的 :
- 串接 (使用 + 運算子)
- 複製 (使用 * 運算子)
- 切片 (使用 [] 運算子)
- 查詢元素 (使用 in 與 not in)
- 多重指定
>>> a=(1,2,3,)
>>> b=(4,5,6,)
>>> c=a+b
>>> c
(1, 2, 3, 4, 5, 6)
>>> a
(1, 2, 3)
>d=a*3
>>> d
(1, 2, 3, 1, 2, 3, 1, 2, 3)
元組與串列一樣是繼承 sequence 之序列型別, 因此可以使用整數索引去擷取個元素, 例如 :
>>> a=0,1,2,3,4,5
>>> a[0]
0
>>> a[3]
3
>>> a[5]
5
但是元組屬於不可變型別 (immutable), 所以物件建立後無法再用指定運算子更改其內容, 例如 :
>>> a=(0,1,2,3,4,5)
>>> a[0]='a'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> a=0,1,2,3,4,5,
>>> a
(0, 1, 2, 3, 4, 5)
>>> a[:] #擷取全部元素
(0, 1, 2, 3, 4, 5)
>>> a[3:] #擷取索引 3 至結尾的元素
(3, 4, 5)
>>> a[:3] #擷取開頭至索引 2 (不包括結束索引 3)
(0, 1, 2)
>>> a[2:4] #擷取索引 2 至 3 (不包括結束索引 4)
(2, 3)
>>> a[0:5:1] #擷取索引 0 至索引 5 步階 1 (不包括結束索引 5)
(0, 1, 2, 3, 4)
>>> a[0:5:2] #MicroPython 不支援步階大於 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NotImplementedError: only slices with step=1 (aka None) are supported
注意, 上面串列的測試顯示, 串列的切片步階可大於 1, 但在元組卻沒有, MicroPython 的元組在切片的步階 (step) 參數上只支援 step=1, 不支援大於 1 的步階, 這在 CPython 執行結果為 :
C:\Users\cht>python
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)]
on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> a=0,1,2,3,4,5
>>> a[0:5:2]
(0, 2, 4)
要查詢指定元素有無在 tuple 中可用 in 與 not in 指令, 例如 :
>>> a=('a','b','c')
>>> 'a' in a
True
>>> 'a' not in a
False
>>> 'abc' not in a
True
與 list 一樣, tuple 也可以做多重指定 (又稱為開箱, unpacking), 例如 :
>>>x,y,z='a','b','c',
>>> x
'a'
>>> y
'b'
>>> z
'c'
>>> w,x,y,z=('a','b','c') #兩邊不一致
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: need more than 3 values to unpack
>>> y,z=('a','b','c') #兩邊不一致
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
3. 用內建函數操作元組 :
雖然元組是串列的不可變版, 但下列內建函數並非就地 (in-place) 操作, 不會去更改元組內容, 因此也可以用在元組 :
函數 | 說明 |
len(obj) | 傳回物件元素個數 |
min(obj) | 傳回物件中數值最小的元素 |
max(obj) | 傳回物件中數值最大的元素 |
sum(obj) | 傳回物件所有元素之和 |
sorted(obj) | 傳回由小到大排列之物件 |
reversed(obj) | 傳回與原物件元素順序相反之迭代物件 |
next(iterator) | 傳回迭代物件的下一個元素 |
zip(obj1, obj2) | 傳回兩個物件元素一對一配對的 zip 物件 |
>>> len((1,2,3,4,5))
5
>>> len((123, 3.14, "abc", True))
4
>>>
函數 min(), max(), 與 sum() 會傳回元素為數值的元組中的最小值, 最大值, 以及加總值 :
>>> min((1,2,3))
1
>>> max((1,2,3))
3
>>> sum((1,2,3))
6
這三個函數也可以用在全部元素是字串情況 (依 ASCII 碼逐一比對), 但不能用在元素包含數值與字串混合情況 :
>>> max(('a','b','c'))
'c'
>>> min(('a','b','c'))
'a'
>>> max(('aa','aA','Aa','AA'))
'aa'
>>> min(('aa','aA','Aa','AA'))
'AA'
>>> min((1,'b','c'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported types for __lt__: 'str', 'int'
>>> sum((1,'b',3))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported types for __add__: 'int', 'str'
>>> a=(5,1,0,3,2,4)
>>> sorted(a) #升冪排序, 傳回串列
[0, 1, 2, 3, 4, 5]
>>> a
(5, 1, 0, 3, 2, 4)
>>> reversed(a) #反序排序, 傳回 reversed 物件
<reversed>
>>> list(reversed(a)) #將 reversed 物件轉成串列
[4, 2, 3, 0, 1, 5]
>>> b=reversed(a) #反序排序, 傳回 reversed 物件
>>> next(b) #取出 reversed 物件元素
4
>>> next(b)
2
>>> next(b)
3
>>> next(b)
0
>>> next(b)
1
>>> next(b)
5
>>> next(b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration:
而 zip() 函數可將傳入的兩個 tuple 物件對應元素配對後傳回 zip 物件 (迭代物件), 可以用 next() 函數檢視此 zip 物件之元素, 也可以用 tuple() 函數轉成元組, 或者用 list() 函數轉成串列 :
>>> a=1,2,3,
>>> b=4,5,6,
>>> zip(a,b) #傳回 zip 物件
<zip>
>>> list(zip(a,b)) #轉成 list
[(1, 4), (2, 5), (3, 6)]
>>> tuple(zip(a,b)) #轉成 tuple
((1, 4), (2, 5), (3, 6))
>>> c=zip(a,b)
>>> type(c)
<class 'zip'>
>>> next(c) #取出下一個迭代元素
(1, 4)
>>> next(c) #取出下一個迭代元素
(2, 5)
>>> next(c) #取出下一個迭代元素
(3, 6)
因為元組是不可變的串列, 所以串列物件的方法中只有 count() 的 index() 在元組中可用 :
方法 | 說明 |
count(obj) | 傳回串列中出現 obj 元素的次數 |
index(obj) | 傳回元素 obj 在串列中的索引 |
例如 :
>>> a=(1,2,3,3,3,2)
>>> a.count(1)
1
>>> a.count(2)
2
>>> a.count(3)
3
>>> a=('a','b','c',1,2,3,'a','b')
>>> a.count('a')
2
>>> a.count('b')
2
>>> a.count('c')
1
>>> a.count('d')
0
>>> a=[0,1,2,3,4,5]
>>> a.index(0)
0
>>> a.index(3)
3
>>> a.index(5)
5
以上便是 MicroPython 序列型別的完整測試, 還真長.
小狐狸你好:
回覆刪除此篇的大標題 二.串列,1.建立串列:
當中的這段
>>> a=list()
>>> type(a)
>>> a=list(123, 3.14, "abc", True)
>>> a
[123, 3.14, 'abc', True]
我試著照做,但是出現錯誤訊息
>>> a=list()
>>> type(a)
>>> a=list(123, 3.14, "abc", True)
Traceback (most recent call last):
File "", line 1, in
a=list(123, 3.14, "abc", True)
TypeError: list expected at most 1 argument, got 4
在MicroPython跟Python都一樣出現這個ERROR,其中Python的2.7.17版跟3.8.0版皆出現此ERROR
用google翻譯錯誤訊息是說參數最多應只有1個,找到4個
想請問這個狀況該怎麼排除?
阿麥您好, 感謝您的留言, 抱歉, 我少打了第二層小括弧, 正確是這樣 :
回覆刪除>>> a=list((123, 3.14, "abc", True))
>>> a
[123, 3.14, 'abc', True]
您查的資訊是對的, list() 函數只接受一個參數, 那就是 tuple, 所以需要兩層小括號, 內層代表 tuple.
原來如此!感謝解惑。:)
回覆刪除