PythonのClassの生成に関してまとめてみた

published: 2021/6/29 update: 2021/6/29

Table of Contents

TL;DR

Pythonのクラス、色々ありすぎて難しいのでまとめます。まずはClassの生成についてです。

Classの生成

  • __new__メソッドが呼ばれたあと__init__メソッドが呼ばれる。
  • __new__メソッド内ではクラス変数の定義などが行われる。__init__メソッド内では、インスタンス変数が定義できる。
  • クラス変数は、クラスから作成されたインスタンス全てから利用できる変数で、インスタンス変数はそれぞれのインスタンスからのみ利用できる変数。
  • クラス変数はインスタンスが生成されていなくても使えて、クラス変数を利用するメソッドにはは@classmethodのデコレータを付けて明示する。
  • 生成されたインスタンスはself、クラスそのものはclsと慣用的に命名される。

__new____init__の挙動確認

# -*- coding: utf-8 -*-
class Name:
    class_name = None # クラス変数

    def __new__(cls, name):
        print("new:", str(id(cls)))
        return super().__new__(cls)

    def __init__(self, name):
        print("==init==")
        print("id:", str(id(self)), "name:", name)
        self.name = name # インスタンス変数

    @classmethod
    def set_class_name(cls, class_name):
        cls.class_name = class_name

    @classmethod
    def print_class_name(cls):
        print(cls.class_name)

    @staticmethod
    def print_hi():
        print("hi!")

のようにクラスを定義します。少し話はずれていますが、@staticmethodはクラス変数にも生成されたインスタンス(cls, selfを引数に取らない)メソッドのデコレータで、このメソッドもインスタンスが生成されてなくても使えます。

以下の様に、@classmethod@staticmethodで定義されている部分については、インスタンスを生成しなくても使えていることがわかります。

Name.print_class_name()
Name.set_class_name("A")
Name.print_class_name()
Name.print_hi()

# None
# A
# hi!

次にインスタンスの生成過程を見てみます。

john = Name("John")
mike = Name("mike")

# new: 25652888
# ==init==
# id: 140347266309760 name: John
# new: 25652888
# ==init==
# id: 140347266309816 name: mike

インスタンスが生成された後のIDを見ると、__new__で生成されているIDは同じでクラス自身が生成されています。また、__init__で生成されているIDは異なっていて、違うインスタンスが生成されていることがわかります。

さらに、クラス変数を変更した場合の挙動を確認します。

print("classname:", john.class_name, "name:", john.name)
print("classname:", mike.class_name, "name:", mike.name)
print("-" * 10)
mike.set_class_name("B")
print("classname:", john.class_name, "name:", john.name)
print("classname:", mike.class_name, "name:", mike.name)

# classname: A name: John
# classname: A name: mike
# ----------
# classname: B name: John
# classname: B name: mike

どちらかの側でクラス変数を変更すると、両方のインスタンスでクラス変数が変更されていることがわかります。

__new__は何に使うのか

__new__の使用例としては、

  1. そのクラスが何回呼び出されたのかを記録する
  2. tupleなどのimmutableなオブジェクトの初期化
  3. メタクラスを利用してクラスを切り替える

などが挙げられます。公式的には、2,3が想定用途っぽいです (参考: 3. データモデル)。

__new__() の主な目的は、変更不能な型 (int, str, tuple など) のサブクラスでインスタンス生成をカスタマイズすることにあります。また、クラス生成をカスタマイズするために、カスタムのメタクラスでよくオーバーライドされます。

記事に間違い等ありましたら、お気軽に以下までご連絡ください

E-mail: illumination.k.27|gmail.com ("|" replaced to "@")

Twitter: @illuminationK

当HPを応援してくれる方は下のリンクからお布施をいただけると非常に励みになります。

ofuse

Other Articles

Site Map

Table of Contents

    TL;DR

    Classの生成

      __new__

    __new__


当HPを応援してくれる方は下のリンクからお布施をいただけると非常に励みになります。

ofuse
Privacy Policy

Copyright © illumination-k 2020-2021.