2020年2月29日 星期六

電腦與手機鏡頭視訊透過 WiFi 連線的方法

今天在 Youtube 看到有人分享如何將手機鏡頭的視訊透過 WiFi 連線到電腦上的教學, 對於製作動手做的視訊教學很有用 :

如何把手機當電腦視訊鏡頭使用教學- DroidCam




DroidCam - 讓你把手機變成視訊鏡頭




這個方法需要在電腦端與手機端分別下載軟體才行, 電腦端要到下列網址下載安裝 DroidCam Client 這軟體 :

https://www.dev47apps.com/droidcam/windows/

此軟體經 VirusTotal 掃描為安全無毒軟體, 我安裝的是最新 6.1 版, 安裝時會跳出下面視窗, 按 "安裝" 鈕但取消 "永遠信任" 項即可.

其次到手機搜尋 "DroidCam" 下載安裝其中的 DroidCam Wireless Webcam 這個 App, 開啟 WiFi 連線電腦所連線的同一基地台, 畫面會顯示手機獲得之 內網 IP (此處為 192.168.43.29) 與 4747 埠, 此 App 固定用 4747 埠通訊 :




然後在電腦端開啟 DroidCam 軟體, 輸入手機之 IP 按 Start 鈕即可 :




連線建立後即在視窗中間嵌入手機鏡頭視訊畫面 :




按左下角的第二個 "Pop Out Video Preview" 按鈕會開啟單獨的視訊視窗.

有了這個工具就可以把淘汰下來的堪用手機拿來做為視訊教學鏡頭了. 等這陣子 AWS 認證忙完後就來開始製作 MicroPython on ESP32 的實驗視頻教學影片製作吧!

參考 :

利用舊安卓手機和DroidCam做台式機攝像頭

好書 : D3 for the impatient

今天找到一本 D3.js 的好書 :

D3.js for the Impatient


Source : 天瓏


D3.js 學習曲線較陡, 要花蠻多時間學習, 此書書名 "for the impatient" 顧名思義就是要讓學習者能快速上手, 是 D3 初學者不可多得的好書.

製作 Win10 1909 版系統映像檔

上週我的 ACER Swift5 筆電升版為 1909 版, 但一直沒時間製作新的映像檔, 昨天終於把 C 碟下的檔案備份到隨身硬碟去, 今天傍晚回到鄉下順利製作了映像檔, 由於高達 62GB, 所以存放於 WD 那顆 2T 硬碟裡.

在做映像檔之前要先做的清空動作包括 :
  • 下載檔案
  • 文件, 圖片, 影片下的檔案
  • 資源回收桶
  • 瀏覽器隱私權與安全性 (清除瀏覽資料)
  • 檔案總管之快速存取
在開始備份之前, 先查看檔案總管本機, 記下 D 碟可用空間, 以便計算映像檔用掉多少空間.


1. 開啟控制台/系統, 點左下角的 "安全性與維護" : 




2. 點左下角的 "檔案歷程記錄" (如未開啟要先開啟) : 




3. 點左下角的 "系統映像檔備份" : 




4. 點選要備份到 D 碟 :





5. 開始備份 :




映像檔製作完成後, 再查看檔案總管本機 D 碟空間, 計算映像檔共用掉 62GB 空間, 這裡面還包括了 OneDrive 的 12GB 與 DropBox 的 2GB, 故實際上 Win10 本身應該 45~50 GB 左右.

參考 :

升級 Win10 並建立系統映像檔
回復舊版 Win10 停止自動更新並建立修復隨身碟

2020年2月24日 星期一

Python 學習筆記 : 基本語法 (一) : 變數, 資料型態, 與運算子

用 Python 那麼久了, 筆記也寫了一些, 但卻一直沒有對基本語法做個完整測試與整理. 此篇自 2019 年 8 月卸下邏輯設計授課重擔後配合二哥學習 Python 開始整理, 但雜務太多斷斷續續, 利用 2020 舊曆年連假大致告一段落, 但仍不完整, 直到今天才完工.

其實之前在學 MicroPython 時也對 Python 基本語法做過測試, 但那時太倉促, 而且是在 ESP8266 物聯網嵌入式設備上進行, 而非在 CPython 上, 所以也不太完整, 參考 :

MicroPython on ESP8266 (二) : 數值型別測試
MicroPython on ESP8266 (三) : 序列型別測試
MicroPython on ESP8266 (四) : 字典與集合型別測試

CPython 核心語法包括下列 7 個部分 :
  1. 分行與併行
  2. 縮排
  3. 註解
  4. 變數與常數
  5. 資料型態
  6. 運算子
  7. 流程控制
  8. 函數
  9. 自訂函數
  10. 變數作用範圍
下面這個網站可找到豐富的 Python 程式範例 :

# Python Code Examples (Program Creek)

另外屬於 Python 程式寫作風格 (廣義的語法) 參考 :

PEP8 - Python 程式碼風格指引(中文)

其他不錯的網站參考 :

https://www.w3schools.com/python/default.asp

本篇測試是讀過下列書籍後整理的 :
  1. 深入淺出 Python 第二版 (歐萊禮)
  2. 一步到位 Python 程式設計 (旗標, 陳惠貞)
  3. 精通 Python-運用簡單的套件進行現代運算 (歐萊禮)
  4. Python 神乎其技 (旗標, 江良志譯)
這些書都各有所長, 但以第 2 本較有系統且完整.


一. 分行與併行 :

Python 程式的最小執行單位是敘述 (statement), 它可以是一個指派 (assignment), 運算式 (expression), 或函數呼叫 (function call). 一個敘述通常占一行, 行尾直接跳行不需要像 Java 與 C 那樣使用分號當結束標記, 但即使行尾加分號也不會有錯誤, 例如 :

>>> a='hello world'         
>>> print(a) 
hello world
>>> a='hello world'; 
>>> print(a); 
hello world

分號在 Python 中的作用是併行, 亦即多個敘述可寫在同一行但用分號隔開, 例如 :

>>> a='hello world'; print(a); 
hello world

若敘述太長, 可在敘述的任何位置用倒斜線 \ 斷開, 並立即按 enter 跳行至下一行接續, 將敘述分成多行, 例如 :

>>> msg='hello \
world! \
Tony'
>>> print(msg)
'hello world! Tony'

注意, 倒斜線後面不可以有空白, 必須立即跳行, 否則會出現 "SyntaxError: EOL while scanning string literal" 錯誤 (在 IDLE 介面會被自動消除不會報錯, 但在 .py 程式檔執行時會出錯). 對於串列, 元組, 集合, 字典這四個資料結構, 因為有括弧作為界線, 其元素或項目太多時可直接跳行不需要用 \ 串接 (用也 OK).

另外一種分行的方法是使用小括弧 (), 這樣就不需要倒斜線了, 例如 :

>>> msg=('hello ' + 
'world! ' + 
'Tony') 
>>> print(msg)   
'hello world! Tony'

將字串用 + 串接, 並且用小括弧包起來就不需要倒斜線, 也可以將整個敘述包起來, 例如 :

>>> (print('hello ' +
   'world! ' +
   'Tony'))
hello world! Tony


二. 縮排 :

Python 程式的特點是強制要求縮排 (indentation), 其唯一的程式區塊分隔符號為冒號, 冒號換行後開始縮排, 開始縮排標示著一個程式區塊之開始, 取消縮排則標示區塊結束. 縮排是 Python 語法的一部分, 違反縮排規則的程式將無法執行. 

每個程式區塊 (if, else, for, def, class, try, except 等) 內都必須有一致的縮排 (REP 建議是用 4 個空白為一個縮排單位), 但各區塊之縮排可以不同. 縮排可使程式碼格式整齊劃一, 提高可讀性與降低維護難度, 特別是在多人共同開發大型程式時, 更能彰顯強制縮排的優點.

if score >=60 :
    result='pass'
else :
    result='no pass'

注意, 編輯 Python 程式時最好是按 "Space" 鍵來建立縮排, 不要按 "Tab" 鍵.  如果編輯器有類似 "Insert spaces instead of Tab" 的設定選項建議勾選, 這樣按 "Tab" 鍵時會以所設定之空格 (space) 取代.
   

三. 註解 :

