2021年12月31日 星期五

Good Bye 2021, Hello 2022

再過三個多小時就要告別 2021, 我如往常從不時興去參加跨年活動 (每年跨年似乎是萬人為我慶生, 我是元旦寶寶, 哈哈), 而是在年尾的冬夜檢視回顧過去的 365 天都在忙甚麼? 完成了那些計畫與夢想? 今年年初我訂了一個 2021 學習地圖, 決心先擱置 R 語言, 專心學習 Python/MicroPython, 確實照計畫走, 雖然進度不如預期, 但也達到了七八成, 並非一事無成. 展望 2022 我還是要專注在 Python 應用, 重點放在下面三項 (依序) :
  1. 用 Python 重建金融資訊系統
  2. 執行物聯網專案計畫
  3. 資料科學與機器學習
明年開始陸續有老同事退休, 遇缺不補將使工作整併加重, 我打算按進度逐步撰寫技術手冊以應付未來的工作要求, 畢竟還有近十年才能屆退, 記憶力又隨年齡衰退, 不記下來不行, 過一個星期就逐漸淡忘了. 每天都在忙, 不知不覺已來到大叔的末段班, 人生彷彿在一眨眼間就過了一大半, Time is short! 

2021年12月30日 星期四

好站 : 糊裡糊塗Python就上手系列

晚上在整理 Chrome 書籤時找到以前存下來的 Python 教學網站 : 


此系列 30 篇文章大致把 Python 基本用法與常見應用 (爬蟲, 資料庫, Pandas, Numpy, ... 等) 都有詳細介紹, 雖然限於篇幅無法鉅細靡遺, 但值得一看. 

好站 : SX127x (LoRa transceiver) driver for (Micro)Python

今天搜尋時在 Wei 部落格找到一個 LoRa 的 MicroPython 驅動程式, 作者應該是 C/Python 很強, 他把 Arduino 的 LoRa 程式改寫成 MicroPython 版以便能夠在 ESP8266/ESP32 上面跑 : 

 
相關程式碼放在 GitHub :


希望明年有時間回來玩 LoRa 與物聯網, 先記下來. 

2021年12月29日 星期三

Python 學習筆記 : 串列元素的排序

排序是演算法課程的 ABC, 在 Python 的容器物件中, 不可變的字串與元組 (tuple) 內容無法排序 (因為排序會改變元素的順序); 無序的字典 (dict) 與集合 (set) 當然也無法排序, 只有串列 (list) 可以排序. 本篇是最近複習串列排序時的測試紀錄, 參考書籍 : 


要對串列物件之內容排序有如下兩種方式 : 
  • 使用串列的 sort() 與 reverse() 方法 : 會直接改變原串列內元素的排序
  • 使用內建函式 sorted() : 傳回排序後的新串列 (不影響原串列)

1. 使用串列的 sort() 與 reverse() 方法排序與倒序 : 

呼叫 sort() 方法預設會將串列的元素值由小到大排列 (升冪), 如果是字串元素則依據其 Unicode 編碼排序, 如果要將元素值由大到小排列 (降冪), 則可傳入參數 reverse=True, 語法如下 : 

list_obj.sort([key=None, reverse=False])     

另外, 與串列元素順序有關的還有 reverse() 方法, 但它並不是將元素值由大到小降冪排序, 而是前軍做後軍, 後軍做前軍, 前後順序顛倒而已 (倒序), 嚴格來說不是排序, 語法如下 : 

list_obj.reverse()     

注意, reverse() 沒有任何參數. 順帶一提, reverse() 的倒序操作也可以用切片 [::-1] 來達成, 但[::-1] 與呼叫 reverse() 不同的是它不會改變原串列, 而是傳回倒序後的新串列, 例如 :

>>> lot=[2, 34, 16, 7, 18, 27]    
>>> new_lot=lot[::-1]    
>>> new_lot      
[27, 18, 7, 16, 34, 2]   
>>> lot      
[2, 34, 16, 7, 18, 27]    
>>> lot.reverse()       
>>> lot   
[27, 18, 7, 16, 34, 2]

sort() 方法有兩個備選參數, 其中 key 是在排序時要對每個元素呼叫的關鍵函式, 而 reverse 則是用來設定是要升冪或降冪排序 (預設是升冪), 例如 : 

>>> lot=[2, 34, 16, 7, 18, 27]    
>>> lot.sort()                                 # 預設升冪排序
>>> lot 
[2, 7, 16, 18, 27, 34]
>>> lot=[2, 34, 16, 7, 18, 27]   
>>> lot.sort(reverse=True)          # 指定降冪排序 
>>> lot   
[34, 27, 18, 16, 7, 2]   
>>> lot=[2, 34, 16, 7, 18, 27]  
>>> lot.reverse()                            # 倒序排列
>>> lot   
[27, 18, 7, 16, 34, 2]

元素若是字串則按照每一個字元的 Unicode 編碼值大小逐一比對排序, 可用內建函式 ord() 查詢字元的 Unicode 編碼值, 例如 :

>>> string=['cC', 'aA', 'bB', 'Aa', 'Cc', 'Bb']    
>>> string.sort()      
>>> string     
['Aa', 'Bb', 'Cc', 'aA', 'bB', 'cC']
>>> ord('A')      
65
>>> ord('a')   
97
>>> ord('B')   
66
>>> ord('b')    
98

可見 sort() 會依序從第一個字元開始一一比對 Unicode 編碼, 由於大寫字母的 Unicode 編碼比小寫的要小, 因此會排在前面. 任何語言的字串也是依據其 Unicode 編碼排序, 例如 : 

>>> list_obj=['a', '我', '我們', '愛', 'abc', '你']   
>>> list_obj.sort()     
>>> list_obj    
['a', 'abc', '你', '愛', '我', '我們']   
>>> ord('我')      
25105
>>> ord('愛')        
24859
>>> ord('你')   
20320

因為 '你' 的 Unicode 比 '愛' 的 Unicode 小, 所以 你' 排在 '愛' 的前面. 

布林值串列也可以排序, 它是按照 Ture 與 False 相對應的整數值 1 與 0 去排序, 因此 False 會排在最前面, 例如 :

>>> list_obj=[True, True, False, True, False]    
>>> list_obj.sort()      
>>> list_obj       
[False, False, True, True, True]        # False 的值為 0, True 為 1, 故 False 排在前面

注意, 串列元素必須都是同類型資料才能呼叫 sort(), 否則會出現 TypeError 錯誤, 具體而言就是元素中有數值與字串混合情況的串列無法排序, 但布林值可以跟數值一起排序, 因為布林值其實就是 0 與 1 兩個整數. 而 reverse() 只是倒序操作而已, 並不涉及元素排序, 因此混合型態的串列呼叫 reverse() 是可以的, 例如 : 

