Pythonの「魔法の記号」を探れ!アスタリスク(*)とコロン(:)の知られざる力

こんにちは。ゆうせいです。

いやあ、嬉しいですね!

前回の「ループのelse」や「リスト内包表記」、そして「タプルスワップ」といったPythonのユニークな特徴に、皆さんが興味を持ってくれているようで、私も話し甲斐があります!

「Pythonic(パイソニック=Pythonらしい)」と呼ばれる書き方は、知れば知るほど「なるほど、賢い!」と膝を打ちたくなるものばかりです。

では、調子に乗って(笑)、今回も新人の皆さんにぜひ知っておいてほしい、「え、そんな使い方が?」と驚くPythonの面白い特徴を、さらに深掘りしてご紹介しますね!


特徴1: 変数の中身を「デバッグ」までしてくれる「f-string」

皆さん、文字列の中に変数の値を埋め込みたいとき、どうしていますか?

name = "ゆうせい"
age = 30
print("こんにちは、" + name + "です。年齢は" + str(age) + "歳です。")

+ でつなげたり、str() で型を変換したり…ちょっと面倒ですよね。

format() メソッドを使う方法もありますが、それでも少し長くなりがちです。

print("こんにちは、{}です。年齢は{}歳です。".format(name, age))

そこで登場するのが、Python 3.6から使えるようになった「f-string(フォーマット済み文字列リテラル)」です!

専門用語解説: f-string (f文字列)

f-stringは、文字列の先頭に f (または F) をつけるだけで、{} の中に変数名や式を直接書き込める、超便利な機能です。

name = "ゆうせい"
age = 30
print(f"こんにちは、{name}です。年齢は{age}歳です。")

どうです? + も str() も format() もいりません!

{} の中に書いた変数が、そのまま値に置き換わっています。直感的ですよね!

{age * 2} のように、{} の中で計算すらできてしまいます。

そして、f-stringの「面白い」機能はこれだけではありません。

Python 3.8からは、デバッグ(プログラムの誤りを見つける作業)に革命を起こす(かもしれない)機能が追加されました。

それは、=(イコール)です!

user_id = "Yusei-001"
score = 85

print(f"デバッグ情報: {user_id=} , {score=}")

実行結果:

デバッグ情報: user_id='Yusei-001' , score=85

見てください! {user_id=} と書いただけなのに、user_id='Yusei-001' というように、「変数名 = 値」の形で出力してくれたんです!

プログラムがうまく動かないとき、「この変数、今、中身なんだっけ?」と確認するために print(user_id) と書くことはよくありますが、f"{user_id=}" なら、どの変数の値なのかが一目瞭然ですね。

これはもう、知ったら戻れない便利さですよ!


特徴2: 「残り全部」を担当する * (アスタリスク)

前回、a, b = b, a というタプル・アンパッキング(荷解き)による値の入れ替え(スワップ)を紹介しました。

このアンパッキング、実は *(アスタリスク)を使うと、さらに柔軟で強力になるんです。

例えば、テストの点数が入ったリスト [80, 90, 75, 88, 92] があるとします。

このリストから、「最初の点数(80)」と「それ以外の点数」に分けたい場合、どうしますか?

* を知らないと、スライス(後述)などを使ってこう書くかもしれません。

scores = [80, 90, 75, 88, 92]
first = scores[0]
rest = scores[1:] # 1番目から最後まで

悪くはないですが、* を使うとこう書けます。

Python

scores = [80, 90, 75, 88, 92]
first, *rest = scores

print(f"最初の点数: {first}")
print(f"残りの点数: {rest}")

実行結果:

最初の点数: 80
残りの点数: [90, 75, 88, 92]

first, *rest = scores と書くだけで、first には最初の 80 が、そして *rest(アスタリスクを付けた rest)には、残りの要素がすべて詰まったリスト [90, 75, 88, 92] が代入されました!

例えるなら、* は「おまとめ袋」です。

アンパッキングするときに、first が自分の分(先頭の1個)を取った後、「じゃあ、残りは全部 * が付いた rest 袋に入れて!」と指示しているようなものです。

もちろん、最初と最後だけ欲しい、という使い方もできます。

first, *middle, last = [80, 90, 75, 88, 92]

print(f"最初: {first}")
print(f"中間: {middle}")
print(f"最後: {last}")

実行結果:

最初: 80
中間: [90, 75, 88]
最後: 92

first が 80 を、last が 92 を取り、残った [90, 75, 88] が *middle にまとめて入りました。

リストの要素数が可変(変わる可能性がある)でも、柔軟に対応できるすごいヤツなんです。


特徴3: リストをひっくり返す呪文 [::-1]

リストや文字列の一部を取り出す「スライス」は、皆さんも使ったことがあるかもしれません。

my_list[1:4] のように書くと、「1番目から4番目の手前まで」を取り出せますよね。

(Pythonは0番目から数えるので、実際にはインデックス1, 2, 3の要素です)

my_list[ 開始位置 : 終了位置 ]

これが基本ですが、実はスライスには「3番目の引数」が存在します。

my_list[ 開始位置 : 終了位置 : ステップ ]

専門用語解説: スライスの「ステップ」

「ステップ」とは、「何個おきに取り出すか」を指定するものです。

デフォルト(省略した場合)は 1 (1個ずつ)になっています。

例えば、[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] というリストから、偶数だけ(2個おき)を取り出したい場合、こう書けます。

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
evens = numbers[::2] # 開始と終了は省略し、ステップだけ 2 を指定

print(evens)
# [0, 2, 4, 6, 8]

[::2] と書くことで、「最初から最後まで、2個おきに」という意味になりました。

そして、ここからが本題です。

この「ステップ」に、もしマイナスの値を指定したら、どうなると思いますか?

そう、取り出す方向が「逆」になるんです!

my_str = "PYTHON"
reversed_str = my_str[::-1] # ステップに -1 を指定

print(reversed_str)

実行結果:

NOHTYP

[::-1] という、まるで暗号のような書き方。

これは「最初から最後まで(::)、ステップ -1 で(逆順に1個ずつ)」という意味になり、文字列やリストをあっという間にひっくり返す、Python界隈では超有名な「呪文」なんです!


まとめと今後の学習指針

今回も、Pythonの面白い特徴を3つご紹介しました。

  1. f-string: f"{variable=}" でデバッグが超はかどる!
  2. * アンパッキング: *rest で「残り全部」をスマートに受け取れる!
  3. スライス [::-1]: ステップ -1 で、リストや文字列を逆順にする呪文!

f-stringはすぐにでも使える実用的な機能ですし、*[::-1] は、他の人が書いた「Pythonic」なコードを読むときに必ずと言っていいほど出くわす表現です。

「こんな書き方があるんだ」と知っておくだけで、コードの読み書きの効率が格段に上がります。

Pythonは、いかにプログラマーが「楽をできるか」「直感的に書けるか」を突き詰めた結果、こうしたユニークな文法をたくさん持っています。

これからも、新しい文法や関数に出会ったら、「なぜこんなものが用意されているんだろう?」とその背景にある「思想」を想像してみてください。

きっと、Pythonの設計者の「優しさ」や「遊び心」が見えてきて、ますますこの言語が好きになるはずですよ!

セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。