Python 有兩種註解符號 :
  1. 單行註解 :
    使用井字號 #, 此符號開始到該行結尾會被解譯器忽略不予執行. 
  2. 多行註解 :
    使用成對的 3 個連續單引號 ''' 或雙引號 """, 解譯器遇到 ''' 或 """ 時會忽略之後一直到下一個 ''' 或 """ 間之敘述. 在函數定義的最前面都會用多行註解來製作函數的使用說明. 
多行註解方式也可用來製作多行字串, 例如 :

>>> msg='''hello 
world! 
Tony'''  
>>> print(msg)
'hello\nworld!\nTony'

函式內容的第一行應該用多行註解撰寫該函式之功能或摘要, 若後面還有詳細說明, 須先空一行, 再寫說明註解. 例如 :

def get_circle_area() :
    """此函式用來計算圓面積"""

    #圓面積公式=pi*r^2

Python 的函數, 類別, 模組都有一個內建屬性可用來取得其第一行註解, 例如 : 

>>> def get_circle_area() :     
    """此函式用來計算圓面積"""    
    
>>> print(get_circle_area.__doc__)
此函式用來計算圓面積


四. 關鍵字 (keywords) 與識別字 (identifiers)  :

識別字是程式語言中用來命名變數, 常數, 函數, 或物件的詞彙, 它是指向這些物件在記憶體中的參考位址. 關鍵字則是 Python 保留不可用做識別字的詞彙, Python 3 有 33 個關鍵字, 這些關鍵字不能被用作變數或函數等之識別字, 否則執行時會出現語法錯誤 :


Falseclassfinallyisreturn
Nonecontinueforlambdatry
Truedeffromnonlocalwhile
anddelglobalnotwith
aselififoryield
assertelseimportpass
breakexceptinraise


原本在 Python 2 有 31 個關鍵字, 但其中的 print 與 exec 這兩個關鍵字到 Python 3 後被函數化, 於是變成 29 個; Pyhton 3 又另外增加了 None, False, True, 以及 nonlocal 這四個關鍵字, 到 Python 3.4 開始因支援非同步又增加 async 與 await, 總共是 35 個, 參考 :


Python 的關鍵字可用過內建模組 keyword 的 keylist 屬性查得, 例如 :

>>> import keyword
>>> keyword.kwlist 
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
>>> len(keyword.kwlist) 
35

Python 的識別字有如下限制 :
  1. 有分大小寫. 
  2. 只能使用英文字母, 底線或數字 (但第一個字元不可以是數字). 
  3. 不可使用 Python 關鍵字.
  4. 不要使用與內建函數同名之變數, 例如 str, len, int 等. 
簡言之, 識別字不可用數字開頭, 字元中間不可有空白, 也不能使用特殊字元例如 $, #, %, ? 等等. 雖然 Python 3 以後全面支援 Unicode, 可使用中文字當變數, 但因輸入與維護困難以及可攜性低, 故不建議使用.

>>> 訊息="哈囉"    #可以用中文當變數 (但可攜性低)
>>> print(訊息) 
哈囉

使用關鍵字當識別字會出現語法錯誤, 例如 as (但 As 或 AS, aS 則可) :

>>> as=1                    #不可使用保留字當變數名稱
  File "<stdin>", line 1
    as=1
     ^
SyntaxError: invalid syntax       
>>> As=1                    #As 不是保留字可以用
>>> As
1

下面是不合法的識別字例子 :

2name               (以數字開頭)
_getter!@         (含有特殊字元 ! 與 @)
ab c-de               (不可使用 - 或空格)

Python 是物件導向語言, 其類別與方法名稱之命名方式亦須遵守上述變數與自訂函數識別字之規範. 此外, 類別還有非強制的命名慣例如下 :
  1. 類別名稱: 慣用首字大寫駝峰字, 例如 ClassName 或 Class_Name
  2. 方法名稱: 慣用首字小寫駝峰字, 例如 methodName 或 method_Name


五. 輸出與輸入 : 

從標準輸入 (鍵盤) 讀取使用者輸入可呼叫內建函數 input(str), 傳入參數為提示字串, 其傳回值類型為字串, 故若輸入值為後續要進行計算的數值, 則進行計算前必須呼叫 int(), float() 等內建函數強制轉型, 例如 :

>>> name=input("Please enter your name=")
Please enter your name=tony
>>> type(name)
<class 'str'>             # input() 傳回值為字串類型
>>> price=input("請輸入定價=")
請輸入定價=100
>>> price*0.8
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: can't multiply sequence by non-int of type 'float'
>>> price=float(input("請輸入定價="))      # 呼叫 float() 將 input() 的傳回值轉成數值
請輸入定價=100
>>> price*0.8
80.0  

若要一次輸入多個變數, 可用 Python 的同步指定與字串物件的 split() 方法處理, 例如 :

>>> account, pwd=input("請輸入帳號密碼, 以空格隔開:").split() 
請輸入帳號密碼, 以空格隔開:tony 123456
>>> account
'tony'
>>> pwd
'123456' 

輸出到 Console 則可呼叫內建函數 print(msg), 傳入參數為字串 : 

>>> print("account=" + account + " pwd=" + pwd)
account=tony pwd=123456


六. 資料型態 :

Python 的內建資料型態可分成 3 類共 9 個型別 :


 資料型態種類 說明
 Numeric (數值) int, float bool, complex
 String (字串) str
 Container (容器) tuple, list, dict, set


這 9 種資料型別的關係結構如下圖所示 :




其中 protocol 類別為四個數值型別 (int, float, bool, complex) 的父類別, 它們都是不可迭代的 (non-iterable), 也是不可改變的 (immutable). 序列型別有三種 : str, tuple, 與 list, 而可迭代 (iterable) 型別共有五種, 即三種序列型別再加上 dict 與 set, 其中僅 str 與 tuple 為不可改變, 其餘 list, dict, set 均可改變. 

不可變型別的物件如數值, 字串, 與元組一旦建立, 其內容即固定不變 (即均為常數). 一個指向不可變型別物件的變數, 其賦值改變時並非該物件內容被改變, 而是建立了一個新的物件實體, 然後將變數指向了新的實體, 例如 :

name="tony"
name="peter"

並非字串物件 "tony" 被改成 "peter", 而是建立了一個新的字串物件 "peter", 並將 name 變數指向新實體, 而原來的 "tony" 若無其他變數指向它, 將被系統回收.

容器型別物件 str, tuple, list, dict,與 set 又可按其元素分為有無順序與可否重複, 這五種容器只有 dict 與 set 無順序, 只有 set 元素不可重複, 摘要如下表 :


 特性 int float bool complex str tuple list dict set
 可迭代 no no no no yes yes yes yes yes
 可改變 no no no no no yes yes yes yes
 有順序 x x x x yes yes yes no no
 可重複 x x x x yes yes yes yes no



1. 數值型別 : 

Python 的數值型別有 4 種 :

 數值型別 說明
 int 整數, Python 3 以後範圍只受到記憶體限制.
 float 浮點數, 可用小數點或科學表示法
 bool 布林值, 只有 True (=1) 與 False (=0) 兩個值.
 complex 複數, 由實部 (real) 與虛部 (imag) 組成, 例如 2+i. 


(1). 整數 (int) :

整數在 Python 2 時有分 int (整數, 固定精準度) 與 long (長整數, 無限精準度), 但 Python 3 之後只有無限精準度的長整數, 其型別名稱為 int (不是 long) : 

>>> type(1)                  #整數的型別名稱為 int
<class 'int'> 

Python 3 可表示的整數大小不受限制, 例如 Google 命名由來的 Googol 是 10 的 100 次方 : 

>>> googol=10**100 
>>> googol       
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

注意, 內建系統模組 sys 中有一個 maxsize 屬性, 但這與整數最大值無關, 而是代表 Python 容器類資料 (例如字串, 串列, 與元組等) 的索引之最大值, 亦即容器物件的長度不可超過此值 : 

>>> import sys                   # 引入 sys 模組
>>> sys.maxsize                 # 顯示 maxsize 索引之最大值
9223372036854775807       # for 64-bit 系統
>>> -sys.maxsize-1   
-9223372036854775808 

參考 :

sys.maxsize() in Python