>> list_obj=['abc', 123]     
>>> list_obj.sort()                              # 數值與字串混合的串列不可呼叫 sort()
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: '<' not supported between instances of 'int' and 'str'  
>>> list_obj.reverse()                        # 混合型態串列可以呼叫 reverse()
>>> list_obj    
[123, 'abc']
>>> list_obj=['abc', True]                 # 字串與布林值為混合型態, 不可排序
>>> list_obj.sort()     
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: '<' not supported between instances of 'bool' and 'str'
>>> list_obj.reverse()                        # 混合型態串列可以呼叫 reverse()
>>> list_obj    
[True, 'abc']
>>> list_obj=[3.14159, 123, True]    # 布林值本質是整數, 與數值並非混合型態        
>>> list_obj.sort()                              
>>> list_obj    
[True, 3.14159, 123]

除了混合資料型態的串列無法呼叫 sort() 進行排序外, 複數串列也不行, 例如 : 

>>> list_obj=[1+2j, 1+1j, 1-1j]    
>>> list_obj.sort()    
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: '<' not supported between instances of 'complex' and 'complex'    


2. 使用內建函式 sorted() 排序 : 

內建函式 sorted() 會將傳入串列預設以升冪排序後傳會心串列 (傳入 reverse=True 則可降冪排序), 不會改變原串列, 語法如下 : 

sorted(list_obj [, key=None, reverse=False])     

備選參數的用法與 sort() 方法的一樣, 例如 : 

>>> lot=[2, 34, 16, 7, 18, 27]    
>>> sorted(lot)                               # 傳回升冪排序後的新串列
[2, 7, 16, 18, 27, 34]
>>> sorted(lot, reverse=True)      #  傳回降冪排序後的新串列
[34, 27, 18, 16, 7, 2]
>>> lot                                            # 原串列不變
[2, 34, 16, 7, 18, 27]

字串串列同樣是以 Unicode 編碼排序, 例如 :

>>> string=['cC', 'aA', 'bB', 'Aa', 'Cc', 'Bb']    
>>> sorted(string)                                                # 傳回升冪排序後的新串列
['Aa', 'Bb', 'Cc', 'aA', 'bB', 'cC']
>>> sorted(string, reverse=True)                       #  傳回降冪排序後的新串列
['cC', 'bB', 'aA', 'Cc', 'Bb', 'Aa']
>>> string                                                             # 原串列不變
['cC', 'aA', 'bB', 'Aa', 'Cc', 'Bb']  

與 sort() 方法一樣, 數值與字串混合的串列, 以及複數串列都無法用 sorted() 排序, 例如 :

>>> list_obj=['abc', 123]                # 數值與字串混合 : 無法排序
>>> sorted(list_obj)   
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: '<' not supported between instances of 'int' and 'str'
>>> list_obj=['abc', True] 
>>> sorted(list_obj)
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: '<' not supported between instances of 'bool' and 'str'
>>> list_obj=[1+2j, 1+1j, 1-1j]      # 複數串列無法排序
>>> sorted(list_obj)   
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: '<' not supported between instances of 'complex' and 'complex'

參考 :



2021年12月28日 星期二

Python 學習筆記 : 在串列中搜尋資料

本篇主要是閱讀借自母校的幾本 Python 基礎書籍後所整理的搜尋測試紀錄, 參考書目 : 


資料搜尋是序列型態常見的操作, 以下是 Python 中常用的搜尋方式 : 


1. 使用 index() 方法搜尋 : 

Python 的串列 (list) 與元組 (tuple) 物件都內建了 index() 方法, 傳入欲搜尋的元素會傳回該元素之索引, 但若該元素不存在則會出現 ValueError 錯誤, 例如 :

>>> lot=[2, 34, 16, 7, 18, 27]      
>>> lot.index(34)                    # 元素存在傳回索引
1
>>> lot.index(27)                    # 元素存在傳回索引
5
>>> lot.index(6)                      # 元素不存在會出現錯誤
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
ValueError: 6 is not in list

故使用 index() 搜尋資料必須做例外處理, 例如 : 

>>> lot=[2, 34, 16, 7, 18, 27]   
>>> try:   
    print(f'index={lot.index(5)}') 
except Exception:                           # 或 ValueError
    print(f'not found!')    
not found!  
>>> try:   
    print(f'index={lot.index(27)}')     
except Exception:                           # 或 ValueError
    print(f'not found!')  
index=5

可以將此搜尋功能寫成一個 search() 函式, 傳入序列物件與搜尋標的後會傳回索引 (有找到) 或 None (沒找到), 例如 : 

>>> def search(series, target):     
    try:  
        index=series.index(target)    
        return index     
    except ValueError:    
        return None    
    
>>> lot=[2, 34, 16, 7, 18, 27] 
>>> search(lot, 27)                   # 有找到 : 傳回索引
5
>>> search(lot, 2)                     # 有找到 : 傳回索引
0
>>> if not search(lot, 21):        # 沒找到 : 傳回 None
    print('not found')    
    
not found


2. 使用迴圈循序搜尋 : 

此方法以迴圈從序列物件的開頭依序搜尋標的, 此法缺點是效率較差, 若標的是在序列的最尾端, 則花費的搜尋時間最多. 可將此程序寫成函式, 找到標的時傳回索引, 否則傳回 None, 例如 :

>>> def search(series, target):    
    index=None                                    # 傳回索引初始值
    for i in range(len(series)):             # 以迴圈走訪序列中的元素
        if series[i]==target:                    # 比對是否為找尋之標的
            index=i                                    # 找到就將傳回值設為目前索引
            break                                       # 中止搜尋
    return index                                   # 傳回索引或 None

>>> search(lot, 2)                               # 有找到 : 傳回索引
0   
>>> search(lot, 27)                             # 有找到 : 傳回索引
5   
>>> print(search(lot, 21))                  # 沒找到 : 傳回 None
None

可見功能與上面用 index() 方法實作的一樣. 


3. 使用二分搜尋法 : 

二元搜尋法的對象必須是已排序 (從小至大) 的序列物件 (list 或 tuple), 它的搜尋作法是先將這由小到大排序的序列中間切開分成兩半, 左半部是較小的部分, 右半部是較大的部分. 然後將正中央的元素與搜尋標的比較, 如果相同就是找到了標的, 可結束搜尋; 否則就要看標的比正中央元素大還是小, 若是比正中央元素大, 那就到右半部繼續搜尋, 反之就到左半部繼續搜尋.

串列由小到大排序可用內建函式 sort(), 此函式會改變原本的串列內容, 例如 :

>>> lot=[2, 34, 16, 7, 18, 27]    
>>> lot.sort()      
>>> lot     
[2, 7, 16, 18, 27, 34]    

如果要自行實作排序, 可以使用最簡單的氣泡排序, 參考 :


以下是寫成函式的氣泡排序 :

>>> def bubble_sort(arr):   
    for i in range(len(arr)-1, -1, -1):     
        for j in range(i):   
            if arr[j] > arr[j+1]:    
                arr[j], arr[j+1]=arr[j+1], arr[j]   

>>> lot=[2, 34, 16, 7, 18, 27]   
>>> bubble_sort(lot)   
>>> lot     
[2, 7, 16, 18, 27, 34]   

排序好後就可以開始實作二元搜尋法, 寫成函式如下 :

>>> def binary_search(series, target):    
    index=None    
    min=0   
    max=len(series) - 1       
    cnt=0   
    while min <= max:   
        mid=int((min + max )/2)   
        cnt += 1   
        if series[mid]==target:      
            index=mid     
            break      
        elif series[mid]>target:      
            max=mid - 1   
        else:   
            min=mid + 1  
    return index   

