この記事はTakumi Akashiro ひとり Advent Calendar 2020の19日目の記事です。
始めに
土曜は練習がてらにAEのスクリプトを作りました!ってストックしていたネタを使おうと思っていましたが、
記事を書く前に調べたところ、同様のことがAEの標準機能でできることが判明し、見事に没になったので、
代わりに、たまに使うPythonの組み込み関数について書きます。
正直、公式ドキュメントを毎日10分1関数ずつでも読んだ方が有用です。
みんなも読もう!公式ドキュメント!
Pythonの組み込み関数
zip(*iterables)
それぞれのイテラブルから要素を集めたイテレータを作ります。
組み込み関数 — Python 3.9.1 ドキュメント より
>>> src_paths = ["c:/nanka", "c:/unagi", "c:/ankimo"]
>>> dst_paths = ["d:/nanka", "f:/unagi", "e:/ankimo"]
>>>
>>> list(zip(src_paths, dst_paths))
[('c:/nanka', 'd:/nanka'), ('c:/unagi', 'f:/unagi'), ('c:/ankimo', 'e:/ankimo')]
>>>
>>> dst_files = ["ohagi", "ooiwa", "karasumi"]
... for src_path, dst_path, dst_file in zip(src_paths, dst_paths, dst_files):
... print(src_path, dst_path, dst_file)
c:/nanka d:/nanka ohagi
c:/unagi f:/unagi ooiwa
c:/ankimo e:/ankimo karasumi
割とよく使いますね。たまに使う、の括りに入れるべきではないかもしれませんが、
知らない人は知らないままかけちゃうので今回紹介します。
個人的にはzip()
とdict()
の合わせ技dict(zip(keys, values))
が結構好みです。
sorted(iterable, *, key=None, reverse=False)
イテレート可能なオブジェクトをソートしてlist
として返します。
いや、それだけなら知ってるよという方もいると思いますが、今回紹介したいのはkey
引数です。
key
には引数が一つの関数を渡せます。その結果を使ってソート可能、ということです。
>>> sorted(["A", "a", "d", "B"])
['A', 'B', 'a', 'd']
>>> sorted(["A", "a", "d", "B"], reverse=True)
['d', 'a', 'B', 'A']
>>>
>>> sorted(["A", "a", "d", "B"], key=str.lower)
['A', 'a', 'B', 'd']
>>>
>>> sorted(["A", "a", "d", "B"], key=lambda x: {"A": 99, "a": 0, "d": 3}.get(x, 100))
['a', 'd', 'A', 'B']
>>>
>>> sorted({"onaka": 2, "udon": 0}.items(), key=lambda item: item[1])
[('udon', 0), ('onaka', 2)]
例にもあるように、辞書をlistに変えたときにvalue側の値でソートしたい、みたいなケースで使えますね。
hasattr(object, name)
オブジェクトがname
と名のついた属性を持っているか確認します。
>>> import datetime
>>> class SampleClass(object):
... # __init__ は実装しないので省略。
... def print_sample(self):
... if not hasattr(self, "_text"):
... print("Generate!")
... self._text = str(datetime.datetime.now())
... print(self._text)
...
>>> sample = SampleClass()
>>> sample.print_sample()
Generate!
2020-12-19 23:16:19.197768
>>> sample.print_sample()
2020-12-19 23:16:19.197768
>>> sample.print_sample()
2020-12-19 23:16:19.197768
個人的にはクソコード生成に便利な関数
インスタンス変数を既に定義されてるか確認して、定義してなかったら初期化する~みたいなときに使いますね。
便利ですが、TPOをわきまえないと保守性を下げることに繋がります。
自分もシングルトンもどきを作りたいとき以外は使わないですかね。
globals()
現在のグローバルシンボルテーブルを表す辞書を返します。これは常に現在のモジュール (関数やメソッドの中では、それを呼び出したモジュールではなく、それを定義しているモジュール) の辞書です。
組み込み関数 — Python 3.9.1 ドキュメント より
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None,
'__spec__': None, '__annotations__': {},'__builtins__': <module 'builtins' (built-in)>}
>>> import sys
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None,
'__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>,
'sys': <module 'sys' (built-in)>}
MayaのScriptEditorでglobals()
を使うと、インタプリタで宣言されているオブジェクトを取得できます。
なので、あのモジュールimportしたかな?と思ったときに叩きます。大体は叩く前にimportしちゃいますが。
id(object)
オブジェクトのidを返す関数です。
idが同一のオブジェクトは同一です。(当然ですが)
hoge is huga
のis
比較はこのidを比較しています。
>>> sample_str_a = "apple"
>>> sample_str_b = "apple"
>>>
>>> print(id(sample_str_a) == id(sample_str_b), id(sample_str_a), id(sample_str_b))
True 1289401480176 1289401480176
>>>
>>> sample_str_a += " pie"
False 1289401480240 1289401480176
# str型は += すると別のオブジェクトを返している。
>>>
>>> sample_list_a = []
>>> sample_list_b = []
>>>
>>> sample_list_a == sample_list_b
True
>>> sample_list_a is sample_list_b
False
>>> print(id(sample_list_a) == id(sample_list_b), id(sample_list_a), id(sample_list_b))
False 1289401452736 1289401452800
>>> # isと同じ結果が出る
>>>
>>> sample_list_c = sample_list_d = []
>>> sample_list_c += ""
>>> print(id(sample_list_c) == id(sample_list_d), id(sample_list_c), id(sample_list_d))
True 1289401453376 1289401453376
>>> # 同一オブジェクトである
>>>
>>> sample_list_c += ["lorem ipsum"]
>>> print(id(sample_list_c) == id(sample_list_d), id(sample_list_c), id(sample_list_d))
True 1289401453376 1289401453376
>>> # まだ同一オブジェクト
>>>
>>> print(sample_list_c, sample_list_d)
['sample'] ['sample']
>>> # 中身も同じ
前はデバッグで使っていましたが、ptvsdの出現でめっきり使わなくなりました。
番外編
try-finally
文
例外の有無に関わらず、必ず最後に実行します。
>>> try:
... sample = 0 / 0
... finally:
... print("--- Fin ---")
--- Fin ---
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero
>>> try:
... sample = 0 / 0
... except:
... pass
... finally:
... print("---- Fin 2 ----")
---- Fin 2 ----
処理が実行できたかに関わらず、セーブしたい1って場合に使えます。
del
で必ず参照を切らないと不味い場合にも使えます。
for-else
文
for
が正常に終了したときにelse
の内容を実行します。
break
でループを抜けた場合は実行しません。
>>> for x in range(3):
... print(x)
... else:
... print("Fin !")
...
0
1
2
Fin !
>>> for x in range(3):
... print(x)
... break
... else:
... print("Fin !")
0
検索して見つからなかった場合にデフォ値を設定したいときですかね?
それなら先にデフォ値をセットして、見つかった値で上書きすればいいしなあ……
……うーん使った覚えがない。ならここに乗せンなや!
締め
こういうネタに興味があれば、Fluent PythonとかEffective Pythonとかオススメです。
Fluent Python、1ページ7.8円なのでページ換算すると安いですよ!832ページあるけど。
それに比べて、Effective Pythonは456ページしかない!読みやすい!京極夏彦の文庫版「魍魎の匣」の半分以下!
こっちは割とオススメです。Pythonに手慣れてきたけど、もうちょっと理解を深めてみたいな……って思った時が買い時ですね。
-
そんなときあるか? ↩