整數可用十進位 (decimal), 二進位 (binary), 八進位 (octal), 以及十六進位 (hexadecimal) 表示, 除了十進位外, 其他進位系統都必須用前置碼 (prefix) 表示其基底 (base), 整理如下表 :


 整數基底 (base) 前置碼 (prefix) 說明
 2 進位 (0~1) 0b 或 0B 0b1100 等於 10 進位之 12
 8 進位 (0~7) 0o 或 0O 0o14 等於 10 進位之 12
 10 進位 (0~9) 無 12 (不可用 012)
 16 進位 (0~9, A~F) 0x 或 0X 0xc 等於 10 進位之 12


注意, 前置碼大小寫皆可, 其次, 十進位沒有前置碼, 前面不可補 0, 例如以 print() 函數 :

>>> 012                          #十進位數不可以補 0
  File "<stdin>", line 1
    012
      ^
SyntaxError: invalid token
>>> 0b1100                     #二進位的 12
12
>>> 0o14                         #八進位的 12     
12
>>> 0xc                            #十六進位的 12
12
>>> a=0b1100 + 0o14     #二進位加八進位結果會以十進位表示
>>> print(a)
24

可見用 print() 函數列印用非十進位表示的數值時,  Python 會將其轉成十進位. Python 提供了下列內建函數可用來進行整數的基底或型態轉換 :


 整數轉換函數 說明
 bin(d) 將十進位整數 d 轉成二進位後以字串型態傳回
 oct(d) 將十進位整數 d 轉成八進位後以字串型態傳回
 hex(d) 將十進位整數 d 轉成十六進位後以字串型態傳回
 int(o) 將物件 o 轉成 int 型態十進位整數 
 int(o, base) 將物件 o 轉成基底為 base 的 int 型態整數


注意, bin(), oct(), hec() 這三個函數只能傳入十進位整數值 (必要參數, 不傳入會出現錯誤); 而 int() 只能傳入整數字串或布林值, 例如 :

>>> bin(12)           #10 進位轉 2 進位
'0b1100'
>>> oct(12)            #10 進位轉 8 進位
'0o14'
>>> hex(12)           #10 進位轉 16 進位
'0xc'
>>> hex(255)         #10 進位轉 16 進位
'0xff'
>>> int('12')          #字串轉整數
12
>>> int('012')        #字串轉整數, 前面的 0 會被忽略
12
>>> int(True)         #不林值轉整數
1


(2). 浮點數 (float) :

浮點數即帶有小數點之數值, 例如圓周率 3.14159, 精密度為 double (倍精度), 大約是到小數點後 17 位, 例如在 Win10 與 Raspberry Pi 3 上分別計算如下無限小數 :

Python 3.5.3 (default, Sep 27 2018, 17:25:39)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 22/7 
3.142857142857143
>>> import math 
>>> math.sqrt(2) 
1.4142135623730951
>>> math.e 
2.718281828459045 

Python 3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 23:09:28) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> 22/7   
3.142857142857143
>>> import math 
>>> math.sqrt(2) 
1.4142135623730951
>>> math.e 
2.718281828459045

浮點數也可以用科學表示法表示, 例如普郎克常數 6.62607*10**(-34) 的科學表示法為 6.62607e-34 或 6.62607E-34 (焦耳秒), 其中 e 或 E (大小寫均可) 表示底數 10, 後面的 -34 為次方, 小於 1 的浮點數若超過小數點四位數就會自動以科學表示法來表示, 例如 :

>>> type(1.234)               #浮點數型別名稱為 float
<class 'float'>
>>> type(1.234e-12) 
<class 'float'>
>>> 6.62607e-34              #科學表示法用 e/E 均可
6.62607e-34
>>> 6.62607E-34
6.62607e-34
>>> 12.3456789e-89        #自動調整為標準科學表示法
1.23456789e-88 
>>> 0.0001
0.0001
>>> 0.00001                      #超過小數點四位數用科學表示法
1e-05

Python 內建函數 float() 可將布林值, 整數, 數值 (整數或浮點數) 字串轉換成浮點數, 但不能轉換複數, 例如 :

>>> float(2)                    #整數轉浮點數
2.0
>>> float(True)              #布林值轉浮點數
1.0
>>> float(False) 
0.0
>>> float("2")                #整數字串轉浮點數
2.0
>>> float("3.14159")     #浮點數字串轉浮點數
3.14159
>>> float(1+2j)               #float() 不可轉換複數
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't convert complex to float


(3). 布林數 (bool) :

布林數只有 True 與 False 兩個值, 用在邏輯運算, 但它其實是整數的子類型, 因為 True 的值為 1, False 的值為 0. 將布林數與整數做運算時, True 會用 1 代替, False 會用 0 代替進行運算, 用 int() 轉換 True 與 False 會分別傳回 1 與 0 :

>>> type(True)     #布林值的型別名稱為 bool
<class 'bool'>
>>> int(True)        #轉成整數
1
>>> int(False)       #轉成整數
0
>>> 5 + True         #True 其實就是整數 1
6
>>> 4 * False         #False 其實就是整數 0
0
>>> 1 + False 
1
>>> 100/False         #發生除以 0 錯誤
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero

內建函數 bool() 可將傳入之其他型態資料轉成布林值, 除了 0, 0.0, False, None, 空字串 '', 空串列 [], 空元組 (), 空字典 {}, 與空集合 set() 等會被轉成 False 外, 其餘都會被轉成 True. 例如 :

>>> bool(1)
True
>>> bool('ok')
True
>>> bool('')
False
>>> bool(' ')
True
>>> bool(None)
False
>>> bool(0)
False
>>> bool(0.0)
False
>>> bool(())
False
>>> bool([])
False
>>> bool({})
False
>>> bool(None)
False


(4). 複數 (complex) :

複數由實部 (real) 與虛部 (imaginary) 組成, 數學中通常使用 i 表示虛部, 工程界則偏好使用 j 表示虛數, 但在 Python 中虛部必須用 j 或 J 標示 (大小寫均可), 不可用 i 或 I.

其次, 虛部數值可在 j 前面或後面, 即一個複數可表示為 z=a +  b j 或 z=a +  j b. 其中 a 與 b 可為整數或浮點數. 但注意, 虛部值為 1 時必須寫出不可省略, 否則會出現 "j is not defined" 錯誤, 例如 :

>>> type(1+1j)         #複數型別名稱為 "complex"
<class 'complex'>
>>> x=1+1j               #虛部值為 1 時必須寫出來
>>> y=1-1j                #虛部值為 1 時必須寫出來
>>> x*y                     #複數乘法
(2+0j)
>>> x+y                     #複數加法
(2+0j)
>>> x/y                      #複數除法
1j
>>> (1+2j)/(1-2j)       #複數除法
(-0.6+0.8j)
>>> x=1+j                 #虛部值為 1 時必須寫出來
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'j' is not defined

Python 有一個內建函數 complex(real, imag) 可傳入兩個參數 (第一參數為實部, 第二為虛部) 來建立一個複數, 例如 :

>>> z=complex(1,2)         #呼叫 complex() 建立複數
>>> type(z)
<class 'complex'>     
>>> print(z)
(1+2j)

此外 complex() 亦可將複數字串, 整數, 浮點數或布林值等轉成複數, 例如 :

>>> x=complex(1)   
>>> x 
(1+0j)
>>> type(x)
<class 'complex'> 
>>> x=complex('1+1j')       #將複數字串轉成複數
>>> x 
(1+1j) 
>>> type(x)   
<class 'complex'>   
>>> complex(False)            #布林值 False 會被轉成 0j
0j
>>> complex(True)             #布林值 True 會被轉成 1+0j
(1+0j)

複數本身也是一個物件, 有 real 與 imag 兩個屬性用來分別儲存實部與虛部之值, 還有一個會傳回其共軛複數的 conjugate() 方法, 例如 :

>>> z=1+2j                  #複數字面值
>>> z
(1+2j)
>>> z.real                     #實部
1.0
>>> z.imag                   #虛部
2.0
>>> z.conjugate()        #傳回共軛複數
(1-2j)


2. 字串 (str) : 

字串可以用引號直接建立字面值 (literal) 或呼叫內建函數 str() 建立字串物件. 用引號建立字串物件有單行與多行兩種表示法 : 

(1). 單行字串 :

