Documentation Python

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のクラスシステムを深く理解するために重要な概念です。メタプログラミングやフレームワーク開発では、この知識が役立ちます。

参考文献

円