iT邦幫忙

2022 iThome 鐵人賽

DAY 18
0
自我挑戰組

從前端角度看30天學Python系列 第 18

【Day 18】引數打包與開箱

  • 分享至 

  • xImage
  •  
  • 開箱(unpacking)
  • 打包(packing)
  • 展開(spreading)
  • 列舉(enumerate)
  • 壓縮(zip)

這篇文章是閱讀Asabeneh的30 Days Of Python: Day 17 - Exception Handling後的學習筆記與心得。

是的,原文章是在Day 17提到,但這怎麼看都不像例外處理,因此我想拿到Day 18討論。


基本上就像是JavaScript中的展開運算子(spread syntax)的用法:

  • 元組(tuples)用*
  • 字典(dictionaries)用**

開箱(unpacking)

假設我們有個函式get_date_object接收三個參數day, month_name,和year

from datetime import datetime

def get_date_object(day, month_name, year):
    date_string = "%s %s, %s" %(day, month_name, year)
    return datetime.strptime(date_string, "%d %B, %Y")
    
date_param = ["24", "December", "2022"]

# results TypeError
date_object = get_date_object(date_param)

print(date_object)
  • 可以看到date_param是一個list,不能直接當參數傳入get_date_object否則會產生TypeError
  • 這時只要加個*像:get_date_object(*date_param),就能順利拿到並印出2022-12-24 00:00:00

就像在 Day 5 List 時提到的開箱用法:

numbers = [1, 2, 3, 4, 5, 6, 7]
one, *middle, last = numbers
print(one, middle, last) # 1 [2, 3, 4, 5, 6] 7

如果是字典(dictionary),則加的是**

from datetime import datetime

def get_date_object(day, month_name, year):
    date_string = "%s %s, %s" %(day, month_name, year)
    return datetime.strptime(date_string, "%d %B, %Y")

date_param = {"day": "24", "month_name": "December", "year": "2022"}

date_object = get_date_object(**date_param)

print(date_object)
  • 如果少加了一個*會產生錯誤:"ValueError: time data 'day month_name, year' does not match format '%d %B, %Y'",看起來是變成拿到key而非value

打包(packing)

這裡針對 list 的打包用法在Day 11 Functions有提到過,效果就像JS中的其餘參數(rest parameter)

def sum_all(*args):
	s = 0
	for i in args:
		s += i
	return s

print(sum_all(1, 2 ,3))

如果是打包 dictionary 的話也跟上面開箱一樣,改用**就行了:

def packing_person_info(**kwargs):
	for key in kwargs:
		print(f"{key} = {kwargs[key]}")
	return kwargs

print(packing_person_info(name="John", city="Taipei", age=25))

印出的結果如下:

name = John
city = Taipei
age = 25
{'name': 'John', 'city': 'Taipei', 'age': 25}

展開(spreading)

同樣開箱的用法,也可以用在展開上,就像JS的...那樣:

# for list
lst_one = [1, 2, 3]
lst_two = [4, 5, 6, 7]
lst = [0, *lst_one, *lst_two]

print(lst) # [0, 1, 2, 3, 4, 5, 6, 7]

# for dictionary
test = {"foo": "bar", "beep": "boop", "hello": "tmp"}
result = {**test, "hello": "world"}

print(result) # {'foo': 'bar', 'beep': 'boop', 'hello': 'world'}

列舉(enumerate)

如果想要像JS中的map((item, index) => unknown)一樣拿到index參數的話,可以用enumerate

  • 語法enumerate(iterable, start=0)
  • 回傳值:enumerate object
colors = ["red", "blue", "green", "yellow", "orange"]

for index, color in enumerate(colors):
    print (index, color)

上面這個例子會輸出:

0 red
1 blue
2 green
3 yellow
4 orange

也可以用list()tuple()轉換enumerate object:

colors = ["red", "blue", "green", "yellow", "orange"]

print(list(enumerate(colors)))
# [(0, 'red'), (1, 'blue'), (2, 'green'), (3, 'yellow'), (4, 'orange')]

print(tuple(enumerate(colors)))
# ((0, 'red'), (1, 'blue'), (2, 'green'), (3, 'yellow'), (4, 'orange'))

壓縮(zip)

若需要結合兩個 list 的操作,可以使用zip函式:

  • 語法zip(*iterables, strict=False)
    • strict 這個參數若為True會檢查iterables的資料長度是否都相同,否則會產生ValueError。
  • 回傳值:tuple
colors = ["red", "blue", "green", "yellow", "orange"]
hex_code = ["#FF0000", "#0000FF", "#00FF00" , "#FFFF00", "#FFA500"]

color_code = [{"color": color, "hex": code} for color, code in zip(colors, hex_code)]

print(color_code)
# [{'color': 'red', 'hex': '#FF0000'}, {'color': 'blue', 'hex': '#0000FF'}, {'color': 'green', 'hex': '#00FF00'}, {'color': 'yellow', 'hex': '#FFFF00'}, {'color': 'orange', 'hex': '#FFA500'}]

strict 參數看的是傳入的iterables的資料長度是否不同:

  • 設為 False (預設)的情況下,會以最短的那個遍歷完就終止並回傳,跟Python的 map 函式一樣。
  • 設為 True 的情況下,會產生ValueError:
origin_color = ["red", "green", "blue"]
hex_code = ["#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FFA500"]

print(tuple(zip(origin_color, hex_code, strict=False)))
# (('red', '#FF0000'), ('green', '#00FF00'), ('blue', '#0000FF'))

print(tuple(zip(origin_color, hex_code, strict=True)))
# ValueError: zip() argument 2 is longer than argument 1

上一篇
【Day 17】例外處理
下一篇
【Day 19】正規表達式
系列文
從前端角度看30天學Python30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言