Python 的字串可用單引號 '' 或雙引號 "" 括起來, 如果單引號裡面內含單引號, 或雙引號裡面內含雙引號, 則裡面的引號需用倒斜線 \ 跳脫, 或者採取內單外雙/內雙外單交替的方式, 例如 :

>>> print("I'm Tony")   
I'm Tony
>>> print('I\'m Tony')  
I'm Tony

長字串可用 "+" 與 "\" 分行串接, 例如 :

>>> s="Hello " + \
...   "World"
>>> print(s)
Hello World

注意, "\" 後面必須直接跳行, 不可有空格.


(2). 多行字串 : 

Python 也直接提供多行字串語法, 連續三個單引號或多引號之間的字串為多行字串, 每一行之間會以跳行字元 '\n' 字元隔開, 例如 :

>>> s='''Tony,
... Kelly,
... Peter,
... Amy'''
>>> s
'Tony,\nKelly,\nPeter,\nAmy'
>>> print(s)
Tony,
Kelly,
Peter,
Amy

可見直接輸入變數名稱會顯示多行字串的原始內容 (包含跳行字元 \n), 但若呼叫 print() 則跳行符號會被解讀. 

也可以呼叫內建函數 str() 來建立字串, 特別是要將數值物件轉成字串物件時, 例如 :

>>> s="123"   
>>> type(s)
<class 'str'>            #字串物件 str
>>> s=str(123)
>>> type(s)
<class 'str'>            #字串物件 str

注意, 因為內建函數 str() 的存在, 故不要將字串變數命名為 str, 否則 Python 解譯器會將 str 認為是變數使得呼叫 str() 時發生 "not callable" 錯誤, 例如 :

>>> str="123"              # str 參考指向變數 str
>>> s1=str(123)           # 無法呼叫 ()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable     
>>> del str                  # 刪除會造成混淆的 str 變數
>>> s1=str(123)          # str 恢復指向內建函數 str() 而可呼叫
>>> s1
'123'

字串是不可變 (immutable) 型別, 字串變數一經賦值即不可更改, 對同一變數重複賦值並非更改其內容, 而是建立一個新字串, 該變數改成指向新字串, 這可用內建函數 id() 檢驗, 此函數會傳回物件之參考索引 (指向該字串在記憶體中的位址), 例如 :

>>> s="abc"   
>>> id(s)    
2648457405808   
>>> s="123"        
>>> id(s)     
2648460584304         # s 指向新字串物件

可見字串變數 s 的內容並非被改成 "abc", 而是指向新字串 "123". 另外, Python 沒有字元型別, 字元是以字串來表示, 例如 :

>>> c='a' 
>>> print(c)   
'a'
>>> c="A"   
>>> print(c)   
'A'


(3). 字串的長度 (字元數) :

計算字串的長度 (字元數) 可用 Python 內建函數 len(), 注意, 跳脫字元算一個字元, 不是兩個字元, 例如 :

>>> len('Hello\nWorld')
11

此例 Hello 與 World 中間有一個跳行字元 "\n", 所以加起來是 11 個字元. 中文一個字元的長度也是 1, 例如 :  

>>> len("我")   
1
>>> len("您好")    
2
>>> len("我\n愛\n你")   
5


(4). 字串的運算 : 

字串的運算包括 : 串接, 複製, 與比較. 多個字串可用 "+" 運算子串接, 例如 :

>>> 'Hello' + ' ' + 'World' 
'Hello World'
>>> 'Hello' + '\n' + 'World'     
'Hello\nWorld'
>>> print('Hello' + '\n' + 'World')     
Hello
World

一個字串可用乘法運算子 "*" 與一個正整數相乘而複製, 若乘以 0 或負整數將得到空字串 :

>>> "Hello" * 3          #乘以正整數複製
'HelloHelloHello'
>>> "Hello" * 0          #乘以 0 得空字串
''
>>> "Hello" * (-3)      #乘以負整數得空字串
''

字串可以用比較運算子依序根據 Unicode 值之大小進行比較 :

>>> "a" > "b" 
False
>>> "a" < "b" 
True
>>> "a" == "a" 
True
>>> "a" != "b" 
True
>>> "abc" > "abb"     
True


(5). 字串切片 (slice) :




(6). 字串方法 :

字串物件提供許多方法參考 :

MicroPython on ESP8266 (三) : 序列型別測試


3. 串列 (list) : 

串列是可變有序的群集 (mutable and ordered collection), 實際上是一種可被索引的動態陣列 (dynamic array) 結構, 其元素可以是任何物件, 亦即允許不同型別之異質元素 (heterogeneous), 包括串列甚至函數都可以, 且可以隨時新增或移除元素. 為了可存放異質元素, 其資料以較稀疏的形式存放, 故所佔之記憶空間也比 C 語言中的相同型別 (同質) 陣列要大.


(1). 建立串列物件 :

串列元素用中括號運算子 [] 包圍, 元素之間用逗號隔開, 串列字面值 (literal) 語法格式如下 :

list1=[e1, e2, e3, ....]

與 tuple 不同的是, 如果只有一個元素, 元素後面不需要加逗點. 查詢串列的元素個數可用內建函數 len(), 例如 :

>>> list1=[123, 12.3, True, False, 7+8j, "abc",  (1, 2, 3), ['A', 'B', 'C']]   
>>> type(list1)   
<class 'list'>
>>> list1 
[123, 12.3, True, False, (7+8j), 'abc', (1, 2, 3), ['A', 'B', 'C']]
>>> len(list1)      #查詢串列長度
8

除了使用字面值來建立串列外, 還可以呼叫內建函數 list() 來建立串列物件, 然後再呼叫串列物件的 append(e) 或 insert(i, e) 方法來添加元素, 前者會將元素 e 添加到串列尾端; 而後者則是將元素 e 插入到指定索引 i, 例如 :

>>> list1=list()                #建立空陣列
>>> type(list1) 
<class 'list'>   
>>> list1.append('a')      #添加元素至尾端
>>> list1
['a']
>>> list1.append('i')       #添加元素至尾端
>>> list1 
['a', 'i']
>>> list1.insert(1, 'u')     #插入元素於指定索引
>>> list1   
['a', 'u', 'i']


串列物件的方法如下表 :


Python : How to copy a dictionary | Shallow Copy vs Deep Copy


(1). 新增串列元素 :


append([]) : 會添加空陣列於結尾
extend([]) : 不會添加空陣列於結尾


4. 元組 (tuple) : 

元組是不可變有序的群集 (unmutable and ordered collection), 它與串列一樣都是有序的序列結構, 差別僅僅是元組的元素不可變而已 (即 tuple 建立後不能再新增元素或更改任一元素之值). 

建立 tuple 字面值的方法是用指定運算子將元素以逗號隔開指派給變數即可, 也可以用小括弧將資料括起來, 呼叫內建函數 len() 會傳回元素數目, 例如 : 

>>> a=1, 2, 3       # 外面沒有小括弧
>>> type(a)
<class 'tuple'>
>>> a
(1, 2, 3)
>>> a=(1, 2, 3)     # 外面有小括弧
>>> type(a)
<class 'tuple'>
>>> a
(1, 2, 3)
>>> len(a)      # 查詢元素數目
3

可見建立時不論有無小括號, 顯示元組內容時都會有小括號.

取得元組內元素的方法與串列一樣, 使用中括號運算子 [索引] 取得, 也可以用迴圈走訪, 因為元組是不可變資料, 更改元素之值會出現錯誤

>>> a
(1, 2, 3)
>>> print(a[0], a[1], a[2])      # 用 [索引] 取得
1 2 3
>>> for i in a:      # 用迴圈走訪元素
    print(i)
    
1
2
3
>>> a[0]=100        # 元組的內容是不可變的
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment  

元組的元素可以是異質的 (即不同資料型態), 也可以是另一個元組, 例如 :

>>> t=('debby', 28, True, (45, 26, 44))    # 具有異質元素的 tuple
>>> t
('debby', 28, True, (45, 26, 44))
>>> for i in t:
    print(i)
    
debby
28
True
(45, 26, 44)

可以用指定運算子將元組解包 (unpack) 給多個變數, 但要注意變數個數必須等於 tuple 元素個數, 否則會發生解包錯誤 : 