>>> lot=[2, 34, 16, 7, 18, 27]   
>>> lot.sort()   
>>> lot   
[2, 7, 16, 18, 27, 34]
>>> binary_search(lot, 27)        
4
>>> binary_search(lot, 7)   
1
>>> binary_search(lot, 34)   
5
>>> print(binary_search(lot, 21))   
None

從程式碼長度來看, 似乎是用 index() 加上 try except 例外處理比較簡單. 

2021年12月27日 星期一

Python 學習筆記 : 用 print() 函式輸出格式化字串

Python 的內建函式 print() 是最常用來輸出變數值的工具, 除了在開發過程中 debug 時用來檢視變數之值外, 也可以用在輸出報表時控制文字的輸出格式, 本篇對 Python 演化的過程中陸續發展出 % 運算子, format() 方法, 以及 f 字串這三種格式化字串輸出方式做了摘要整理與測試.    

參考文章 :   


參考書籍 : 

# 增壓的 Python (碁峰, 2020)
# Python 神乎其技 (全新超譯版, 旗標, 2020)
# Python 也可以這樣學 (博碩, 董付國, 2018)


Python 內建函式 print() 的語法如下 : 

print(value1, value2, .... [, sep=' ', end='\n'])

其中 value1, value2, ... 等參數為要輸出的變數或字面值 (literal), 亦即 print() 可以一次輸出多個值, 各個值以逗號隔開. 備選的關鍵字參數 sep 是用來隔開這些輸出資料的字串, 預設是一個空白字元; 而參數 end 是全部輸出結束時放在結尾的字串, 預設是換行字元 '\n', 故每次呼叫 print() 預設都會換行輸出, 若不要換行則需用 end 設定為其它字串, 例如 end 設為空字元會讓下一次 print() 的輸出緊接在此次 print() 輸出的後面. 

除了單純輸出資料外, print() 還可以控制輸出的格式, 在 Python 的發展過程中產生了三種格式化輸出方式, Python 2.x 使用 % 字元做為控制格式的運算子, Python 3 之後則在字串物件上新增了 format() 方法 (此方法後來也反向移植到 Python 2.7 裡), 而 Python 3.6 以後則新增了效率更好的 f 字串用法, 可以在字串中直接嵌入變數. 


1. 使用 % 運算子 : 

這是 Python 最早的字串格式化做法, 它是在字串中使用 % 運算子控制對應的變數在字串中的輸出格式, 其語法如下 : 

print("...%? .... %?" % (var1, var2, ...))     # 其中 %? 為格式化字串

print() 傳入參數分成三部分 : 




前面部分是內嵌格式化字串 %? 的輸出字串, 中間是 % 字元, 後面部分是要嵌入的變數序列元組 (對應前面的格式化字串), 變數數目需與前面輸出字串內的格式化字串 %? 數目一致, 輸出時將以對應之格式逐一插入字串中. 這三個部分可以連寫, 不需要用空格隔開, 但為了提高可讀性, 通常會用空格隔開. 如果只有一個變數要輸出, 則 tuple 的小括弧可以省略. 

% 格式化字元可控制變數輸出時的對齊方式, 正數是否冠 + 號, 空位是否補 0, 最小輸出長度, 以及精確度等, 語法如下 :

%[-][+][0][寬度][.精確度]型態

中括號表示可有可無, 說明如下 : 
  • - : 指定靠左對齊 (即寬度過多時預設為靠右對齊)
  • + : 正數前面加上 + 號
  • 0 : 寬度過多時空位補 0 (僅用於數值), 預設補空格
  • 寬度 : 指定最小輸出寬度 (超出時不受此限制)
  • 精確度 : 指定浮點數精確度到小數點後幾位或輸出字串中的前幾個字元
  • 型態 : 如 s (字串), d (整數), f (浮點數), e (科學表示法) 等
注意, 浮點數的寬度包含小數點, 資料寬度超過此指定寬度時不會被截斷 (因為這是最小寬度), 而是顯示完整的資料, 但變數值實際寬度小於此最小寬度設定時則會預設補空格 (數值可用 0 格式設為補 0). 資料寬度小於設定時也有對齊問題, 不論字串或數值在 % 格式化裡預設都是靠右對齊. 精確度雖然大部分用在浮點數或其科學表示法, 但也可用在字串, 表示輸出前幾個字元.  

另外, 寬度與精確度都可以用變數控制, 這時格式字元要用 * 字元代替明確之整數, 在 % 後面的 tuple 中, 必須在輸出資料的前面依序增加寬度與精確度之設定值 (可用變數), 如下圖所示 :



 
 控制資料型態的格式化字元如下表 :


 格式化字元 說明
 d 或 i 以整數格式輸出 (預設)
 f 或 F 以浮點數格式輸出數值
 s 以字串格式輸出任何資料型態之字串 (無引號)
 r 以字串格式輸出任何資料型態之字串 (有引號)
 c 輸出 0~127 整數所代表之 ASCII 字元
 x 以小寫之 16 進制格式 (0~9, a~f) 輸出整數
 X 以大寫之 16 進制格式 (0~9, A~F) 輸出整數
 o 以 8 進制整數格式 (0~7) 輸出整數
 e 以小寫 e 科學記號式輸出數值
 E 以大寫 E 科學記號式輸出數值
 g 以小寫 e 科學記號式輸出數值 (短格式)
 G 以大寫 E 科學記號式輸出數值 (短格式)
 % 輸出 % 字元


格式化輸出主要分為字串/字元與數值兩類, 其中最常用的是 %d (整數), %f (浮點數), 以及 %s (字串) 這三個, 例如 : 

>>> d=123                     # 整數
>>> f=3.14159               # 浮點數
>>> s='Hello World'     # 字串
>>> print('d=%d f=%f s=%s' % (d, f, s))     # 用適當的格式輸出    
d=123 f=3.141590 s=Hello World

如果只有一個資料要輸出, 變數可加或不加小括弧; 但兩個以上則必須加小括弧成為 tuple :

>>> print('d=%d' % d)          # 只輸出一個變數時可加或不加小括弧
d=123
>>> print('d=%d' % (d))       
d=123
>>> print('d=%d f=%f s=%s' % d, f, s)    # 輸出兩個以上變數時必須用 tuple 形式     
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: not enough arguments for format string     

變數通常應該使用適當的格式輸出 (數值用 %d, %f , %x 等, 字串用 %s), 但所有資料型態都可用 %s 字串格式輸出,  反之則不成立, 字串不可以用數值格式輸出, 例如 : 

>>> print('%s' % 123)                # 整數可用 %s 格式輸出
123
>>> print('%s' % 3.14159)         # 浮點數可用 %s 格式輸出
3.14159
>>> print('%s' % 3e-10)             # 浮點數可用 %s 格式輸出
3e-10
>>> print('%d' % '123')             # 字串不可用 %d 格式輸出
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: %d format: a number is required, not str
>>> print('%f' % '3.14159')       # 字串不可用 %f 格式輸出
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: must be real number, not str


