
インスタンスアロケータ - Python学習講座 https://www.python.ambitious-engineer.com/archives/310
上記サイトで学んでいますが、'new()'と'init()'の使い分けがいまいち理解できません。
どちらもクラスからインスタンスを生成する際には必ず呼ばれているとの認識でしたが、以下のページを見ると、'init()'は呼ばれない場合もあるとのことです。
__new__と__init__とメタクラスと - Qiita https://qiita.com/FGtatsuro/items/49f907a809e53b874b18
であれば、【質問①】なぜ多くの教本等ではインスタンスを生成する際には'init()'を使うのでしょうか。必ず呼ばれる'new()'を用いれば良いのではと思ってしまいます。
また、【質問②】上記Qiitaのページにあるメタクラスとは何者なのでしょうか。いくつかページを巡回してみましたが、存在意義がまったく理解できませんでした。もし、「こういった際に使うものだよ、実業務のなかでこう使ってるよ」というものがあればご教示いただければ幸いです。
素人質問で恐縮ですが、何卒、よろしくお願いいたします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答2件
0
ベストアンサー
【質問①】なぜ多くの教本等ではインスタンスを生成する際には'init'を使うのでしょうか。必ず呼ばれる'new()'を用いれば良いのではと思ってしまいます。
そもそも、__new__
が必ず呼ばれる、という事が間違っています。
参考にされているサイトでは、「super().__init__
を呼ばなければ」という条件を出していますが、そうであればsuper().__new__
を呼び出さない事もできます。
python
1class Hoge: 2 def __new__(cls, *args, **kwargs): 3 print('Hoge.new') 4 return super().__new__(cls, *args, **kwargs) 5 6class Piyo(Hoge): 7 def __new__(cls, *args, **kwargs): 8 print('Piyo.new') 9 return object.__new__(cls, *args, **kwargs)
「__new__
」は、インスタンスを生成するメソッド。「__init__
」は、インスタンスを初期化するメソッドです。
ですので、初期化を行うコードは「__init__
」に書くのが自然ですし、皆そのように従っているだけかと思います。
【質問②】上記Qiitaのページにあるメタクラスとは何者なのでしょうか。
メタクラスに関して、自分も最近真面目に調べた程度の浅い知識なのですが。
その時に参考にしたのが、以下のサイトです。
一言で言えば、「クラスのクラス」です。と言ってもさっぱりわかりませんが。
Pythonにおいて、モジュールもメソッドも全てobjectです。それはクラスに関しても例外ではありません。
そして、全てのobjectは型オブジェクトを持ちます。
普通にクラスを定義した場合、型オブジェクトはtype
になります。
>>> class Hoge: ... pass ... >>> type(Hoge) <class 'type'> >>>
この型オブジェクトを、自分で定義した物がメタクラスです。
>>> class Metaclass(type): ... pass ... >>> class Hoge(metaclass=Metaclass): ... pass ... >>> type(Hoge) <class '__main__.Metaclass'> >>>
では、どのように使うかと言えば、クラス定義をした際にそのクラスインスタンスに対して処理する用途などに使います。
そういった意味ではデコレータと似ていると思いますが、デコレータと違う点は。
- 「
@decorator
」というような記述をしなくてもよい。 - クラス、もしくはその派生クラスにしか適用できない。
- デコレータは生成されたクラスインスタンスに対して処理するのに対し、メタクラスはクラスインスタンスを生成する前にも処理を行うことができる。
です。
例えば、PyQtの場合、自分のクラスにシグナルを追加する場合、クラス属性にシグナルを追加します。
python
1from PyQt5 import QtCore 2class MyObject(QtCore.QObject): 3 mysignal = QtCore.pyqtSignal()
または、SQLAlchemyのテーブル定義では、クラス属性にテーブル名なりカラム定義なりを追加します。
python
1from sqlalchemy import Column, String 2from sqlalchemy.ext.declarative import declarative_base 3Base = declarative_base() 4class MyTable(Base): 5 __tablename__ = 'mytable' 6 name = Column(String, primary_key) 7Base.metadata.create_all(engine)
このように、クラス属性を定義して振る舞いを指定する事は何らかのモジュールを使っている上で多々ある事ですが、大抵の場合属性を定義するだけではなく、何らかの処理が必要になるはずです。
python
1class Parent: 2 subclasses = {} 3 4 @staticmethod 5 def init_class(cls): 6 Parent.subclass[cls.__clsname__] = cls 7 8class Hoge(Parent): 9 __clsname__ = 'hoge' 10Parent.init_cls(Hoge)
上記のようにParent.init_class
を呼び出せば処理ができますが、実際にはそのような処理は記述しません。
そこで、メタクラスを使います。
python
1class Metaclass(type): 2 subclasses = {} 3 def __init__(cls, name, bases, attrs): 4 super().__init__(name, bases, attrs) 5 Metaclass.subclasses[cls.__clsname__] = cls 6 7class Parent(metaclass=Metaclass): 8 __clsname__ = 'parent' 9 pass 10 11class Hoge(Parent): 12 __clsname__ = 'hoge' 13 14print(Metaclass.subclasses)
このようにしておけば、Parent
を継承するクラスは__clsname__
を定義しておくだけでOKというようになります。
そもそもメタクラスのようなメタプログラミング技法は、ライブラリ作成者がディベロッパに対して余計な手間を省くために使用されることが多いですから、一般的にはあまり使用しないと思います。
投稿2020/01/25 10:09
総合スコア3578
0
__new__
はインスタンスを生成する前段階の処理を書けます。
例えば、唯一無二のインスタンスを生成して、そのインスタンスをみんなで共有したい場合があります。デザインパターンで「シングルトンパターン」という名前が付いている方法です。
それを実現するのに、そのクラスのインスタンスを一度も生成してなければ生成してキャッシュしておき、インスタンス生成済であればキャッシュしてあるインスタンスを返す、という処理を __new__
に書きます。
メタクラスは、インスタンス生成時の処理を書けます。
必ず必要なメンバーやメソッドが定義されていなければ例外を発生させたり、
自動的にメンバーやメソッドを作り出して追加するようなこともできます。
__init__
はインスタンス生成後の初期化処理です。
インスタンス生成しなければ呼び出しません。
インスタンス生成すれば呼び出します。
投稿2020/01/24 21:16
総合スコア5406
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。


あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2020/01/26 13:37