>>> a=(1, 2, 3) 
>>> x, y, z=a         # 用指定運算子解包 tuple 內之元素到多個變數
>>> print(x, y, z)
1 2 3
>>> x, y=a             # 解包變數數目與 tuple 元素數目不符導致錯誤
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
ValueError: too many values to unpack (expected 2)

如果要在解包時避免數目不符錯誤, 可在某變數前面加 "*" 符號, 表示接收其餘元素, 但此變數會變成 list 型態, 例如 :

>>> *x, y=a          # 將元組 a 解包給 x, y, 其中 y 接收最後元素, 其餘給 x
>>> x                    # 接收其餘元素的 x 型態為 list
[1, 2]
>>> y
3
>>> x, *y=a          # 將元組 a 解包給 x, y, 其中 x 接收第一個元素, 其餘給 y
>>> x                    
1
>>> y                    # 接收其餘元素的 y 型態為 list
[2, 3]
>>> type(y)
<class 'list'>

元組物件的方法如下表 : 


 tuple 物件方法 說明
 count(i) 傳回 tuple 元素中 i 出現之次數
 index(i) 傳回 tuple 元素中 i 之索引


例如 :

>>> b=('tony','amy','kelly','tony')
>>> b.count('tony')       # 'tony' 出現 2 次
2
>>> b.index('kelly')      # 'kelly' 的索引是 2
2


5. 集合 (set) :

集合是獨一無二 (不重複) 的物件所構成之可變無序群集 (mutable and unordered collection), 其元素必須是不可變的型別. 數學上的集合是一群元素的組合, 除了元素不能重複外, 還有聯集, 交集, 以及差集運算.


(1). 建立集合物件 : 

Python 的集合字面值 (literal) 是以大括弧運算子 {} 將元素括起來. 每個元素以逗號相隔, 語法格式如下 :

set1={e1, e2, e3, ....}

集合的元素必須是不可變的型別, 因為集合是透過計算元素獨一無二雜之湊值來定位元素, 因此只有 int, float, bool, complex, str, tuple 這六種型別的物件可作為集合之元素, 例如 :

>>> s={123, 12.3, True, False, 7+8j, "abc",  (1, 2, 3)} 
>>> print(s)
{False, True, 'abc', 12.3, (1, 2, 3), 123, (7+8j)}   

至於 list, dict, 與 set 這三種型態資料, 由於它們是可變的, 無法計算雜湊值, 因此不能作為集合的元素, 例如 :

>>> s={[1,2,3]}                 #串列不可作為集合之元素
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'   
>>> s={{'a':1,'b':2}}         #字典不可作為集合之元素
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict' 
>>> s={{1,2,3}}                  #集合不可作為集合之元素
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set' 

集合的長度 (元素個數) 可用內建函數 len() 取得, 例如 :

>>> set1={1, 2, 3, 4, 5} 
>>> len(set1) 
5

除了用大括弧運算子 {} 直接建立集合外, 也可以呼叫內建函數 set() 並傳入一個序列型別物件 (字串, 元組, 或串列) 來建立, 例如 :

>>> set1={123, 456, 'a', 123, 'b', 'a'} 
>>> print(set1) 
{456, 123, 'a', 'b'}
>>> set1=set([123, 456, 'a', 123, 'b', 'a'])   
>>> set1 
{456, 123, 'a', 'b'}

可見集合會將重複的元素刪除以保證每一個元素在集合中是獨一無二的, 如果想從其他群集 (例如元組或串列) 中移除重複的部分, 只要將他們傳給內建函數 set() 即可.

不過對於字串而言, 用 {} 與 set() 所建立的集合是不同的, set() 函數會將字串中的字元分拆開來並去除重複的字元, 而 {} 不會, 例如 : 

>>> set1={'Hello World'} 
>>> print(set1)   
{'Hello World'}
>>> set1=set('Hello World')      
>>> print(set1)    
{'e', ' ', 'H', 'l', 'd', 'r', 'W', 'o'}    #字串會被拆散成字母

集合物件的方法如下表 :


 集合物件的方法 說明
 s1.union(s2) 計算集合 s1 與 s2 之聯集, 傳回新集合
 s1.intersection(s2) 計算集合 s1 與 s2 之交集, 傳回新集合
 s1.difference(s2) 計算差集合 s1-s2, 傳回新集合 (s1-s2 與 s2-s1 不同)
 s1.issubset(s2) 檢查集合 s1 是否為集合 s2 之子集合 (傳回 True/False) 
 s1.issuperset(s2) 檢查集合 s1 是否包含集合 s2 (傳回 True/False) 
 s1.update(s2) 將集合 s2 全部元素加入集合 s1 中 (s1 會改變)
 s1.add(e) 將元素 e 新增至集合 s1 中
 s1.remove(e) 從集合 s1 中移除元素 e (若不存在出現 KeyError)
 s1.copy() 複製集合 s1 傳回一個新集合
 s1.clear() 清空 s1 集合之全部元素 (成為空集合)


注意, 除了有註明傳回值者外, 其餘方法均傳回 None.


(3). 新增集合的元素 :

呼叫 add(e) 方法可將元素 e 加入集合中, 例如 :

>>> set1={'i','a','o','u','e'} 
>>> print(set1)
{'a', 'u', 'i', 'e', 'o'}                 #順序與加入時不同

顯示集合時元素順序與建立時不同, 因為集合是無序的資料結構, 它不會維護元素加入之順序.

注意, 集合與字典都使用大括弧 {} 定義其內容, 而空的大括弧預設是定義一個空字典, 所以不能用 {} 來建立空集合後再呼叫 add() 方法加入元素, 這樣會出現 AttributeError 錯誤, 例如 :

>>> set1={}           #這是一個空字典, 不是空集合
>>> print(set1)   
{}
>>> set1.add('a') 
Traceback (most recent call last): 
  File "<pyshell#49>", line 1, in <module>
    set1.add('a')
AttributeError: 'dict' object has no attribute 'add'
>>> type(set1) 
<class 'dict'>

正確做法是呼叫內建函數 set() 來建立空集合, 例如 :

>>> set1=set()          #建立空集合
>>> type(set1) 
<class 'set'>
>>> print(set1)   
set()
>>> set1.add('a')      #新增元素
>>> set1 
{'a'}

呼叫 update(set) 則可以把另一個集合的全部元素合併到目前的集合中, 並剔除重複的元素, 例如 :

>>> set1={1, 2, 3, 6, 7, 9}   
>>> set2={2, 4, 6, 8, 9}   
>>> set1.update(set2)          #把 set2 的元素加入 set1 中
>>> print(set1)   
{1, 2, 3, 4, 6, 7, 8, 9}

可見加入新集合時會剔除重複的元素 (例如此處之 2, 6, 9).


(2). 集合的聯集運算 : 

呼叫集合物件的 union(set) 方法會傳回此集合與傳入集合之聯集, 它會將兩集合的元素全部合併, 然後剔除重複的元素, 例如 :

>>> set1={1, 2, 3, 6, 7, 9} 
>>> set2={2, 4, 6, 8, 9} 
>>> set3=set1.union(set2)   
>>> print(set3)     
{1, 2, 3, 4, 6, 7, 8, 9} 
>>> set3=set1.union(set2) 
>>> print(set3) 
{1, 2, 3, 4, 6, 7, 8, 9}

可見 union() 具有交換性, 不論哪一個集合在前結果都一樣.


(3). 集合的交集運算 :

呼叫集合物件的 intersection(set) 方法會傳回此集合與傳入集合之交集, 亦即兩集合共同元素所成的集合, 例如 :

>>> set1={1, 2, 3, 6, 7, 9} 
>>> set2={2, 4, 6, 8, 9} 
>>> set3=set1.intersection(set2) 
>>> print(set3)
{9, 2, 6}
>>> set3=set2.intersection(set1) 
>>> print(set3) 
{9, 2, 6}

可見 intersection() 也具有交換性, 不論哪一個集合在前結果都一樣.


(4). 集合的差集運算 :

呼叫集合物件的 difference(set) 方法會傳回此集合與傳入集合之差集, set1.difference(set2) 的意思是將 set1 元素剔除與 set2 交集的部分後之子集合; 而 set2.difference(set1) 則是將 set2 元素剔除與 set1 交集的部分後之子集合, 注意, difference() 沒有交換性, 例如 :

