Effective Python(第2版) 2章~3章の気になった箇所をまとめてみた
引き続き、Challeng-Every-Monthというコミュニティで、みんなで Effective Python を読み合うイベントに参加しています。
Effective Pythonの公式の .py コードがGitHubに公開されています。
しばらくバタバタしていて、2章~3章はすべてのコードを詳細に見れていません。
勉強のため、気になったコード、個人的に使えそうだなあと思ったコードを啄んでいます。
手前ミソですが、第1章の記事はこちらです。
2章 項目13 アンパック
変数に * (アスタリスク)を付けてアンパックすることで、複数の変数にリストの値をまとめて代入するとき、リスト内の要素数が変数の数を上回っても代入ことができる。
# 経過年数を表すリスト age_list = [0, 9, 4, 8, 7, 20, 19, 1, 6, 15] # 並び替え sorted_list = sorted(age_list, reverse=True) sorted_list
そのまま複数の変数にまとめて値を代入すると、変数が2つしかないのにリスト内には3つ以上の数値があるため、エラーが発生する。
リストから1番目、2番目に大きい数値を抽出したい
bigest, second_bigest = sorted_list --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-14-6f07495bfa6c> in <module> 1 # 1番目、2番目に大きいものを抽出 2 # エラーになる ----> 3 bigest, second_bigest = sorted_list ValueError: too many values to unpack (expected 2)
スライスで抽出することも可能だが、コードがゴチャついてしまう
bigest = sorted_list[0] second_bigest = sorted_list[1] print(f"bigest: {bigest}, second_bigest: {second_bigest}")
[出力] bigest: 20, second_bigest: 19
アンパックを使うと、スライスを使うよりも行数を少なく処理できる。
bigest, second_bigest, *others = sorted_list print(f"bigest: {bigest}, second_bigest: {second_bigest}, others: {others}")
なお、アンパックのみでデータを受け取ることはできない。
*others = sorted_list File "<ipython-input-104-83e6b9fe5a33>", line 5 SyntaxError: starred assignment target must be in a list or tuple
辞書型のデータもアンパック可能
# 用意した辞書型データ info = { 'age':(20, 19, 15, 9, 8, 7, 6, 4, 1, 0), 'type':("a", "b", "c", "d", "e", "f", "g", "h", "i", "j") } # アンパック処理 ((key1, (value1, *value_others1)), (key2, (value2, *value_others2))) = info.items() # 結果を出力 print(f"No.1 key {key1}: values {value1}, values_others {value_others1}") print(f"No.2 key {key2}: values {value2}, values_others {value_others2}")
[出力]
key age: values 20, values_others [19, 15, 9, 8, 7, 6, 4, 1, 0]
key type: values a, values_others ['b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
イテレータをアンパックすることも可能
def generate(): yield ("a", "b", "c") yield ("d", "e", "f") yield ("g", "h", "i") yield ("j", "k", "l")
it = generate() # イテレータのアンパック first, *others = it print(f"first: {first}, others: {others}")
[出力] first: ('a', 'b', 'c'), others: [('d', 'e', 'f'), ('g', 'h', 'i'), ('j', 'k', 'l')]
ちなみに、スライスを使って処理することも可能
# listに変換する必要がある it_list = list(generate()) print(f"first: {it_list[0]}, others: {it_list[1:]}")
[出力] first: ('a', 'b', 'c'), others: [('d', 'e', 'f'), ('g', 'h', 'i'), ('j', 'k', 'l')]
3章 項目22 可変長位置引数、スター引数
アンパックを使うと、代入するものが何もなくても、空のリストを自動で代入してくれる
# 1つしか要素のないリストを用意する num_list2 = [5] # othersに代入するリストはないので、自動的に空っぽのリストが入る first, *others = num_list2 print(f"first: {first}, others: {others}")
[出力] first: 5, others: []
スライスを使う場合は、空のリストを指定する必要が生じる
first, others = num_list[0], []
空のリストを指定しないとエラーが生じる
first, others = num_list[0] --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-112-99477d836b96> in <module> ----> 1 first, others = num_list[0] TypeError: cannot unpack non-iterable int object
引数であるvalue が空っぽの場合はメッセージのみを返す log()という関数を前提とし、value が空の時、どのような処理になるか確かめる
def log(message, value): if not value: print(message) else: print(message, value)
引数であるvalue に値を代入する場合
log('Number is', [1, 2])
[出力] Number is [1, 2]
引数であるvalue に値を代入しない場合、エラーが生じる
log('Number is Nothing') --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-64-3e547894f1e6> in <module> ----> 1 log('Number is Nothing') TypeError: log() missing 1 required positional argument: 'value'
引数である value に値を代入しない場合は valueに空のリストを指定する必要がある
log('Number is Nothing', [])
[出力] Number is Nothing
引数にスター(*)を付けることで引数に代入する値がなくても自動でからのリストが代入される
def log(message, *value): # values が空っぽの場合はメッセージのみを返す if not value: print(message) else: print(message, value)
log('Number is Nothing')
[出力] Number is Nothing
ただし、引数にスター(*) を付けてしまうと、本来意図しない引数として認識されてしまうこともある
先ほどのlog関数に、sequenceという引数を1番目に追加し、出力にも追加する
なお、sequenceは数値データを想定している
def log2(sequence, message, *value): # values が空っぽの場合はメッセージのみを返す if not value: print(sequence, message) else: print(sequence,"-", value, message, )
7以降の値は引数valueにアンパックされる
log2(1, 'Number is', 7, 13)
[出力] Number is 1 - (7, 13)
引数であるsequenseになにも設定しなかった場合、本来意図しない引数に代入されてしまう
log2('Number is', 7, 13)
[出力] 7 Number is - (13,)
'Number is' が sequenseに、7 がmessageに、13 が value に格納されてしまい、出力がおかしなことになる
なぜこのような処理になるのか原因が突き止めにくいという欠点もある
上記のコードはこちらのPart 2フォルダの中、Chapter 02_03 Select.ipynbになります。
以上になります、最後までお読みいただきありがとうございました。