(1). 輸出字串 : 

格式字元 s 或 r 可用來輸出字串, 兩者的差別是 %r 輸出的字串有引號, 而 %s 則沒有, 例如 :

>>> print('%s' % 'Hello World')    
Hello World
>>> print('%r' % 'Hello World')       
'Hello World'

這跟呼叫內建函式 str() 與 repr() 的效果類似, 呼叫後者會在傳入字串外再包一個雙引號 : 

>>> str('Hello')    
'Hello'
>>> repr('Hello')    
"'Hello'"  

關於 repr() 與 str() 參考 :


如果有指定寬度, 多出來的空位會補空格且預設向右對齊; 若要向左對齊可用 - 格式. 但實際字串大於指定寬度時會輸出完整字串, 而非截掉字串, 例如 : 

>>> print('|%10s' % 'Hello')             # 指定寬度 10, 預設向右對齊補空格
|     Hello
>>> print('%-10s|' % 'Hello')           # 指定寬度 10, 指定向左對齊預設補空格
Hello     |
>>> print('%5s' % 'Hello World')    # 字串長度超過指定時輸出完整字串
Hello World

字串也可以指定精確度, 它會控制要輸出字串中的前幾個字元, 例如 : 

>>> print('%.1s' % 'Hello')        # 輸出字串的前 1 個字元
H
>>> print('%.2s' % 'Hello')        # 輸出字串的前 2 個字元 
He
>>> print('%.3s' % 'Hello')        # 輸出字串的前 3 個字元
Hel
>>> print('%.4s' % 'Hello')        # 輸出字串的前 4 個字元
Hell
>>> print('%.5s' % 'Hello')        # 輸出字串的前 5 個字元
Hello
>>> print('%.6s' % 'Hello')        # 輸出字串的前 6 個字元
Hello

+ 格式只用在數值, 對字串無作用, 例如 : 

>>> print('%+s' % 'Hello')    
Hello

由於 % 被用來識別格式化字串的起點, 如果要輸出 % 本身必須用 %%, 例如 :

>>> print('%d%%' % (42))        # 輸出 % 字元本身
42%


(2). 輸出 ASCII 字元 : 

格式字元 c 可用來將 ASCII 碼 (0~127) 輸出為 ASCII 字元, 例如 : 

>>> print('%c' % 48)      # 輸出 ASCII 碼 48 的字元
0
>>> print('%c' % 57)      # 輸出 ASCII 碼 57 的字元
9
>>> print('%c' % 65)      # 輸出 ASCII 碼 65 的字元
A
>>> print('%c' % 90)      # 輸出 ASCII 碼 90 的字元
Z

這與內建函式 chr() 效果相同, 例如 :

>>> chr(48)          # 傳回 ASCII 碼 48 的字元
'0'
>>> chr(57)          # 傳回 ASCII 碼 57 的字元
'9'
>>> chr(65)          # 傳回 ASCII 碼 65 的字元
'A'
>>> chr(90)          # 傳回 ASCII 碼 90 的字元
'Z'

順帶一提, chr() 的反函數是 ord(), 它會傳回傳入字元之 ASCII 碼, 例如 : 

>>> ord('0')          # 傳回字元 0 的 ASCII 碼
48
>>> ord('9')          # 傳回字元 9 的 ASCII 碼
57
>>> ord('A')         # 傳回字元 A 的 ASCII 碼
65
>>> ord('Z')          # 傳回字元 Z 的 ASCII 碼
90


(3). 輸出整數 : 

輸出 10 進制整數可用 %d 格式, 輸出 8 進制整數使用 %o 格式, 輸出 16 進制整數則用 %x 格式 (小寫) 或 %X 格式 (大寫), 但就是缺了輸出二進制整數的格式 (沒有 %b 格式), 例如 : 

>>> print('%d' % 123)        # 10 進制
123
>>> print('%o' % 123)        # 8 進制
173
>>> print('%x' % 123)        # 16 進制 (小寫)
7b
>>> print('%X' % 123)       # 16 進制 (小寫)  
7B

不論哪個進制都可以配合使用 -, +, 0 等格式字元. 指定寬度格式時若整數小於此寬度時預設會向右靠齊, 並在前面空位補空格, 例如 : 

>>> print('|%10d' % 12345)         # 最小寬度 10, 預設靠右對齊補空格
|     12345
>>> print('|%010d' % 12345)       # 最小寬度 10, 預設靠右對齊補 0
|0000012345
>>> print('%-10d|' % 12345)        # 最小寬度 10, 指定靠左預設補空格
12345     |
>>> print('%-010d|' % 12345)      # 最小寬度 10, 指定靠左補 0 (無作用)
12345     |
>>> print('%3d' % 12345)            # 數值長度超過指定時輸出完整數值
12345

可見對整數而言, 指定靠左對齊時右方補 0 是沒作用的. 其它進制也是如此, 例如 16 進制 : 

>>> print('|%10x' % 56789)        # 16 進制預設靠右補空格
|      ddd5
>>> print('%010x|' % 56789)      # 16 進制預設靠右補 0
000000ddd5|
>>> print('%-10x|' % 56789)       # 16 進制指定靠左補空格
ddd5      |
>>> print('%3x' % 56789)           # 數值長度超過指定時輸出完整數值
ddd5
>>> print('%-010x|' % 56789)      # 最小寬度 10, 指定靠左補 0 (無作用)
ddd5      |

格式 + 會在正數前面添加 + 號 (0 算正數), 例如 : 

>>> print('%+d' % 12345)     # 正數會冠 +
+12345
>>> print('%+d' % 0)             # 0 被視為正數
+0
>>> print('%+d' % -12345)    # 負數不冠 +
-12345

指定精確度對整數沒甚麼意義, 但也不會報錯, 而是輸出完整的數字, 例如 :

>>> print('%.3d' % 12345)  
12345
>>> print('%.1d' % 12345)      
12345
>>> print('%2.1d' % 12345)     
12345

整數可以用 %e 或 %E 格式以科學表示法輸出, 也可以指定精確度, 例如 : 

>>> print('%e' % 12345)         # 預設顯示到小數第 6 位 (空位補 0)
1.234500e+04
>>> print('%E' % 12345)        # 預設顯示到小數第 6 位 (空位補 0)
1.234500E+04
>>> print('%.2e' % 12345)       # 顯示到小數 2 位 (四捨五入)
1.23e+04
>>> print('%.2E' % 12345)      # 顯示到小數 2 位 (四捨五入)
1.23E+04
>>> print('%e' % 1456789)      # 超出小數 6 位則完整輸出
1.456789e+06
>>> print('%.1e' % 1456789)    # 顯示到小數 1 位 (四捨五入)
1.5e+06
>>> print('%.1e' % 1446789)    # 顯示到小數 1 位 (四捨五入)   
1.4e+06

可見 e 或 E 格式預設會顯示到小數點後 6 位, 不足 6 位時空位補 0, 若指定精確度則四捨五入到指定之位數.  


(4). 輸出浮點數 :

輸出浮點數使用 %f 格式, 數值預設靠左顯示, 預設顯示到小數 6 位, 若小數部分有空位補 0 到 6 位, 超過則四捨五入到小數 6 位, 例如 : 