>>> set1={1, 2, 3, 6, 7, 9} 
>>> set2={2, 4, 6, 8, 9} 
>>> set3=set1.difference(set2)    #傳回 set1-set2 元素所成集合
>>> print(set3)
{1, 3, 7}
>>> set1-set2                                 #差集也可以直接用 - 運算子
{1, 3, 7}
>>> set3=set2.difference(set1)   
>>> print(set3) 
{8, 4}
>>> set2-set1                                  #差集也可以直接用 - 運算子
{8, 4}

可見 set1 去除交集 {9, 2, 6 } 後傳回 {1, 3, 7}; 而 set2 去除交集 {9, 2, 6 } 後傳回 {4, 8}, 差集運算沒有交換性, 結果可能是不一樣的.


(5). 集合元素的排序 :

集合是無序的資料結構, 其元素顯示的順序與加入之順序無關, 例如 :

>>> set1={'u','a','e','o','i'} 
>>> print(set1) 
{'a', 'u', 'i', 'e', 'o'}                 #顯示順序並非建立時之順序
>>> for e in set1: 
print(e, end=',')     

a,u,i,e,o,                               #迭代之順序與 print() 相同

如果要在顯示集合元素時進行排序, 可將集合傳給 list() 轉成串列, 再呼叫內建函數 sorted() 排序, 例如 :

>>> set1={'u','a','e','o','i'} 
>>> for e in sorted(list(set1)):   
print(e, end=',')   

a,e,i,o,u,

可見元素已經排序好了.


(6). 複製集合 :

呼叫 copy() 方法會複製集合並傳回為新集合, 例如 :

>>> set1={'u','a','e','o','i'} 
>>> set2=set1.copy() 
>>> print(set2) 
{'i', 'a', 'u', 'e', 'o'}


(7). 刪除集合元素與清空集合 :

呼叫 remove(e) 方法可刪除指定的元素, 但若元素不存在會出現 KeyError; 呼叫 clear() 則會清空全部元素成為空集合, 例如 :

>>> set1 
{'a', 'u', 'i', 'e', 'o'}
>>> set1.remove('e')      #刪除元素 'e'
>>> set1 
{'a', 'u', 'i', 'o'}
>>> set1.remove('e')      #刪除已不存在之元素 'e'
Traceback (most recent call last):
  File "<pyshell#43>", line 1, in <module>
    set1.remove('e')
KeyError: 'e'
>>> set1.clear() 
>>> set1     
set()


6. 字典 (dict) :

字典是由鍵值對 (key-value pair) 構成的可變長度無序群集 (collection), 是一個兩欄多列 (two-columned, multi-row) 的資料結構, 與 Javascript 的關聯式陣列 (associate array), Perl 與 Ruby 的雜湊表 (hash table), 或 Java 的映射 (map) 結構是一樣的, 都是一種透過唯一的鍵 (key) 來對應一個值 (value) 的查找表 (look-up table) 結構.


(1). 建立字典物件 :

字典使用大括弧運算子 {} 來列舉項目 (item), 項目由鍵值對組成, 每一個項目間用逗號隔開, 語法格式如下 :

dict1={key1:value1, key2:value2, key3:value3, ..... }

與集合的元素值不可重複一樣, 字典每一個項目 (item) 的鍵必須是不可變型別且獨一無二不可重複 (unique), 例如 int, float, bool, complex, str, tuple 這六種型別均可作為字典的鍵, 因為這樣才可計算鍵的雜湊值以便關聯其所對應之值, 而值則可以是任何型別的物件 (包括字典), 例如 :

>>> test={0:'zero', 3.14159:'pi', True:1, False:0, 1+1j:'complex 1+1j', (1,1):'tuple (1,1)'} 
>>> print(test)      
{0: 0, 3.14159: 'pi', True: 1, (1+1j): 'complex 1+1j', (1, 1): 'tuple (1,1)'}

通常是用字串做鍵, 例如 :

user1={'account' : 'tony', 'password' : 'blablabla', 'category' : 'admin'} 

為了提高程式可讀性, 字典的項目最好一個項目一列輸入, 由於有大括弧做界線, 所以每一列結尾不需要用倒斜線 \ (有也可以) :

user1={'account' : 'tony',
             'password' : 'blablabla', 
             'category' : 'admin'}

與串列或元組一樣, 存取字典的項目也是是用中括弧運算子 [], 但裡面是使用項目的鍵來取得關聯值, 而不是像串列那樣用數字索引, 例如 :

>>> user1['account'] 
'tony'
>>> user1['password'] 
'blablabla'
>>> user1['category'] 
'admin'

可以先建立一個空字典, 再用中括弧運算子 [] 來初始化鍵 (賦值), 例如 :

>>> user1={}          #建立空陣列 (不是空集合)
>>> user1['account']='tony'   
>>> user1['password']='blablabla'  
>>> user1['category']='admin'       
>>> print(user1)      
{'account': 'tony', 'password': 'blablabla', 'category': 'admin'}

除了用空的大括弧 {} 外, 也可以呼叫內建函數 dict() 來建立空字典 :

>>> user1=dict()  #建立空陣列
>>> print(user1)
{}

此外, 字典還提供了 setdefault(key, value) 方法來初始化字典的鍵, 它會傳回項目之值 (value) :

>>> user1={}          #建立空陣列
>>> user1.setdefault('name', 'tony')   
'tony'
>>> user1.setdefault('password', 'blablabla')  
'blablabla'
>>> user1.setdefault('category', 'admin')   
'admin'
>>> print(user1)  
{'name': 'tony', 'password': 'blablabla', 'category': 'admin'}

因為字典是透過計算鍵的雜湊值 (hash) 來定位其所關聯的值而非索引, 所以顯示字典內容時不一定會依照加入的順序來排序. 字典是無序的 (unordered) 資料結構, 它不會維護項目之間的排列順序.

字典物件的方法如下表 :





(2). 使用 get() 方法取值 :

字典的鍵必須先初始化 (亦即要先對鍵賦值使其有內容) 才能讀取, 讀取未初始化的鍵會產生 KeyError 錯誤, 例如上面的 user1 並沒有 email 這個鍵, 直接取值會報錯 :

>>> user1['email']    
Traceback (most recent call last): 
  File "<pyshell#51>", line 1, in <module>
    user1['email']
KeyError: 'email'

這問題可以在讀取前先用 in 與 not in 先檢查鍵是否存在來避免 :

>>> if 'email' in user1:   
  print(user1['email'])
else: 
  print('key not found')   

key not found

不過更好的解決辦法是利用字典的 get() 方法傳入鍵來取值, 如果鍵不存在會傳回 None, 不會報錯 :

>>> user1.get('email') 
>>> type(user1.get('email'))
<class 'NoneType'> 


(3). 新增字典的項目 : 

新增字典項目有兩個方法, 一是直接用中括號運算子 [] 給新鍵賦值, 例如 :

>>> user1['email']='tony@bla.com'
>>> print(user1)   
{'account': 'tony', 'password': 'blablabla', 'category': 'admin', 'email': 'tony@bla.com'} 

第二個方式是呼叫字典物件的 update() 方法, 並傳入新項目鍵值對所組成的字典 (即新增一個字典進去) :

>>> user1.update({'email':'tony@bla.com'})
>>> print(user1)      
{'name': 'tony', 'password': 'blablabla', 'category': 'admin', 'email': 'tony@bla.com'}


(4). 迭代字典的項目 :

迭代 (iteration) 字典項目要用 for in 敘述來拜訪字典中的每一個項目, 但迭代的變數是每個項目的鍵而不是項目本身或值, 例如 :

>>> for k in user1:   
                     print(k) 

account
password
category
email

可見所取得的迭代變數 k 是項目的鍵而非值. 如果迭代變數是要取得項目的值則須呼叫 values() 方法, 它會傳回一個由值串列組成的 dict_values 物件, 例如 :

>>> user1.values()   
dict_values(['tony', 'blablabla', 'admin', 'tony@bla.com']) 
>>> for v in user1.values(): 
                     print(v)   

tony
blablabla
admin
tony@bla.com

如果要存取鍵所對應之值, 則必須用中括號運算子 [k] 或呼叫 get(k) 方法, 例如 :

>>> for k in user1: 
                     print(k + ":" + user1[k])      #或 user1.get(k)

