投稿日: | 最終更新日:
Pythonのメタクラス
Pythonのメタクラスの基本的な使い方を調べてみます。
メタクラスとは?
メタクラスとは、インスタンス(実体)がクラス(設計図)となるクラス(設計図)のことです。例えばPythonでは、クラスオブジェクトの型がメタクラスにあたります。
クラスオブジェクトとは、クラス定義を抜けると生成されるオブジェクトです。
代表的なメタクラス
Pythonの組み込み(ビルトイン)クラスである「type」は、メタクラスです。
typeビルトイン関数は、型を調べるほかにクラスオブジェクトのインスタンス作成(コンストラクタ)としても利用されます。
例)typeは、以下のように動作確認できます。
>>> class A(object): ... test = 1 ... >>> A = type('A', (object,), {'test':1}) >>> >>> a = A() >>> a.test 1
Pythonにおけるtypeを簡単にまとめると、以下のようになります。
- class文はtype呼び出しのシンタックスシュガー(読みやすくした構文)
- typeはデフォルトのメタクラス
typeはどこ?
そもそもPythonのクラスは、全てオブジェクトです。インスタンスはもちろん、インスタンスのもとになるクラスもオブジェクトです。全てのオブジェクトは必ず「型」を持ちます。
そして、 クラスはtypeのインスタンスです 。
例)文字列’abc’の型は以下のようになります。
>>> type('abc') <type 'str'>
str型です。
この例では、「str」がクラスオブジェクトとなります。では、クラスオブジェクト「str」の型はどうなるか?以下のようにして調べます。
>>> type(str) <type 'type'>
type型でした。
目に見えなくてもtypeが存在します。このように、クラスオブジェクトの型の「type」をメタクラスと呼びます。
メタクラスを何に使うか?
クラスに同じメソッドを持たせたい場合があります。サブクラスという方法で可能ですが、まったく無関係なクラスをサブクラスとして派生させるわけにはいきません。このような場合、Pythonでは「メタクラス」という仕組みを利用します。
環境
Python | 3.6 |
---|
メタクラスの基本的な使い方
メタクラスの定義方法は、通常のクラス定義と変わりありません。ただし、特定の引数を用意する必要があります。
たとえば、次のような形です。
例)以下のようにMyMetaClassというメタクラスを定義しています。
>>> def extra(self): >>> print("追加されたメソッド") ... >>> class MyMetaClass(type): >>> def __init__(cls, classname, superclases, attributes): >>> cls.extra = extra
関数extraの中にメタクラスMyMetaClassが存在します。
__init__メソッド
__init__メソッドには、以下の引数が渡されます。
第一引数 | クラスオブジェクト:cls |
---|---|
第二引数 | クラス名:classname |
第三引数 | 親クラス:superclases |
第四引数 | 属性:attributes |
メタクラスを使う
このメタクラスを使うには、次のようにします。
>>> class MyClass(metaclass=MyMetaClass): >>> pass ... >>> myclass = MyClass() >>> myclass.extra() 追加されたメソッド
解説
メタクラスを指定するには、クラス定義に「(metaclass=[メタクラス名])」を記述します。この例ではMyClassクラス自体は空であり、なんのメソッドも持っていません。
class MyClass(metaclass=MyMetaClass): pass
メタクラスによりextraメソッドが追加されているのが確認できます。
myclass = MyClass() myclass.extra() 追加されたメソッド
メタクラスでシングルトンを実装する
シングルトンはデザインパターンの一種です。クラスが唯一のオブジェクトしか持たないことを保証するものです。(※つまり、クラスのインスタンスをひとつに制限します。)
これは、複数のインスタンスを持つ必要がないクラスを作るときに使います。これをメタクラスで実現します。
>>> class Singleton(type): ... def __init__(cls, classname, superclases, attributes): ... cls.instance = None ... def __call__(cls, *args, **kwargs): ... if cls.instance is None: ... cls.instance = super(Singleton, cls).__call__(*args, **kwargs) ... return cls.instance ... >>> class SingletonClass(metaclass=Singleton): ... pass
メタクラスを使ったクラス「SingletonClass」からインスタンスを作ります。
>>> ins1 = SingletonClass() >>> ins2 = SingletonClass()
同じインスタンスか判定します。
>>> if ins1 == ins2: ... print("同じインスタンスです") ... else: ... print("異なるインスタンスです") ... 同じインスタンスです
インスタンスのidを表示してみます。
>>> print(id(ins1)) 140534320890824 >>> print(id(ins2)) 140534320890824
解説
... def __call__(cls, *args, **kwargs): ... if cls.instance is None: ... cls.instance = super(Singleton, cls).__call__(*args, **kwargs) ... return cls.instance
クラスがインスタンス化されるときには、メタクラスの「__call__」メソッドが呼ばれます。ここでインスタンス生成に干渉します。つまり、まだインスタンスが生成されていなければ新しく作成し、すでに生成されていれば既存のインスタンスを返します。
... cls.instance = super(Singleton, cls).__call__(*args, **kwargs)
super関数を使って、親クラス(ここではtype)の「__call__」メソッドを呼び出します。(※この呼び出しは、通常のインスタンス生成で行われる処理と同等です。)
if ins1 == ins2: print("同じインスタンスです") else: print("異なるインスタンスです") 同じインスタンスです print(id(ins1)) 140534320890824 print(id(ins2)) 140534320890824
実際にSingletonClassを2つ作成してみると、どちらも同じインスタンスであることが確認できます。
「class Meta」はメタクラスではない
WEBフレームワークのDjangoでは、以下のような記述をする時があります。
class Question(models.Model): class Meta: verbose_name = '質問' verbose_name_plural = '質問の複数形'
まぎらわしいですが、これはメタクラスではなくメタデータです。
モデルのメタデータ
Djangoでは、モデルのメタデータを「Meta」という名前のクラスでモデルの中に作ります。モデルのメタデータとは、「フィールド定義じゃない何か」です。並べる時の順番指定(ordering)や、DBのテーブル名や(db_table)、表示名の単数形と複数形(verbose_name と verbose_name_plural)などを指定します。つまり、モデルをデコレーションします。(※Metaは必須ではありません。)
まとめ
- メタクラスとは、インスタンスがクラスとなるクラスのことです。
- メタクラスは、関係のない別々のクラスに同じメソッドを持たせたい時に使います。
- メタクラスを定義するには、特定の引数を用意する必要があります。
- Pythonでは、特に指定がなければtypeがメタクラスです。
- 新しくメタクラスを追加する場合、typeクラスのサブクラスにする必要があります。
- Python 114
- 制作 54
- RaspberryPi 41
- Django 40
- WordPress 40
- Linux 27
- VPS 22
- JavaScript 21
- PHP 20
- HTML・CSS 19
- AWS 16
- 仮想環境 15
- レスポンシブデザイン 13
- マイコン 11
- WEB全般 11
- 動画製作 9
- Webサービス 8
- 統合開発環境 8
- 機械学習 8
- PyCharm 7
- jQuery 7
- AfterEffects 7
- 起業・設立 7
- Django REST framework 6
- C# 6
- デザイン 6
- SEO 6
- pydata 6
- Visual Studio 5
- 数学 5
- 携帯サイト 5
- heroku 5
- Mac 5
- illustrator 5
- node.js 5
- Anaconda 5
- Nginx 4
- Jupyter Notebook 4
- インフラ 4
- Google Colaboratory 4
- symfony 4
- Webスクレイピング 3
- photoshop 3
- Go言語 3
- PC 3
- ツール 3
- Docker 3
- facebook 3
- 作業効率化 3
- データベース 3
- Cloud9 3
- コマンド 2
- micro:bit 2
- Kali Linux 2
- Webサーバー 2
- MariaDB 2
- ドローン 2
- コンテナ 2
- DaVinci Resolve 2
- ネットワーク 2
- Java 2
- movie 2
- PCDJ 2
- 音楽 2
- XSERVER 2
- Ansible 1
- Vue.js 1
- JSON 1
- Bootstrap 1
- バージョン管理システム 1
- SSL 1
- S3 1
- ムームードメイン 1
- ネットワーク 1
- アニメーション 1
- D3.js 1
- Rhino 1
- アニメ 1
- git 1
- windows 1
- アクセス解析 1
- スマートフォン 1
- アフィリエイトノウハウ 1
- 知識 1
- TypeScript 1
- 役立つ本・書籍 1
- データサイエンス 1
- ESP32 1
- AI 1
- ownCloud 1
- API 1