>>> print('圓周率=%f' % 3.14)                # 小數點後不足 6 位補 0 
圓周率=3.140000  
>>> print('圓周率=%f' % 3.14159)          # 小數點後不足 6 位補 0
圓周率=3.141590   
>>> print('圓周率=%f' % 3.1415926)      # 超過舊四捨五入到小數 6 位
圓周率=3.141593  

注意, 對浮點數指定寬度時是包含小數的. 指定精確度時會四捨五入到指定之小數位數; 指定 0 格式時空位會補 0 (預設補空格); 指定 + 格式時正數會顯示 + 號; 指定 - 格式會讓數值靠左對齊 (數值預設靠右對齊), 例如 : 

>>> print('圓周率=%12f' % 3.14159)         # 預設左方空位補空格
圓周率=    3.141590
>>> print('圓周率=%12.1f' % 3.14159)      # 指定顯示小數 1 位 (四捨五入)
圓周率=         3.1
>>> print('圓周率=%12.2f' % 3.14159)      # 指定顯示小數 2 位 (四捨五入)
圓周率=        3.14
>>> print('圓周率=%12.3f' % 3.14159)      # 指定顯示小數 3 位 (四捨五入)
圓周率=       3.142
>>> print('圓周率=%012.2f' % 3.14159)    # 指定左方空位補 0
圓周率=000000003.14
>>> print('圓周率=%+12f' % 3.14159)       # 正數顯示 +
圓周率=   +3.141590
>>> print('圓周率=%-12f' % 3.14159)        # 靠左對齊
圓周率=3.141590 

數值也可用 e 與 E 格式固定用科學表示法輸出, 預設顯示到小數點後 6 位, 過長截斷 (不是四捨五入), 空位則補 0. 指定精確度時會四捨五入到指定之小數位數, 指定寬度時寬度指的是從小數點後面起算的位數 (包含指數部分), 例如 : 

>>> print('%e' % 1.23456789)      # 預設顯示到小數點後 6 位 (截斷)
1.234568e+00
>>> print('%e' % 0.123456789)     
1.234568e-01
>>> print('%e' % 0.0123456789)     
1.234568e-02
>>> print('%+e' % 0.0123456789)      # 正數顯示 + 號
+1.234568e-02
>>> print('%.2e' % 0.0123456789)     # 指定精確度到小數後 2 位 (四捨五入)
1.23e-02
>>> print('%.3e' % 0.0123456789)     # 指定精確度到小數後 3 位 (四捨五入)
1.235e-02   
>>> print('%10e' % 0.0123)       # 指定小數點後 6 位 
1.230000e-02    

格式 g 與 G 會根據值的大小自動選擇用整數, 浮點數, 或科學表示法來輸出數值, 小數部分若與整數部分比起來小很多, 則小數部分會被捨棄. 指數超過 6 次方或小於 -5 次方時時會以科學表示法輸出 (相當於使用 e 或 E 格式), 在這範圍之內則用整數或浮點數輸出, 例如 : 

>>> print('%g' % 123456)                 # 用 g 格式輸出整數
123456
>>> print('%g' % 123456.789)          # 整數很大, 捨棄小數部分
123457
>>> print('%g' % 1234567)               # 寬度較長時自動改為科學表示法
1.23457e+06    
>>> print('%g' % 1234567.89)          # 寬度較長時自動改為科學表示法  
1.23457e+06
>>> print('%g' % 0.123456789)        
0.123457
>>> print('%g' % 0.0123456789)      
0.0123457
>>> print('%g' % 0.00123456789)      
0.00123457
>>> print('%g' % 0.000123456789)         
0.000123457
>>> print('%g' % 0.0000123456789)    # 指數小於 -4 時自動改為科學表示法 
1.23457e-05    
>>> print('%G' % 0.123456789)     
0.123457
>>> print('%G' % 0.0123456789)     
0.0123457
>>> print('%G' % 0.00123456789)    
0.00123457
>>> print('%G' % 0.000123456789)    
0.000123457
>>> print('%G' % 0.0000123456789)    # 寬度較長時自動改為科學表示法    
1.23457E-05  


(5). 可變寬度與精確度的用法 :

以上的範例中寬度與精確度格式均明確指定一個數值, 若用 * 字元取代明確的 m 與 .n則可以變數來控制這兩個格式, 這時後面的變數 tuple 中, 對應變數前面需傳入其寬度與精確度, 語法如下 (以輸出整數為例) : 

'%[+]*.*d' % (width, precision, variable)    

例如 :

>>> print('濕度 : %*d%%' % (5, 50))     
濕度 :    50%
>>> print('濕度 : %0*d%%' % (5, 50))         
濕度 : 00050%
>>> print('濕度 : %0*d%%' % (6, 50))       
濕度 : 000050%

注意, * 格式指的是寬度, 其值必須為整數, 下面是可變寬度的範例 :

>>> print('溫度 : %*.2f' % (6, 28.435))   
溫度 :  28.43
>>> print('溫度 : %0*.2f' % (6, 28.435))      
溫度 : 028.43
>>> print('溫度 : %0*.2f' % (7, 28.435))     
溫度 : 0028.43

下面是可變精確度範例 :

>>> print('溫度 : %6.*f' % (1, 28.435))    
溫度 :   28.4
>>> print('溫度 : %6.*f' % (2, 28.435))    
溫度 :  28.43
>>> print('溫度 : %6.*f' % (3, 28.435))    
溫度 : 28.435
>>> print('溫度 : %6.*f' % (4, 28.435))      
溫度 : 28.4350

下面是寬度與精確度同時可變的範例 : 

>>> print('溫度 : %*.*f' % (6, 1, 28.435))    
溫度 :   28.4
>>> print('溫度 : %*.*f' % (6, 2, 28.435))     
溫度 :  28.43
>>> print('溫度 : %*.*f' % (6, 3, 28.435))     
溫度 : 28.435
>>> print('溫度 : %0*.*f' % (7, 3, 28.435))      
溫度 : 028.435

輸出多個可變寬度格式的範例如下 : 

>>> print('溫度 : %0*.*f 濕度 : %0*d%%' % (6, 2, 28.435, 4, 50))    
溫度 : 028.43 濕度 : 0050%

注意, 使用 * 可變寬度與精確度格式時, 傳入的 tuple 元素要一一對應. 


2.  使用 format() 方法 :

此種方式是從 Python 3.0 開始支援的, 字串物件中多了一個 format() 方法來格式化要輸出的字串, 其語法除對應位置內嵌外, 還支援與位置無關的變數序號內嵌與關鍵字內嵌, 比傳統的 % 格式化更有彈性, 且繼承了 % 格式化字元用法 (除了對齊方式以外). 


(1). 對應位置內嵌 :    

此與傳統 % 格式化用法類似, 只不過把 % 換成 {} 而已, 語法如下 : 

print("...{}...{}...".format(var1, var2, ...))    

例如 : 

>>> name='Tony'       
>>> age=22   
>>> print("name:{} age:{}".format(name, age))    # 將變數輸出到對應之 {}    
name:Tony age:22       
>>> str="name:{} age:{}"        
>>> print(str.format(name, age))       
name:Tony age:22    