account:tony
password:blablabla
category:admin
email:tony@bla.com

如果要讓迭代的結果排序, 可將字典傳入內建函數 sorted(), 注意, sorted() 是對鍵排序而非對值排序. 例如 :

>>> for k in sorted(user1): 
                     print(k + ":" + user1[k]) 

account:tony
category:admin
email:tony@bla.com
password:blablabla

注意, sorted() 不會改變原始資料 (即傳入之字典) 的順序.

如果要在迭代時同時取得鍵與值, 則可呼叫字典物件的 items() 方法, 它會傳回鍵值對元組組成的 dict_items 物件, 這樣迭代時便能用兩個迭代變數同時取得鍵與值, 這樣就不需要用中括號運算子取得值了, 例如 :

>>> for k,v in user1.items(): 
                     print(k + ":" + v) 

account:tony
password:blablabla
category:admin

如果鍵值對要排序, 同樣可將 items() 的傳回值傳入 sorted() 函數, 例如 :

>>> for k,v in sorted(user1.items()): 
                     print(k + ":" + v) 

account:tony
category:admin
password:blablabla


(5). 刪除字典的項目 : 

欲刪除字典物件中的某個項目可 pop(key) 方法並傳入鍵, 它會傳回該項目之值, 例如 :

>>> print(user1) 
{'account': 'tony', 'password': 'blablabla', 'category': 'admin', 'email': 'tony@bla.com'}
>>> deleted=user1.pop('email')       #刪除鍵=email 的項目
>>> print(user1)   
{'account': 'tony', 'password': 'blablabla', 'category': 'admin'}
>>> print(deleted)                             #傳回被刪除項目之值
tony@bla.com

注意, 刪除不存在的項目 (傳入不存在的鍵) 會產生 KeyError 錯誤 :

>>> user1.pop('email') 
Traceback (most recent call last):
  File "<pyshell#29>", line 1, in <module>
    user1.pop('email')
KeyError: 'email' 


(7). 字典的應用 :

字典這種資料結構的用途之一是可以很方便進行頻率計數統計, 例如下面用字典來統計字串中母音字母 (a, i, u, e, o) 出現次數的範例 :

vowels=['a','i','u','e','o']
word='a silver bullet'
print(word)
found={}
for letter in word:
    if letter in vowels:
        found.setdefault(letter, 0)   #初始化項目值為 0
        found[letter] += 1               #值增量 1
for k,v in sorted(found.items()):
    print(k, 'was found ', v, ' time(s)')

執行結果如下 :

a silver bullet
a was found  1  time(s)
e was found  2  time(s)
i was found  1  time(s)
u was found  1  time(s)


七. 運算子 :

電腦進行運算需有運算元 (operand) 與運算子 (operator). Python 的運算元有各種資料型態如上述, 運算子則有七類 :
  1. 算術運算子 (arithmetic operator) 
  2. 指定運算子 (assignment operator) 
  3. 比較運算子 (comparison operator) 
  4. 邏輯運算子 (logical operator) 
  5. 位元運算子 (bitwise operator) 
  6. 移位運算子 (shifting operator) 
  7. 符號運算子 (symbolic operator) 
以作用的運算元數目區分, 又可分為單元運算子 (unary, 例如正負號) 與二元運算子 (binary).  


1. 算術運算子 (arithmetic operator) : 

算術運算子有七個如下表 :


 算術運算子 說明
 + 加法運算, 例如 a + b
 - 減法運算, 例如 a - b
 * 乘法運算, 例如 a * b
 / 浮點數除法運算, 例如 a / b (傳回 float 型態之浮點數)
 // 整數除法運算, 例如 a // b (傳回商, 為 int 型態之整數)
 % 餘數運算, 例如 a % b
 ** 指數運算, 例如 a ** b (即 a 的 b 次方)


注意 :
  1. '+' 為多用途運算子, 運算元均為數值時為加法運算子; 運算元均為字串時為串接運算子; 做為單元運算子時表示正數, 雖可在正數前面冠 '+' 但不需要,  +123 等同於 123. 但數值與字串不能進行 '+' 運算, 因為 Python 是強型別語言, 不允許隱性 (自動) 型別轉換. 但字串可與數值做 * 運算, 表示將字串重複指定之次數. 
  2. '-' 可做加法運算子, 亦可做單元運算子用來表示負數, 例如 -123. 
  3. 整數除法只傳回相除之商, 小數部分無條件捨去, 不是四捨五入. 
  4. Python 沒有 Java 的 ++ 與 -- 運算子, 如果要遞增與遞減請用 +=1 與 -=1 代替. 
例如 :

