言語ごとの特徴 · 40
Python らしいコード
内包表記、ステップ付きのスライス、アンパック、enumerate・zip、in、f 文字列、そして3つの落とし穴。
この単元は Python 向けです。
ほかの言語は同じことをループかライブラリのメソッドで書きます(JavaScript map・filter、Java のストリーム、C# の LINQ、C・C++・Craykon はループと push_back・追加)。
Python には、何行ものループを1行に縮める短い書き方がたくさんあります。
下の例は内包表記・スライス・アンパック・enumerate・zip・f 文字列を順に使い、最後にエラーなしで間違った答えを出す落とし穴を2つ見せます。
nums = list(map(int, input().split()))words = input().split() odd_squares = [x * x for x in nums if x % 2 == 1]print(*odd_squares)print({x % 3 for x in nums})print({w: len(w) for w in words}) print(*nums[::-1])print(*nums[1:6:2])print(words[0][::-1]) first, *rest = numsa, b = first, rest[-1]a, b = b, aprint(a, b, len(rest)) for i, w in enumerate(words, start=1): print(f"{i}. {w:<6}|")print(*(f"{w}={n}" for w, n in zip(words, nums)))print(9 in nums, "lo" in words[0]) gen = (x for x in nums)print(sum(gen), sum(gen)) grid = [[0] * 3] * 2grid[0][0] = 1print(grid)grid = [[0] * 3 for _ in range(2)]grid[0][0] = 1print(grid)3 1 4 1 5 9 2 6 hello world codes
9 1 1 25 81
{0, 1, 2}
{'hello': 5, 'world': 5, 'codes': 5}
6 2 9 5 1 4 1 3
1 1 9
olleh
6 3 7
1. hello |
2. world |
3. codes |
hello=3 world=1 codes=4
True True
31 0
[[1, 0, 0], [1, 0, 0]]
[[1, 0, 0], [0, 0, 0]]
ポイント
- 内包表記(comprehension)は、ループ1行で新しいリストを作ります。
[x * x for x in nums if x % 2 == 1]は「奇数だけを選んで2乗したリスト」で、空のリストにappendする4行のループがこの1行になります。 - 括弧を変えるだけで、同じ形で集合
{x % 3 for x in nums}や辞書{w: len(w) for w in words}も作れます。 - スライス
a[開始:終わり:ステップ]は終わりを含まず、省略した部分は先頭・末尾・1 になります。nums[1:6:2]は 1・3・5 番、nums[::-1]は逆順の新しいリスト、"hello"[::-1]は"olleh"です。 - 範囲を超えるスライスはエラーにならず、ある分だけを返します(
nums[5:100])。
負の番号は後ろから数えるので、a[-1]が最後です。 - アンパック:
a, b = b, aは一時変数なしで入れ替え、first, *rest = numsは最初の値と残りのリストに分けます。
番号はenumerate(words, start=1)、2つのリストを並べて回すならzip(words, nums)(短い方で止まります)を使います。 inは含まれているかを調べます。
リストは前から1つずつ探すので遅く、集合・辞書はほぼすぐに見つけます。
文字列では"lo" in "hello"のように部分文字列を探します。
言語ごとの書き方
| Python | f 文字列 f"{i}. {w:<6}|" は波括弧の中に式、: のあとに書式(<6 は6桁左寄せ、.2f は小数第2位まで)。f"{x=}" は x=3 のように名前まで出すのでデバッグに便利です。range(len(...)) で番号を回すことはあまりせず、ステップ付きのスライスや [::-1] は Python だけの短い書き方です |
|---|
よくある間違い
デフォルト値に [] を置いた
def add(x, bucket=[]):
bucket.append(x)
return bucket
add(1); print(add(2))→ [1, 2] — [] は関数を作るときに一度だけ作られるので、呼ぶたびに同じリストを使います
bucket=None にして、関数の中で if bucket is None: bucket = [] と新しく作ります。
ジェネレータを2回使った
gen = (x for x in nums)
print(sum(gen), sum(gen))→ 31 0 — 丸括弧 ( ) はリストではなく、一度使うと空になるジェネレータです
2回使うなら角括弧 [ ] でリストを作ります。
[[0] * 3] * 2 で2次元リストを作った
grid = [[0] * 3] * 2
grid[0][0] = 1
print(grid)→ [[1, 0, 0], [1, 0, 0]] — 外側の * 2 は内側のリストをコピーせず、同じリストを2回入れます
[[0] * 3 for _ in range(2)] のように内包表記で行ごとに新しく作ります([0] * 3 のように数を掛けるのは大丈夫です)。
言語ごとの違い
掛け算(
リストを複数作るなら内包表記、デフォルト値は
掛け算(
* m)で作った2次元リストと =[] のデフォルト値は、エラーなしで同じリストを共有するので、思わぬところが変わります。リストを複数作るなら内包表記、デフォルト値は
None にしてください。