內嵌大括弧內可用冒號加上  <, ^, > , +, 0 等格式化字元對變數進行格式化, 語法如下 :

:[[填充]<|^|>|=][+][0][寬度][,][.精確度]型態
  • 填充 : 若資料寬度比指定最小寬度小時用來填充空位的字元
  • < : 靠左對齊
  • ^ : 置中對齊
  • > : 靠右對齊
  • = : 在 +/- 號與數值間用填充字元補位 (僅限數值)
  • + : 正數前面加上 + 號
  • 0 : 寬度過多時空位補 0 (用於數值)
  • 寬度 : 指定最小輸出寬度 (超出時不受此限制)
  • , : 千位符號, 將整數部分每千位打一個逗號
  • 精確度 : 指定浮點數精確度到小數點後幾位或輸出字串中的前幾個字元
  • 型態 : 與 % 格式化之型態相同 (例如 d, f, s 等), 另新增二進制類型 b
這些格式化字元必須放在一個冒號之後. 比較特殊的是, format() 有更豐富的對齊格式, 可靠左, 置中, 與靠右對齊, 而且可在前面設定填充字元, 其優先權比補 0 高. 注意, 填充字元需搭配對齊格式, 不可單獨使用. 其次, format() 增加了一個千位符號格式 (即逗號) 以及二進制整數型態 b. 另外, 由於 format() 使用了大括弧 {} 內嵌, 輸出大括弧本身要用 {{ 與 }}.

% 格式化的 s 類型可用來輸出字串或數值, 例如 :

>>> print('%s' % ('Hello'))       # s 型態本用來輸出字串
Hello
>>> print('%s' % (123))             # s 型態也可輸出數值 (整數)
123
>>> print('%s' % (3.14159))      # s 型態也可輸出數值 (浮點數)
3.14159
>>> print('%s' % (1.23e-9))       # s 型態也可輸出數值 (科學表示法)
1.23e-09

format() 格式化的 s 型態只能輸出字串, 不可用來輸出數值, 否則會報錯, 例如 : 

>>> print('{:s}'.format('Hello'))       # s 型態只能用來輸出字串
Hello
>>> print('{:s}'.format(123))            # s 型態不可用來輸出字數值
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
ValueError: Unknown format code 's' for object of type 'int'
>>> print('{:s}'.format(3.14159))     # s 型態不可用來輸出字數值
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
ValueError: Unknown format code 's' for object of type 'float'
>>> print('{:s}'.format(1.23e-9))      # s 型態不可用來輸出字數值
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
ValueError: Unknown format code 's' for object of type 'float'

當指定之寬度大於資料實際寬度時可設定對齊方式, format() 的對齊分別用 <, ^, 與 > 表示靠左, 置中, 與靠右對齊 (字串預設靠左, 數值預設靠右), 而傳統 % 格式化是預設靠右 (不論字串或數值預設皆靠右), 使用 - 字元控制靠左對齊 (無法置中), 所以 format() 的對其方式較有彈性, 例如 : 

>>> print('|{:10d}|'.format(123))           # 數值預設靠右對齊   
|       123|
>>> print('|{:<10d}|'.format(123))         # 指定靠左對齊
|123       |
>>> print('|{:^10d}|'.format(123))         # 指定置中對齊
|   123    |
>>> print('|{:>10d}|'.format(123))         # 指定靠右對齊
|       123|
>>> print('|{:10s}|'.format('Hello'))       # 字串預設靠左對齊   
|Hello     |
>>> print('|{:<10s}|'.format('Hello'))     # 指定靠左對齊
|Hello     |
>>> print('|{:^10s}|'.format('Hello'))     # 指定置中對齊 
|  Hello   |
>>> print('|{:>10s}|'.format('Hello'))     # 指定靠右對齊
|     Hello|

對齊格式前面可指定填充字元, 當資料寬度小於指定寬度時, 空位就會用此填充字元補滿, 其優先權高於後面的補 0 格式, 亦即, 若輸出數值時同時指定填充字元與補 0, 則補 0 會被忽略. 填充字元對於製作標題或分隔行很方便, 例如 : 

>>> print('{:=^20s}'.format('Hello World'))    # 置中對齊空位以 = 填充
====Hello World=====
>>> print('{:*^20s}'.format('Hello World'))    # 置中對齊空位以 * 填充
****Hello World*****
>>> print('{:=<20s}'.format('Hello World'))    # 靠左對齊空位以 = 填充
Hello World=========
>>> print('{:=>20s}'.format('Hello World'))    # 靠右對齊空位以 = 填充    
=========Hello World
>>> print('{:#^20d}'.format(123))       # 置中對齊空位以 # 填充 (輸出數值)
########123#########
>>> print('{:#^020d}'.format(123))     # 置中對齊空位以 # 填 (補 0 無效)
########123#########

對於數值資料而言, 可用 = 對齊格式設定在 +/- 號與數值之間的空位用填充字元補位, 例如 : 

>>> print('{:0=20d}'.format(123))           # 在 +/- 與數值間以 0 填充
00000000000000000123
>>> print('{:*=20d}'.format(123))           # 在 +/- 與數值間以 * 填充
*****************123
>>> print('{:=+20d}'.format(123))           # 在 +/- 與數值間以空格填充 (預設)
+                123
>>> print('{:0=+20d}'.format(123))         # 在 +/- 與數值間以 0 填充 (正數)
+0000000000000000123
>>> print('{:0=+20d}'.format(-123))        # 在 +/- 與數值間以 0 填充 (負數)
-0000000000000000123 

格式化字元 + 控制正數顯示 + 號, 例如 : 

>>> print('{}'.format(123))          # 預設正數不顯示 + 號
123
>>> print('{:+}'.format(123))      # 指定正數顯示 + 號
+123

format() 方法對於整數新增了二進制類型 b, 以補 % 格式化之缺陷, 例如 : 

>>> print('{:d}'.format(15))      # 輸出 10 進位整數 
15
>>> print('{:x}'.format(15))      # 輸出 16 進位整數 (小寫)
f
>>> print('{:X}'.format(15))     # 輸出 16 進位整數 (大寫)
F
>>> print('{:o}'.format(15))      # 輸出 8 進位整數
17
>>> print('{:b}'.format(15))      # 輸出 2 進位整數
1111
>>> print('{:b}'.format(123))    # 輸出 2 進位整數
1111011

若資料寬度小於指定之最小寬度, 預設空位補空格, 但數值可用 0 格式指定補 0. 字串也可以補 0, 雖然較少會用到, 例如 : 

>>> print('|{:^10d}|'.format(123))             # 預設空位補空格
|   123    |
>>> print('|{:^010d}|'.format(123))           # 指定空位補 0
|0001230000|
>>> print('|{:^010f}|'.format(123.45))       # 指定空位補 0 (浮點數補在小數)
|123.450000|
>>> print('|{:^010.2f}|'.format(123.45))    # 指定空位補 0 (浮點數整數小數均補 0)
|00123.4500|
>>> print('|{:^010s}|'.format('Hello'))   
|00Hello000|

