One liner就是以很短的話語說笑話或打動人心,也有很多人使用一行程式,展現Python的威力,以下筆者就節錄一些One liners,與大家共同品味。
list1 = [1, 2, 3, 0, 3, 2, 1]
set(list1)
執行結果:{0, 1, 2, 3}
from collections import Counter
# 測試資料
mylst = [1,1,1,2,2,2,2,3,3,3,3,3,4,4,5,6,6,6]
dict(Counter(mylst))
執行結果:{1: 3, 2: 4, 3: 5, 4: 2, 5: 1, 6: 3}
x, y = 100, 200
temp = x
x = y
y = temp
# 測試
x, y
執行結果:(200, 100)
使用python,可以一行取代,不需借個變數temp:
x, y = 100, 200
y, x = x, y
# 測試
x, y
執行結果:(200, 100)
values = list('零一二三四五六七八九')
values
執行結果:['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
list1 = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
''.join(list1)
執行結果:'零一二三四五六七八九'
values = list('零一二三四五六七八九')
values[::-1]
執行結果:['九', '八', '七', '六', '五', '四', '三', '二', '一', '零']
import sys
mylst = ['India', 'Paris', 'London', 'Italy', 'Rome', '台灣']
sys.getsizeof(mylst)
執行結果:152
List comprehensive就是對陣列(List)的每一個元素進行操作,例如要顯示1~100的偶數,正常寫法如下:
for i in range(2, 101, 2):
print(i)
使用List comprehensive只要一行:
[i for i in range(2, 101, 2)]
執行結果:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100]
以下衍生一些範例:
sum([i for i in range(2, 101, 2)])
執行結果:2550
[i for i in range(2, 101) if i%2 == 0]
與上述程式碼【[i for i in range(2, 101, 2)]】相同。
# 顯示非質數
set([i for i in range(2, 101) for j in range(2, i) if i%j == 0])
執行結果:set可將重複的元素刪除。
# 兩個set相減可取得差集
set([i for i in range(2, 101)]) - set([i for i in range(2, 101) for j in range(2, i) if i%j == 0])
執行結果:
{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}
匿名函數(Lambda function)是沒有名字的函數,可簡化函數的撰寫,也可應用在Functional Programming上,將函數當參數傳遞。
from functools import reduce
reduce(lambda x, y: x * y, range(1, 4))
reduce是Functional Programming的高階函數(Higher Order Functions),會依函數連乘或連加,另外還有map、filter...等。
執行結果:6。
reduce(lambda x, y: x * y, range(1, 6))
執行結果:120。
list(map(lambda x: x ** 2, range(1, 6)))
執行結果:[1, 4, 9, 16, 25]。
list(filter(lambda x: x % 2 == 0, range(1, 101)))
執行結果:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100]
更多Functional Programming請看後續的討論。
values = list('零一二三四五六七八九')
dict(enumerate(values))
執行結果:
{0: '零', 1: '一', 2: '二', 3: '三', 4: '四', 5: '五', 6: '六', 7: '七', 8: '八', 9: '九'}
keys = range(10)
values = list('零一二三四五六七八九')
dict1 = {keys[i]: values[i] for i in range(len(keys))}
# 測試
[dict1[int(i)] for i in list('486')]
執行結果:['四', '八', '六']
''.join([dict1[int(i)] for i in list('486')])
執行結果:'四八六'
keys = range(10)
values = list('零一二三四五六七八九')
dict1 = {keys[i]: values[i] for i in range(len(keys))}
# 依dictionary的value排序
sorted([(k, v) for k, v in dict1.items()], key=lambda x: x[1])
執行結果:依大寫的內碼排序。
[(1, '一'), (7, '七'), (3, '三'), (9, '九'), (2, '二'), (5, '五'), (8, '八'), (6, '六'), (4, '四'), (0, '零')]
也可以依key排序dictionary,只要將x[1]改成x[0]即可。
max([(k, v) for k, v in dict1.items()], key=lambda x: x[1])
執行結果:(0, '零'),【零】內碼為最大值。
{v: k for k, v in dict1.items()} # k, v --> v: k
執行結果:
{'零': 0, '一': 1, '二': 2, '三': 3, '四': 4, '五': 5, '六': 6, '七': 7, '八': 8, '九': 9}
dict1 = {'a': 1, 'b': 2}
dict2 = {'c': 3, 'd': 4}
# 測試
{**dict1, **dict2}
執行結果:
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
使用 one liner定義費波那契(Fibonacci)數列,它是數列的前2個數字加總會等於下一個數字,且上一個數字除以下一個數字會接近0.618,常用於股票漲跌幅的預測。
def Fib(x): return 1 if x in {0, 1} else Fib(x-1) + Fib(x-2)
# 測試前10個數列
[Fib(i) for i in range(1, 11)]
執行結果:
[1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
通常要創建類別(class)如下:
class Employee:
def __init__(self, name, age):
self.name = name
self.age = age
# 測試,實體化物件
michael = Employee("Michael", 25)
michael.age
執行結果:25
可以一行搞定:
Employee = lambda:None; Employee.name = "Michael"; Employee.age = 25
# 測試
type(Employee)
執行結果:<class 'function'>,確實是一個類別,注意,在Jupyter Notebook測試,只會得到function。
使用One liner可以減少程式碼的撰寫,並有效縮小程式碼的行數,缺點是初入門者需花點時間才能理解,系統維護會增加一點難度,可以將One liner包成函數,讓初入門者直接呼叫函數即可。
以上內容係參考下列文章:
本系列的程式碼會統一放在GitHub,本篇的程式放在src/3資料夾,歡迎讀者下載測試,如有錯誤或疏漏,請不吝指正。