🐍

[Python基礎]Pythonの特殊メソッドを理解してコードを読めるようになろう!

2022/05/03に公開

はじめに

今回はPythonの「特殊メソッド」について解説していきます。

Pythonの実務でよく他の人が書いたコードを読むことがあります。

その際結構な頻度で「特殊メソッド」が使われています。

慣れていないと何をしているのかわからず時間だけが過ぎていく可能性があります。

それを防ぐためにこの記事で「特殊メソッド」に慣れて、他の人が書いたコードをスラスラ読めるようになりましょう!

Pythonの基礎はあらかたマスターした!

Pythonのクラスの知識を深めたい。

Pythonの特殊メソッドってなんだろう?

他の人のコードを読めるようになりたい。

このような人に役に立てれば幸いです!

前置きは早々に本題に入っていきましょう。

https://chaldene.net/python-book

本題に入る前に

Pythonの「特殊メソッド」はめちゃくちゃたくさんあります。

その中でもよく使われるものを中心に紹介していきます。

もし今回紹介する以外の「特殊メソッド」を使いたい方は、公式ドキュメントを参考にしたりググってみてください。

また、この記事では丁寧な解説を心がけているので、同じようなコードが繰り返されます。

しつこく感じる方もいるかもしれませんが、初学者を対象に書いているのでご了承ください。

new

概要

__new__は「インスタンスオブジェクト」が生成される前に呼び出されます。

インスタンスオブジェクト」とは、クラスを呼び出すことだと思ってもらえれば大丈夫です。

selfオブジェクトをインスタンス化し、第1引数clsにクラスオブジェクトが代入されます。

変更できないオブジェクトを変更したい」場面で使用されます。

では早速みていきましょう。

class Cardene:
    def __new__(cls):
        print("__new__")
        print(f"cls: {cls}")
        return super().__new__(cls)
    
    def __init__(self):
        print("__init__")
        print(f"self: {self}")
        
cardene = Cardene()

2行目で定義して、引数にclsを取っています。

出力を確認しましょう。

__new__
cls: <class '__main__.Cardene'>
__init__
self: <__main__.Cardene object at 0x10944cfd0>

__new__の方はクラス自体で、次章で解説する__init__はクラスオブジェクトになっているのが確認できますね。

インスタンス生成しない

ちなみにインスタンスを生成しないと__init__が呼ばれません。

確認してみましょう。

class Cardene:
    def __new__(cls):
        print("__new__")
        print(f"cls: {cls}")
        # return super().__new__(cls)
    
    def __init__(self):
        print("__init__")
        print(f"self: {self}")
        
cardene = Cardene()

5行目の部分をコメントアウトしました。

__new__
cls: <class '__main__.Cardene'>

先ほど呼ばれていた__init__が呼ばれていませんね。

このように__new__でインスタンスを生成していないと__init__が呼ばれないので注意しましょう。

__new__を定義しない場合は自動でインスタンスが生成されます。)

イミュータブルオブジェクトを変更

イミュータブル」とは、「変更できない」という意味です。

タプルなど一度定義した後に変更できないオブジェクトのことを指します。

通常クラスに渡された「イミュータブル」なオブジェクトは変更することができません。

まずはタプルから確認してみましょう。

numbers = (1, 2, 3)

print(numbers)
# (1, 2, 3)

ではこのタプルに変更を加えていきましょう。

numbers = (1, 2, 3)

numbers[1] = 4

print(numbers)
# TypeError: 'tuple' object does not support item assignment

想定通りエラーになりましたね。

では__init__ないで変更を加えてみましょう。

class Cardene:
    def __init__(self, num_tuple):
        self.num_tuple = num_tuple
        print(num_tuple)
        self.num_tuple[1] = 4
        
cardene = Cardene((1, 2, 3))

5行目で先ほど同様4を代入しようとしています。

TypeError: 'tuple' object does not support item assignment

先ほどと同じエラーが出ましたね。

では__new__を使って解決していきましょう。

class Cardene(tuple):
    def __new__(cls, num_tuple):
        self = tuple.__new__(cls, (
            num_tuple[0], 4, num_tuple[2]
        ))
        print(self)
    
cardene = Cardene((1, 2, 3))

4行目でタプルを再定義しています。

(1, 4, 3)

変更できましたね!

いやいや再定義してるじゃん!それなら別に__init__でもできるじゃん!

と思った方は鋭い!

ただこのような感じだったらどうでしょうか?

class Cardene(tuple):
    def __new__(cls, num_tuple):
        self = tuple.__new__(cls, (
            num_tuple[0], 4, num_tuple[2]
        ))
        print(self)
        
    def __init__(self, num_tuple):
        self.num_tuple = num_tuple
        print(num_tuple)
        
    
cardene = Cardene((1, 2, 3))

先ほど同様__new__を定義して、さらに__init__も付け足してみました。

(1, 4, 3)

しっかり出力できましたね。

何が言いたいかというと、__init__の時点でタプルの中身が変わっていますよね?

そのため実質タプルの中身を変更できたということです。

少し難しいですがこのように使用するので頭の片隅に入れておきましょう。

参考

続き

これより先は以下の記事にまとめています。

https://chaldene.net/python-method

より詳しく特殊メソッドについて学ぶことができるので、興味がある方はぜひ!
(もちろん無料です!)

Discussion