Pythonの__build_class__は、クラス定義の裏側で動作する内部関数です。通常は直接使用しませんが、メタプログラミングやPythonの内部動作を理解する上で重要な概念です。
クラス生成の仕組み
| 要素 | 役割 | 例 |
|---|---|---|
class文 | クラス定義の構文 | class MyClass: |
__build_class__ | 実際のクラス生成 | 内部で自動呼び出し |
| メタクラス | クラスのクラス | type, カスタムメタクラス |
__new__ | インスタンス生成 | オブジェクト作成 |
基本概念
classキーワードの裏側
# 通常のクラス定義
class MyClass:
def hello(self):
return "Hello, World!"
# 上記は内部的に以下のように処理される
# __build_class__(class_body_function, 'MyClass')
クラス生成の流れ
import dis
# クラス定義のバイトコードを確認
def example():
class Sample:
pass
dis.dis(example)
# 出力に LOAD_BUILD_CLASS が含まれる
# これが __build_class__ の呼び出しを示す
__build_class__のシグネチャ
__build_class__(func, name, *bases, metaclass=None, **kwargs)
| パラメータ | 説明 |
|---|---|
func | クラス本体を定義する関数(名前空間を作成) |
name | クラス名(文字列) |
*bases | 基底クラス(継承元) |
metaclass | 使用するメタクラス |
**kwargs | メタクラスに渡す追加引数 |
基本的な使用例
直接呼び出し
# __build_class__を直接使用してクラスを作成
def class_body(ns):
"""クラス本体を定義する関数"""
ns['value'] = 42
def get_value(self):
return self.value
ns['get_value'] = get_value
# builtins から __build_class__ を取得
import builtins
# クラスを動的に生成
MyClass = builtins.__build_class__(
lambda: exec("value = 42\ndef get_value(self): return self.value"),
'MyClass'
)
# より正確な方法
def make_class():
def class_body():
value = 42
def get_value(self):
return self.value
return class_body
# 実際の使用例(type()を使う方が一般的)
MyClass = type('MyClass', (), {
'value': 42,
'get_value': lambda self: self.value
})
obj = MyClass()
print(obj.get_value()) # 42
type()との比較
# type()を使った動的クラス生成(推奨)
def create_class_with_type():
def greet(self):
return f"Hello, {self.name}!"
# type(name, bases, namespace)
Person = type('Person', (), {
'name': 'Unknown',
'greet': greet
})
return Person
Person = create_class_with_type()
p = Person()
p.name = 'Alice'
print(p.greet()) # Hello, Alice!
# 継承も可能
Employee = type('Employee', (Person,), {
'employee_id': None
})
メタクラスとの関係
メタクラスの基本
class MetaLogger(type):
"""クラス生成時にログを出力するメタクラス"""
def __new__(mcs, name, bases, namespace):
print(f"Creating class: {name}")
print(f"Bases: {bases}")
print(f"Namespace keys: {list(namespace.keys())}")
# 親クラス(type)の__new__を呼び出してクラスを生成
cls = super().__new__(mcs, name, bases, namespace)
print(f"Class created: {cls}")
return cls
# メタクラスを使用
class MyClass(metaclass=MetaLogger):
value = 100
def get_value(self):
return self.value
# 出力:
# Creating class: MyClass
# Bases: ()
# Namespace keys: ['__module__', '__qualname__', 'value', 'get_value']
# Class created: <class '__main__.MyClass'>
__build_class__とメタクラスの連携
class ValidationMeta(type):
"""属性を検証するメタクラス"""
def __new__(mcs, name, bases, namespace, **kwargs):
# 必須属性のチェック
required = kwargs.get('required', [])
for attr in required:
if attr not in namespace:
raise TypeError(f"Class {name} must define '{attr}'")
return super().__new__(mcs, name, bases, namespace)
# 使用例
class BaseModel(metaclass=ValidationMeta, required=['validate']):
def validate(self):
return True
# 必須メソッドがないとエラー
# class InvalidModel(metaclass=ValidationMeta, required=['process']):
# pass # TypeError: Class InvalidModel must define 'process'
実践的な応用例
クラス登録システム
class Registry(type):
"""作成されたクラスを自動登録するメタクラス"""
_registry = {}
def __new__(mcs, name, bases, namespace):
cls = super().__new__(mcs, name, bases, namespace)
# 基底クラス以外を登録
if bases:
mcs._registry[name] = cls
return cls
@classmethod
def get_class(mcs, name):
return mcs._registry.get(name)
@classmethod
def all_classes(mcs):
return dict(mcs._registry)
class Plugin(metaclass=Registry):
"""プラグインの基底クラス"""
pass
class ImagePlugin(Plugin):
def process(self):
return "Processing image"
class AudioPlugin(Plugin):
def process(self):
return "Processing audio"
# 登録されたクラスを確認
print(Registry.all_classes())
# {'ImagePlugin': <class 'ImagePlugin'>, 'AudioPlugin': <class 'AudioPlugin'>}
# 名前からクラスを取得
ImageClass = Registry.get_class('ImagePlugin')
plugin = ImageClass()
print(plugin.process()) # Processing image
属性の自動変換
class AutoPropertyMeta(type):
"""アンダースコアで始まる属性を自動的にプロパティに変換"""
def __new__(mcs, name, bases, namespace):
new_namespace = dict(namespace)
for attr_name, value in namespace.items():
if attr_name.startswith('_') and not attr_name.startswith('__'):
# プロパティ名(アンダースコアを除去)
prop_name = attr_name[1:]
# ゲッター
def make_getter(attr):
return lambda self: getattr(self, attr)
# セッター
def make_setter(attr):
return lambda self, value: setattr(self, attr, value)
new_namespace[prop_name] = property(
make_getter(attr_name),
make_setter(attr_name)
)
return super().__new__(mcs, name, bases, new_namespace)
class Person(metaclass=AutoPropertyMeta):
def __init__(self):
self._name = "Unknown"
self._age = 0
p = Person()
p.name = "Alice" # _nameへのアクセス
print(p.name) # Alice
シングルトンパターン
class SingletonMeta(type):
"""シングルトンを実装するメタクラス"""
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
instance = super().__call__(*args, **kwargs)
cls._instances[cls] = instance
return cls._instances[cls]
class Database(metaclass=SingletonMeta):
def __init__(self, connection_string="default"):
self.connection_string = connection_string
print(f"Database initialized: {connection_string}")
# 使用例
db1 = Database("postgres://localhost") # Database initialized: postgres://localhost
db2 = Database("mysql://localhost") # 初期化されない
print(db1 is db2) # True
print(db1.connection_string) # postgres://localhost
デバッグとイントロスペクション
クラス生成の追跡
import sys
# オリジナルの__build_class__を保存
original_build_class = __builtins__.__build_class__
def traced_build_class(func, name, *bases, **kwargs):
"""クラス生成を追跡するラッパー"""
print(f"Building class: {name}")
print(f" Bases: {bases}")
print(f" Kwargs: {kwargs}")
# オリジナルを呼び出し
result = original_build_class(func, name, *bases, **kwargs)
print(f" Created: {result}")
return result
# 追跡を有効化(デバッグ用)
# __builtins__.__build_class__ = traced_build_class
# クラスを定義(追跡される)
# class TracedClass:
# pass
クラス情報の取得
class MyClass:
"""サンプルクラス"""
class_var = 100
def __init__(self, value):
self.instance_var = value
def method(self):
pass
# クラス情報を表示
def inspect_class(cls):
"""クラスの詳細情報を表示"""
print(f"Class: {cls.__name__}")
print(f"Module: {cls.__module__}")
print(f"Bases: {cls.__bases__}")
print(f"MRO: {[c.__name__ for c in cls.__mro__]}")
print(f"Dict keys: {list(cls.__dict__.keys())}")
# メタクラスを確認
print(f"Metaclass: {type(cls)}")
inspect_class(MyClass)
# 出力:
# Class: MyClass
# Module: __main__
# Bases: (<class 'object'>,)
# MRO: ['MyClass', 'object']
# Dict keys: ['__module__', '__doc__', 'class_var', '__init__', 'method', ...]
# Metaclass: <class 'type'>
type()を使った代替手法
ほとんどの場合、__build_class__を直接使う代わりにtype()を使用します。
# 基本的な動的クラス生成
def create_data_class(name, fields):
"""フィールドを持つデータクラスを動的に生成"""
def __init__(self, **kwargs):
for field in fields:
setattr(self, field, kwargs.get(field))
def __repr__(self):
values = ', '.join(f'{f}={getattr(self, f)!r}' for f in fields)
return f'{name}({values})'
namespace = {
'__init__': __init__,
'__repr__': __repr__,
'__slots__': fields,
}
return type(name, (), namespace)
# 使用例
Person = create_data_class('Person', ['name', 'age', 'email'])
p = Person(name='Alice', age=30, email='alice@example.com')
print(p) # Person(name='Alice', age=30, email='alice@example.com')
まとめ
| 用途 | 推奨される方法 |
|---|---|
| 通常のクラス定義 | classキーワード |
| 動的クラス生成 | type() |
| クラス生成のカスタマイズ | メタクラス |
| 内部動作の理解 | __build_class__の学習 |
__build_class__は通常の開発では直接使用しませんが、Pythonのクラスシステムを深く理解するために重要な概念です。メタプログラミングやフレームワーク開発では、この知識が役立ちます。