質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

2317閲覧

'__new__()'、'__init__()'の使い分け、メタクラスの存在意義について

退会済みユーザー

退会済みユーザー

総合スコア0

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

2クリップ

投稿2020/01/24 14:48

編集2020/01/24 23:41

インスタンスアロケータ - 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ページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答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

katsuko

総合スコア3471

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/01/26 13:37

ご回答ありがとうございます。また、サンプルコードや実例混じえてのご説明、本当に分かりやすく参考になります。ただし、1度読んだだけではぼんやりとわかった気になったレベルだったので、明日、もう一度、読み込んでから解決済みにしたいと思います。 今しばらくOPENのままお待ちいただければ幸いです。。
guest

0

__new__ はインスタンスを生成する前段階の処理を書けます。
例えば、唯一無二のインスタンスを生成して、そのインスタンスをみんなで共有したい場合があります。デザインパターンで「シングルトンパターン」という名前が付いている方法です。
それを実現するのに、そのクラスのインスタンスを一度も生成してなければ生成してキャッシュしておき、インスタンス生成済であればキャッシュしてあるインスタンスを返す、という処理を __new__ に書きます。

メタクラスは、インスタンス生成時の処理を書けます。
必ず必要なメンバーやメソッドが定義されていなければ例外を発生させたり、
自動的にメンバーやメソッドを作り出して追加するようなこともできます。

__init__ はインスタンス生成後の初期化処理です。
インスタンス生成しなければ呼び出しません。
インスタンス生成すれば呼び出します。

投稿2020/01/24 21:16

shiracamus

総合スコア5406

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/01/24 23:47

ご回答ありがとうございます。非常にわかりやすく、助かります。 シングルトンの例で言えば、インスタンスが生成される前にインスタンスの存在有無をチェックし、インスタンスが2つ存在しないようにしているということですね。 メタクラスの例については、実装のチェックを行っているようなイメージでしょうか? もしこの認識に相違なければ、実装に誤りがあった場合、それを単体テストで見つけるのか、メタクラスで見つけるのかの違いのように感じるのですがいかがでしょうか。
shiracamus

2020/01/25 00:20 編集

テストにも使える、ですかね。 メタクラスはクラスを定義するためのクラスなので、いろいろなことができます。 チェックだけじゃなく、機能拡張したり、他のクラスと連携させたり。 ネット検索するといろいろな記事が見つかります。 https://www.google.com/search?q=python+metaclass
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問