>>> -(-100)          #負負得正
100
>>> 10 / 4            #浮點數除法
2.5
>>> 10 // 4           #整數除法傳回商 (略去小數)
2
>>> type(10/4)     #浮點數除法傳回 float 型態
<class 'float'> 
>>> type(10//4)    #整數除法傳回 int 型態
<class 'int'>
>>> 10 % 3           #求餘數
1
>>> 10 ** 3           #冪次 (次方)
1000
>>> 'Hello' + 'World'     #字串串接運算
'HelloWorld'
>>> 123 + 'abc'              #字串與數值不可做 + 運算 (無自動轉型)  
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str' 
>>> 'Hello' * 3               #字串重複 3 次
'HelloHelloHello'
>>> 'Hello\n' * 3            #字串重複 3 次 (含跳行字元)
'Hello\nHello\nHello\n'
>>> print('Hello\n' * 3)  #要用 print() 才會有跳行效果
Hello
Hello
Hello


2. 指定運算子 (assignment operator) :

單純指定運算子 = 用來將右邊的運算結果指派給一個變數參考, 例如 :

count=0
msg="Hello World"


(1). 同步指定 : 

Python 支持同時指派多個值到多個對應的變數 (同步指定, simultaneous assignment), 例如 :

a, b, c=1, 2, 3

這功能對於資料交換非常方便, 例如要交換 a, b 兩變數之值可用一個敘述即完成 :

a, b=b, a

這功能在 Javascript, Java 或 C 等語言必須用中間變數交換, 例如 :

var a=1; b=2; 
var tmp=a;  //將 a 暫存在 tmp
a=b;            //a 換成 b 之值
b=tmp;       //b 換成原來的 a 之值


(2). 多重指定 : 

Python 支持將一個值一次指派給多個變數, 例如 : 

a=b=c=d=e=100

此運算式會從右到左 (唯一的例外順序) 將 100 指派給 e. d, c, b, a 五個變數. 

指定運算子還可與算術, 移位, 以及位元運算子結合為複合指定運算子 :


 指定運算子 說明
 = 將右邊的字面值 (literal) 指定給左邊變數, 例如 a=2 
 += 相加指定, 左右相加後再指定給左邊變數, a += b 即 a=a+b
 -= 相減指定, 左右相減後再指定給左邊變數, a -= b 即 a=a-b
 *= 相乘指定, 左右相乘後再指定給左邊變數, a *= b 即 a=a*b
 /= 相除指定, 左右相除後再指定給左邊變數, a /= b 即 a=a/b
 //= 整除指定, 例如 a //= b 即 a=a//b
 %= 餘除指定, 例如 a %= b 即 a=a%b
 **= 指數指定, 例如 a **= b 即 a=a**b
 <<= 左移後指定, a <<= b 即 a=a << b
 >>= 左移後指定, a >>= b 即 a=a >> b
 &= 位元 AND 後指定, a &= b 即 a=a & b
 |= 位元 OR 後指定, a |= b 即 a=a | b
 ^= 位元 XOR 後指定, a ^= b 即 a=a ^ b


注意 : Python 沒有 ++ 與 -- 運算子, 要做遞增與遞減運算需使用相加指定 +=1 與相減指定 -=1 代替.

例如 :

>>> a, b, c=1, 2, 3     #一次指定多個值給對應之多個變數
>>> a
1
>>> b
2
>>> c
3
>>> a += b
>>> a
3


3. 比較運算子 (comparison operator) :

比較運算子又稱關係運算子 (relational operator), 用來比較左右兩個運算元之值的大小關係, 內建資料型別雖均可作為運算元, 但主要用在數值與字串型別, 且兩個運算元必須為同型別, 其運算結果是一個布林值 (True/False), 常用在選擇敘述 if else 與迴圈敘述 while 中控制執行方向或判斷迴圈是否要繼續.


 比較運算子 說明
 == 兩邊值相等時傳回 True, 否則 False
 != 兩邊值不相等時傳回 True, 否則 False
 <> 兩邊值不相等時傳回 True, 否則 False
 > 左邊的值大於右邊的值時傳回 True, 否則 False
 < 左邊的值小於右邊的值時傳回 True, 否則 False
 >= 左邊的值大於或等於右邊的值時傳回 True, 否則 False
 <= 左邊的值小於或等於右邊的值時傳回 True, 否則 False


注意, Python 的不等於可用 != 或 <> 兩種運算子. 其次,  >= 與 <= 運算子的等號都在右邊, =< 與 => 是錯誤的寫法. 

運算元若為字串, 則依據其 Unicode 編碼值由左向右一一比對對應之字元, 直到比出大小或其中一個字串結束為止, 比較長的較大, 呼叫內建函數 ord() 可查詢字元的 Unicode 編碼值. 

例如 :

>>> 1 == 1.0                  #整數與浮點數值相等
True
>>> 1 > 1.0           
False
>>> 1 == 1+0j                 #複數虛部為 0 等於整數
True
>>> True == 1                 #布林值 True 其實就是 1
True
>>> False == 0                #布林值 False 其實就是 0
True
>>> 'hello' == 'hello'        #相同字串
True
>>> 'hello' < 'Hello'     #大寫字母 ASCII 編碼較小
False
>>> 'hello' > 'Hello'     #大寫字母 ASCII 編碼較小
True
>>> 'a' < 'b'      #英文字母 ASCII 碼 'a' 比 'b' 小
True
>>> ord('a')
97
>>> ord('b')
98
>>> 'a' < 'ab'    #前面字元相同, 長度較長者較大
True
>>> 'a' < '文'    #英文的 Unicode 一定小於非英文字
True
>>> '文' < '文學'    #前面字元相同, 長度較長者較大
True

兩個數值關係運算式若形成範圍可以寫成範圍關係運算式, 例如體溫介於 36 與 37.5 為正常 :

if temp >=36 and temp < 37.5:           # 以邏輯 and 運算子串聯兩個關係式
    print("體溫正常")
else: 
    print("體溫異常")

可以改寫為如下之範圍關係運算式 :

if 36 <= temp <37.5:        # 範圍關係運算式
    print("體溫正常")
else: 
    print("體溫異常")


4. 邏輯運算子 :   

邏輯運算子的運算元均為布林值, 用來執行運算元的 and, or, 與 not 三種邏輯運算, 其中 not 為單元運算子, 只有一個運算元 :


 邏輯運算子 說明
 and 兩個運算元均為 True 時才傳回 True, 否則 False
 or 兩個運算元均為 False 時才傳回 False, 否則 True
 not 運算元值為 True 傳回 False, 否則 True (反相)


例如 :

>>> a=True
>>> b=True
>>> a and b     #兩運算元均為 True 則為 True
True
>>> a or b
True
>>> not a        #真變假
False
>>> not b
False


5. 位元運算子 (bitwise operator) :

位元運算子是將運算元以二進位形式展開後逐位元進行 0 與 1 的邏輯運算, Python 有四個位元運算子 :


 位元運算子 說明
 ~ 位元否定 (not) 運算 (即 1 的補數), ~1 為 0, 而 ~0 為 1
 & 位元且 (and) 運算, 只有 1&1 為 1, 其餘為 0
 |  位元或 (or) 運算, 只要有一個運算元為 1 即得 1
 ^ 位元互斥或 (xor) 運算, 只要 1^0 與 0^1 得 1, 其餘得 0


例如 :

>>> ~7
-8
>>> bin(7)      #轉成二進位
'0b111'
>>> bin(~7)    #取 1 的補數再轉成二進位
'-0b1000'
>>> 3 & 8       #0011 & 1000=0000 (0)
0
>>> 9 & 8       #1001 & 1000=1000 (8)
8
>>> 5 & 12     #0101 & 1100=0100 (4)
4
>>> 5 | 12       #0101 | 1100=1101 (13)
13
>>> 5 ^ 12      #0101 ^ 1100=1001 (9)
9


6. 移位運算子 (shifting operator) :

移位運算子是對運算元的二進位形式進行向左或向右移動一個位元的動作 : 


 移位運算子 說明
 >> 右移一個位元, 左方補 0, 相當於除以 2
 << 左移一個位元, 右方補 0, 相當於乘以 2


例如 :

>>> a=3
>>> bin(a)        #傳回二進位形式
'0b11'
>>> b=a << 1
>>> b
6
>>> bin(b)
'0b110'
>>> b >> 1
3



7. 符號運算子 (symbolic operator) :

Python 使用如下符號表示資料結構, 也是一種運算子 :


 符號 說明
 () 小括號 定義 tuple (元組/序對), 函數參數, 或優先處理之運算式
 [] 中括號 定義 list (串列), 或索引
 {} 大括號 定義 dict (字典) 或 set (集合) 
 ,   逗號 用來分隔變數, 運算式, 參數, 或容器型別的元素
 :   冒號  用來分隔字典之鍵值對, 分支與迴圈指令與其區塊
 .   小數點 存取物件之屬性或方法
 ;   分號 分隔多個敘述


注意逗號在元組中的特殊作用, 元組如果只有一個元素時必須在後面添加一個逗號, 否則不會是一個 tuple, 例如 :

>>> i=(5)
>>> type(i)
<class 'int'> 
>>> i=(5,
>>> type(i) 
<class 'tuple'> 

以上的運算子是有優先順序的, 如下表所示 :


 運算子優先順序 說明
 1  () 巢狀多層時內層優先 (由內而外)
 2  ** 冪 (次方)
 3  ~ 位元運算子 (NOT, 否定)
 4  +,  - 正負號
 5  *,  /,  //,  % 乘 *, 除 /, 整數除法 //, 求餘數 %
 6  +,  - 加減運算
 7  <<, >> 位元運算子 : 左移 <<, 右移 >>
 8  & 位元運算子 AND
 9  ^ 位元運算子 XOR
 10  |  位元運算子 OR
 11  in, not in, is, is not, <,  <=, >,  >=,  !=, == 成員 (in, not in), 識別 (is. is not), 與關係運算子
 12  not 邏輯運算 (否定)
 13  and  邏輯運算 (且)
 14  or 邏輯運算 (或)


Python 運算式中含有多個運算子時, 基本上都是由左向右依照上面的優先順序運算 (可用小括號改變先後順序), 唯一的例外是多重指定運算式, 它是由右到左運算, 例如 x=y=z=0 會先執行 z=0, 然後 y=0, 最後 x=0. 

四則運算遵循普通數學裡的先乘除後加減原則, 例如 :

>>> 1+2*3/4      #先算 2*3/4 得 1.5 再與 1 相加得 2.5
2.5
>>> 1*2+3/4      #先算 1*2 得 2 與 3/4 得 0.75, 再相加得 2.75
2.75

注意, 排序 4 的乘除求餘數 (* / // %), 排序 5 的加減, 以及排序 6 的關係運算中的運算子優先順序一樣, 同時出現時運算式會依先來後到原則由左向右運算, 例如 :

>>> 100//5*3%7    #100 先整除 5 得 20 再乘 3 得 60 再除 7 取餘數得 4
4
>>> 40%6*5/4       #40 除 6 取餘數得 4 再乘 5 得 20 再除以 4 得 5
5.0

為了避免邏輯錯誤, 運算式應該用第一優先的小括弧明確訂出優先順序.

算術運算式是由左向右依據運算子優先順序 (參考下面的順序表) 依序計算, 但可用

除了上面的運算子外, 還有如下表七組特殊符號 :


 符號 說明
 () 小括號 定義 tuple (元組/序對), 函數參數, 或優先處理之運算式
 [] 中括號 定義 list (串列), 或索引
 {} 大括號 定義 dict (字典) 或 set (集合) 
 ,   逗號 用來分隔變數, 運算式, 參數, 或容器型別的元素
 :   冒號  用來分隔字典之鍵值對, 分支與迴圈指令與其區塊
 .   小數點 存取物件之屬性或方法
 ;   分號 分隔多個敘述


這些運算子用法已在上面資料型態中描述.