Pythonの「なるほど!」と思えるユニークな機能④

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

皆さんは、Pythonを使っていて不思議に思ったことはありませんか?

  • 1 + 2 は、数字を「足し算」する。
  • "a" + "b" は、文字列を「連結」する。
  • [1, 2] + [3, 4] は、リストを「結合」する。

同じ +(プラス)という記号なのに、相手(型)によって振る舞いがガラッと変わります。

len() 関数もそうですよね。len("abc") も len([1, 2, 3]) も、どちらも正しく長さを返してくれます。

「Pythonが賢いから?」

「+ や len() が、if文でたくさん場合分けしている?」

いいえ、違うんです!

その秘密は、「Dunder(ダンダー)メソッド」と呼ばれる、Pythonの「魔法の杖」にあります。

専門用語解説: Dunder (Double Underscore) Methods

Dunder(ダンダー)とは、Double Underscore、つまり「二重アンダースコア」のことです。

__add__ や __len__ のように、名前が __(二重アンダースコア)で始まって __ で終わる特別なメソッドたちを指します。

実は、Pythonで +len() を使うとき、内部ではこんなことが起きています。

  1. あなたが a + b と書くと…
    • Pythonは a に「ねえ、__add__ っていう魔法の杖(メソッド)持ってる?」と聞きに行きます。
    • a__add__(b) というメソッドを持っていれば、それを実行します。
    • (だから、1 + 2(1).__add__(2) を、"a" + "b"("a").__add__("b") を呼び出しているだけなんです!)
  2. あなたが len(obj) と書くと…
    • Pythonは obj に「__len__ っていう魔法の杖、持ってる?」と聞きに行きます。
    • obj__len__() メソッドを持っていれば、それを実行し、その戻り値を返します。

この仕組みのすごい点は、**「この魔法の杖は、私たちプログラマーも自由に作れる」**という点です!

例えば、「お財布」クラスを作ってみましょう。

class Wallet:
    def __init__(self, owner, amount):
        self.owner = owner
        self.amount = amount

# ゆうせいのお財布と、たけしのお財布
my_wallet = Wallet("ゆうせい", 1000)
t_wallet = Wallet("たけし", 500)

この二つのお財布を + で「合算」しようとしたら、どうなるでしょう?

# new_wallet = my_wallet + t_wallet # 実行するとエラー!
# TypeError: unsupported operand type(s) for +: 'Wallet' and 'Wallet'

Pythonが「Wallet 同士を + する方法(__add__)なんて知らないよ!」と怒ってしまいました。

では、__add__ という「魔法の杖」を Wallet クラスに実装してあげましょう!

class Wallet:
    def __init__(self, owner, amount):
        self.owner = owner
        self.amount = amount
    
    # + 演算子(__add__)の魔法を実装!
    def __add__(self, other):
        # 「other」には + の右側(t_wallet)が入る
        if isinstance(other, Wallet): # 相手もWalletなら
            new_owner = self.owner + "と" + other.owner
            new_amount = self.amount + other.amount
            return Wallet(new_owner, new_amount) # 新しいWalletを返す
        else:
            return NotImplemented # できない、と伝える

    # print()(__str__)の魔法も実装!
    def __str__(self):
        # print() で呼び出されたときの「見た目」
        return f"お財布(持ち主: {self.owner}, 金額: {self.amount}円)"

my_wallet = Wallet("ゆうせい", 1000)
t_wallet = Wallet("たけし", 500)

# __add__ が動く!
new_wallet = my_wallet + t_wallet

# __str__ が動く!
print(new_wallet)

実行結果:

お財布(持ち主: ゆうせいとたけし, 金額: 1500円)

見てください! 私たちが作った Wallet オブジェクトが、まるで組み込みのリストや文字列のように + で合算できるようになりました!

ついでに __str__(print() での表示方法)も実装したので、print() したときの見た目もきれいになりましたね。

__lt__(< 比較)を実装すれば sort() できるようになり、__len__ を実装すれば len() できるようになります。

このように、Pythonの演算子や組み込み関数は、すべてこの「Dunderメソッド」(Pythonデータモデル)という「約束事」の上で動いているのです。


特徴3: 式の中で「代入」しちゃう!? セイウチ演算子 :=

最後は、Python 3.8から導入された、比較的新しい「魔法」です。

見た目が「:(目)」と「=(牙)」で、横倒しの「セイウチ(Walrus)」に似ていることから、「セイウチ演算子」と呼ばれています。

この := が解決するのは、プログラミングで非常によくある、この「ちょっとイラッとする」パターンです。

:= を知らない場合:

ファイルから1行ずつ読み込み、その行が空("")になるまで処理を続けたいとします。

# file は開いているとします
line = file.readline() # (1) 1回目の読み込み
while line: # (2) line に中身があるかチェック
    print(line.strip())
    line = file.readline() # (3) 2回目(以降)の読み込み

file.readline() という「値の取得」が、ループの「前」と「中」の2箇所に重複してしまっています。

これは美しくない(Not Pythonic)ですよね?

セイウチ演算子 := を使った場合:

while (line := file.readline()): # (1) 読み込み、代入、チェックを同時に!
    print(line.strip())

たったこれだけです!

専門用語解説: セイウチ演算子 := (代入式)

=(代入文)は、「a = 10」のように、それ自体が「文」としてしか使えませんでした。

if a = 10: なんて書けませんよね?

:=(代入式)は、「式」の中で代入を行う ことができます。

while (line := file.readline()):

これは、Pythonにとって、こんな風に見えます。

  1. まず、() の中の line := file.readline() を実行するぞ。
  2. file.readline() を実行し、その結果(例えば "hello\n")を line 変数に代入する
  3. := 演算子自体の「値」は、代入された値("hello\n")になる。
  4. 結果、while "hello\n": と同じ意味になる。
  5. "hello\n" は Truthy なので、ループが実行される。(line には "hello\n" が入ったまま!)
  6. file.readline() が空文字列 "" を返すと、while (line := ""): となる。
  7. "" は Falsy なので、while ループが終了する。

if文 でも大活躍します。

# if で計算結果を変数に保存しつつ使う
if (length := len(my_list)) > 10:
    print(f"このリストは長すぎます: {length} 個")

「値を取得し、その値をチェックし、もしOKならその値を使い続けたい」という、よくある処理を、重複なく1行でエレガントに書くための、現代のPythonicな道具なんです!


まとめと今後の学習指針

いかがでしたか?

  1. Dunderメソッド (__add__ など): Pythonの演算子や関数の「正体」。これを実装することで、自作のオブジェクトがPythonに「ネイティブ」に組み込まれたかのように振る舞える!
  2. セイウチ演算子 (:=): 「代入」と「チェック」を同時に行い、ループなどの冗長なコードをスッキリさせる!

Dunderメソッドは、Pythonの「オブジェクト指向」の根幹をなす、非常に重要な概念(Pythonデータモデル)です。

セイウチ演算子は、そのPythonの哲学(可読性や効率性)を、さらに推し進めるための新しい道具です。

ここまで学んできたあなたは、もはや「Pythonの文法を知っている」レベルではなく、「Pythonがどういう思想で設計されているか」を理解し始めた、真のPythonistaと言えるでしょう。

この先には、@classmethod や @staticmethod といったデコレータの仲間たち、そしてPythonの「神の領域」とも呼ばれる「メタクラス」の世界が待っています。

ぜひ、その探究心を燃やし続けてください!

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

投稿者プロフィール

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