此處特地用 "^" 讓資料置中對齊, 且前後插入 "|" 字元以便觀察空位之補位情形, 可見對於浮點數而言, 沒有指定小數位數時, 0 會全部補在小數尾端; 有指定精確度, 且有空位時, 整數與小數部分會平均補 0.  

format() 新增了千位符號格式, 其位置是在寬度格式後面, 例如 :

>>> print('{:,d}'.format(123456789))         
123,456,789
>>> print('|{:09,d}|'.format(123456789))       # 沒有超過千位不補 0
|123,456,789|
>>> print('|{:010,d}|'.format(123456789))      # 沒有超過千位不補 0
|123,456,789|
>>> print('|{:011,d}|'.format(123456789))      # 沒有超過千位不補 0
|123,456,789|
>>> print('|{:012,d}|'.format(123456789))      # 超過千位才會補 0
|0,123,456,789|

精確度主要是用在浮點數與科學表示法, 以四捨五入方式顯示到指定之小數位數. 精確度也可以用在字串, 這時會輸出字串的前幾個字元, 例如 : 

>>> print('圓周率={:.1f}'.format(3.1415926))    # 四捨五入到小數 1 位
圓周率=3.1
>>> print('圓周率={:.3f}'.format(3.1415926))    # 四捨五入到小數 3 位
圓周率=3.142
>>> print('{:.2e}'.format(0.123456789))              # 四捨五入到小數 2 位
1.23e-01
>>> print('{:.3e}'.format(0.123456789))              # 四捨五入到小數 3 位
1.235e-01
>>> print('{:.4e}'.format(0.123456789))              # 四捨五入到小數 4 位
1.2346e-01
>>> print('message={:.3s}'.format('Hello'))      # 輸出字串中的前 3 字元 
message=Hel
>>> print('message={:.7s}'.format('Hello'))      # 輸出字串中的前 7 字元
message=Hello

若要輸出大括號本身, 需使用 {{ 與 }}, 例如 :

>>> print('集合 s={{{0}}}, {{{1}}}, {{{2}}}'.format(1, 2, 3))      
集合 s={1}, {2}, {3}

此處 {{{0}}} 前面的 {{ 與後面的 }} 都是要輸出大括號本身 (集合符號), 中間的 {0} 才是內嵌要輸出的資料.  


(2). 序號內嵌 :  

除了上述對應位置內嵌外, 還可以在大括弧 {} 中填入序號 (0 起始) 來對應傳入 format() 之資料順序, 語法如下 :

print("...{1}...{0}...".format(ab, ...)) 

此處 a 會被嵌入後面的 {0}, 而 b 則會被嵌入前面的 {1}. 

格式化字串則依序放在冒號後面, 語法如下 :

print("...{0:格式化字串}...{1:格式化字串}...".format(ab, ...)) 

例如 : 

>>> temp=28.435   
>>> humid=50   
>>> print('溫度 : {0} 濕度 : {1}%'.format(temp, humid))   
溫度 : 28.435 濕度 : 50%
>>> print('濕度 : {1}% 溫度 : {0}'.format(temp, humid))      # 序號調換
濕度 : 50% 溫度 : 28.435
>>> print('溫度 : {0:07.2f} 濕度 : {1:04d}%'.format(temp, humid))     
溫度 : 0028.43 濕度 : 0050%
>>> print('溫度 : {0:+08.2f} 濕度 : {1:+06d}%'.format(temp, humid))    # 正數帶 + 號
溫度 : +0028.43 濕度 : +00050%   

若傳入 format() 的引數是串列或元組, 序號後面可用 [] 存取序列中的元素來內嵌, 例如 : 

>>> print('tuple : {0[0]}, {0[1]}, {0[2]}'.format((1, 2, 3)))   
tuple : 1, 2, 3
>>> print('list : {0[0]}, {0[1]}, {0[2]}'.format([1, 2, 3]))        
list : 1, 2, 3


(3). 關鍵字內嵌 :  

也可以直接在 {} 中直接指定關鍵字來內嵌該變數, 語法如下 : 

print("...{b}...{a}...".format(a=v1b=v2, ...)) 

這樣就不需要煩惱序號對應的問題了. 

格式化字串同樣放在冒號之後, 語法如下 :

print("...{b:格式化字串}...{a:格式化字串}...".format(a=v1b=v2, ...)) 

例如 : 

>>> temp=28.435   
>>> humid=50   
>>> print('溫度 : {temp} 濕度 : {humid}%'.format(temp=temp, humid=humid))     
溫度 : 28.435 濕度 : 50%
>>> print('溫度 : {temp:07.2f} 濕度 : {humid:04d}%'.format(temp=temp, humid=humid))   
溫度 : 0028.43 濕度 : 0050%

此種用法最有彈性, 但要注意 format() 裡面的傳入參數必須指定關鍵字, 不可只傳入變數, 否則會出現 KeyError 錯誤, 因為內嵌時找不到所需的關鍵字, 例如 :

>>> temp=28.435   
>>> humid=50   
>>> print('溫度 : {temp} 濕度 : {humid}%'.format(temp, humid))    
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
KeyError: 'temp'    

若傳入 format() 的引數是串列或元組, 關鍵字後面可用 [] 存取序列中的元素來內嵌, 例如 : 

>>> print('tuple : {a[0]}, {a[1]}, {a[2]}'.format(a=(1, 2, 3)))   
tuple : 1, 2, 3
>>> print('tuple : {a[0]}, {a[1]}, {a[2]}'.format(a=[1, 2, 3]))    
tuple : 1, 2, 3


3.  使用 f 字串 :

f 字串是字串前面冠上一個 f 的格式化字串, Python 自 3.6 版開始支援這種字串格式化方式, 它可以將變數或運算式直接用 {} 內嵌到 f 字串中, 比 format() 更好用, 語法如下 : 

print(f".....{var}.....{expression}.....")      

其中 var 為變數, expression 為運算式. 

Python 3.8 版又為 f 字串添加新功能, 在變數或運算式後面加一個 "=" 號將輸出變數名稱或運算式與等號, 這對程式偵錯相當方便, 語法如下 : 

print(f".....{var=}.....{expression=}.....")    

例如 : 

>>> pi=3.14159   
>>> r=5    
>>> print(f'半徑={r}, 圓周長={2*pi*r}, 圓面積={pi*r*r}')    
半徑=5, 圓周長=31.4159, 圓面積=78.53975   
>>> print(f'{r=}, {2*pi*r=}, {pi*r*r=}')   
r=5, 2*pi*r=31.4159, pi*r*r=78.53975

如果在 Python 3.8 之前的環境執行會出現語法錯誤, 例如 : 

>>> print(f'{r=}, {2*pi*r=}, {pi*r*r=}')    
  File "<fstring>", line 1
    (r=)
      ^
SyntaxError: invalid syntax

f 字串的格式化字元與前面 format() 中使用的完全一樣, 只要在變數或運算式後面加個冒號, 後面接著放置格式化字串即可, 語法如下 : 

print(f".....{var:格式化字串}.....{expression:格式化字串}.....")    

例如以 2, 8, 10, 16 進制輸出整數 : 

