TL;DR
さらに詳しく
__new__はインスタンス作成にまつわる挙動を書くのに便利。typeを戻り値として設定する必要があり、その戻り値が新しいインスタンスのtypeとなる
__init__はインスタンスの変数を定義するのに便利(self.hogeのようなやつ)。戻り値は設定できないので、すでに作成されたインスタンスの変数を設定するのに使われる
__new__と__init__の違いを理解するにはクラス、インスタンスについてよくわかっている必要があるので、まずは初歩的なところから説明していく↓
クラス、インスタンスとは
クラスとはクッキーの型、インスタンスは型によって作られたクッキー自身という例えがある。
似たような機能を持つクッキーを複数作りたいとき、クッキーの型があると便利。
実際にクッキーを作ってみる:
class Cookies(): pass # なにもしない my_cookie = Cookies() your_cookie = Cookies() type(my_cookie) # => __main__.Cookies
my_cookieとyour_cookieという2つのインスタンスが作れた。
メソッドとは
クラスが持っている関数 (= defで始まるやつ) のこと
これによりクッキーに機能をもたせることが出来る
class Cookies(): price = 100 def add_chocolate(self): self.sozai = "ミルクチョコレート" my_cookie = Cookies() your_cookie = Cookies() print(my_cookie.sozai) # sozaiはまだ設定してないのでエラー my_cookie.add_chocolate() print(my_cookie.sozai) # ミルクチョコレート my_cookie.sozai = 'ミント' print(my_cookie.sozai) # => 'ミント' print(my_cookie.price) # => 100 my_cookie.price = 200 print(my_cookie.price) # => 200
↑の例では add_chocolateというメソッドを実行させることで、self, つまりmy_cookieにsozaiを足すことが出来る。ちなみに、selfはクッキー自身のことである
ここで、足したいチョコレートはミルクチョコレート以外にもあるかもしれないので、add_chocolateを改造して便利にしたい
class Cookies(): price = 100 def add_chocolate(self, choco_kind='ミルクチョコレート'): self.sozai = choco_kind my_cookie = Cookies() my_cookie.add_chocolate('いちごチョコレート') print(my_cookie.sozai) # => 'いちごチョコレート'
と、このように好きな素材をセットすることも出来る。
コンストラクターとは (__init__と__new__)
新しくクッキー (インスタンス) を作った時に、常に中にチョコレートを入れたいとき、いちいちadd_chocolate()を実行するのは面倒だし忘れそう。そんなときにコンストラクターを使う
class Cookies(): def __init__(self, choco_kind='ミルクチョコレート'): self.sozai = choco_kind my_cookie = Cookies() print(my_cookie.sozai) # => 'ミルクチョコレート' your_cookie = Cookies(choco_kind='ビターチョコレート') print(your_cookie.sozai) # => 'ビターチョコレート'
ここで、インスタンスを作る前に、今までに作られたクッキーの数をクッキーの型にメモしていき、「クッキーがすでに2つ以上あったら新しいクッキーを作らないようにする」という機能を追加したいとする。
そこで__new__の出番だ。
class Cookies(): max_cookie = 2 current_cookie = 0 def __new__(cls): if cls.current_cookie >= cls.max_cookie: print('すでに2つクッキーがあるので新しいクッキーは作りません') return None cls.current_cookie += 1 return super().__new__(cls) # いつも通り普通にクッキーを作ってねという命令 my_cookie = Cookies() your_cookie = Cookies() nobita_cookie = Cookies() # すでに2つクッキーがあるので...と出る print(nobita_cookie) # => None
これにより、新しいクッキーが作られるのを阻止できた。