Ccmmutty logo
Commutty IT
5 min read

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

https://cdn.magicode.io/media/notebox/blob_LeyrrlS

はじめに

今回はPythonの「特殊メソッド」について解説していきます。
Pythonの実務でよく他の人が書いたコードを読むことがあります。
その際結構な頻度で「特殊メソッド」が使われています。
慣れていないと何をしているのかわからず時間だけが過ぎていく可能性があります。
それを防ぐためにこの記事で「特殊メソッド」に慣れて、他の人が書いたコードをスラスラ読めるようになりましょう!
Pythonの基礎はあらかたマスターした!
Pythonのクラスの知識を深めたい。
Pythonの特殊メソッドってなんだろう?
他の人のコードを読めるようになりたい。
このような人に役に立てれば幸いです!
前置きは早々に本題に入っていきましょう。
この記事はPythonの「クラス」の理解をしておいた方が読みやすいです。「クラス」の理解が怪しいかたは以下を参考に学習してみてください。

本題に入る前に

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__の時点でタプルの中身が変わっていますよね?
そのため実質タプルの中身を変更できたということです。
少し難しいですがこのように使用するので頭の片隅に入れておきましょう。

参考

続き

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

Discussion

コメントにはログインが必要です。