>>> print(f'{15:d}')         # 輸出 10 進位整數 (小寫)
15
>>> print(f'{15:x}')         # 輸出 16 進位整數 (小寫)
f
>>> print(f'{15:X}')        # 輸出 16 進位整數 (大寫)
F
>>> print(f'{15:o}')         # 輸出 8 進位整數
17
>>> print(f'{15:b}')         # 輸出 2 進位整數
1111

下面是空位補 0 的範例 :

>>> print(f'|{123:^10d}|')             # 預設空位補空格
|   123    |
>>> print(f'|{123:^010d}|')           # 指定空位補 0
|0001230000|
>>> print(f'|{123.45:^010f}|')       # 指定空位補 0 (浮點數補在小數)
|123.450000|
>>> print(f'|{123.45:^010.2f}|')    # 指定空位補 0 (浮點數整數小數均補 0)
|00123.4500|

在對齊格式前指定填充字元的範例如下 : 

>>> print(f'{"Hello World":=<20s}')      # 靠左對齊空位以 = 填充
Hello World=========
>>> print(f'{"Hello World":=^20s}')      # 置中對齊空位以 = 填充
====Hello World=====
>>> print(f'{"Hello World":=>20s}')       # 靠右對齊空位以 = 填充
=========Hello World
>>> print(f'{123:*^20d}')           # 置中對齊空位以 * 填充       
********123*********
>>> print(f'{123:*^020d}')         # 置中對齊空位以 * 填充 (補 0 無效)
********123*********

下面是精確度格式的範例 : 

>>> print(f'圓周率={3.1415926:.1f}')    # 四捨五入到小數 1 位
圓周率=3.1
>>> print(f'圓周率={3.1415926:.3f}')     # 四捨五入到小數 3 位
圓周率=3.142
>>> print(f'{0.123456789:.2e}')               # 四捨五入到小數 2 位
1.23e-01
>>> print(f'{0.123456789:.3e}')               # 四捨五入到小數 3 位
1.235e-01
>>> print(f'{0.123456789:.4e}')               # 四捨五入到小數 4 位
1.2346e-01
>>> print(f'{"Hello":.3s}')                       # 輸出字串中的前 3 字元
Hel
>>> print(f'{"Hello":.7s}')                       # 輸出字串中的前 7 字元 
Hello

注意, 此處因 f 字串使用了單引號, 故 Hello 外面要交替改用雙引號. 

斷斷續續寫了三周終於把格式化測試完畢, 好累. 

參考 : 


2021 年第 52 周記事

終於來到 2021 年的最後一周, 檢視 2021 年初的學習地圖, 成果差強人意, 雖然過去一年暫停 R 語言學習, 專注在 Python/MicroPython, 但進度實在很牛步啊! 那時的計畫是 :

複習 Basics -> 正規式 -> Django -> tkinter

tkinter 已近尾聲, 只剩下幾個元件待測試; Django 只走到一半, 正規式也是寫了一半停住, 倒是 Basics 年底前進度較多, 測完 generator, iterator 以及內建函式 map, enumerator, 與 filter 等中級課題, 剩下 closure 與 modifier 等, 希望能在 2022 年 2 月前完工, 才能全心解決爬蟲, 然後朝 Pandas, Numpy, 與 Scipy 前進, 機器學習部分就緩一緩吧. 

週六因要去五穀宮神農大帝壽辰登席, 所以早上就驅車回鄉下了, 去年因為疫情沒有辦桌, 今年來登席者明顯比往年少, 隔壁桌就是空桌, 上的菜都被附近幾桌拿走. 鄉下老人多 (獨居或兩老), 參加酒席很多人都等著打包回家, 這樣晚餐就不用張羅, 我都禮讓長輩幫他們打包, 只有沒人要包時才帶回家, 避免食物浪費. 

週日去種子行買了 20 株香菜與甜玉米, 下午種在木瓜樹旁, 今年香菜很缺, 以前買菜會送, 今年要買, 一把 10 元, 乾脆自己種. 下午本來要把剩下一小片甘蔗清掉, 但岳母周六下午回高雄了, 上週囑咐要兩瓶甘蔗汁, 我榨好冰箱也不夠放, 所以延到下周唄. 上周待辦事項一項都沒完成, 只是將四台腳踏車拉出來打氣清理而已, 追蹤清單增加一項 :
  1. 剷除菜園甘蔗 (完成一半)
  2. 安裝三層櫃
  3. 安裝衣櫥
  4. 除蟻
  5. 安裝車庫米家監視器 2
  6. 種玉米 + 木瓜 
  7. 清除水圳淤泥 (水利小組長已清)
  8. 整理家祠墓園
寫了兩周的 Python print() 格式化這兩天應可測完, 接下來想學一下 Firebase 用法, 初步探索發現可以用在 GitHub 這種無法執行後台的靜態網站上呈現動態資料 (資料可由樹莓派提供), 而且可以用在 jQuery Mobile 行動網頁. 今年計畫中有想要設計一個時間管理 App 用來管理一年中的重要事件 (例如汽機車保養與保險更新, 家庭保單管理, 事件紀錄簿), 打算搭配 Firebase 來做. 

2021年12月24日 星期五

趙乃吉唱的 "曾經你說"

最近聽菁菁在車上播放了這首好聽的歌 "曾經你說" : 





演唱者為中國女歌手張乃吉, 她的音質清亮又富有層次感, 非常有特色. 

2021年12月23日 星期四

料理實驗 : 試做三色蛋

上週日我用水仙王伯公完福用的皮蛋與市集買菜時順便買的鹹鴨蛋, 依照下面阿慶師的教學試做三色蛋, 可惜高湯與牛奶加過量而失敗 (還有我居然加了生胡蘿蔔絲與不易切斷的金針菇). 今天為了幫菁菁重做一次, 記取教訓 (不加高湯, 不加蔬菜, 牛奶減量) 終於成功啦!  
     




材料 :



作法 : 
  1. 一顆皮蛋與鹹鴨蛋剝殼後對切 1/4 塊後再切丁備用.
  2. 打四顆雞蛋, 將蛋黃與蛋清分開放在兩個碗中, 都加入一小匙米醋與鮮味粉, 蛋清則另加入一湯匙牛奶 (我通常用保久乳), 用筷子各自攪拌均勻備用. 
  3. 取小型鐵方盒 (樂扣那種), 裡面鋪上保鮮膜 (避免蛋黏在盒壁無法取出), 將皮蛋與鹹鴨蛋丁均勻鋪在上面, 然後淋上加了牛奶的蛋清, 平放入電鍋蒸, 10 分鐘後取出, 淋上蛋黃再放進電鍋蒸 10 分鐘即可.
  4. 鉆板上鋪上一層保鮮膜, 將蒸好的三色蛋底朝上放在保鮮膜上取出三色蛋, 用刀切成方塊即可. 
我用大同電鍋蒸較快, 原先蒸 6 分鐘我覺得蛋清不夠固化, 所以延長為 10 分鐘. 加高湯 ok, 但是一湯匙就好, 要不然會太水不易固化. 








晚上菁菁打工回來才說明天有聖誕節活動不用帶便當, 不過因為下課回來沒吃飯就去打工, 所以就當晚餐吃掉唄.