Help us understand the problem. What is going on with this article?

Pythonでメタプログラミング

Pythonでのメタプログラミングを紹介。
メタプログラミングを理解する上でtype、__new__、__metaclass__を理解する
必要があるためブロックで分けて紹介してます

クラスの定義はtypeのインスタンスだった

まずPythonでのメタプログラミングを理解するには、
クラスの定義はtypeのインスタンスだったということについて理解しないければならない。

以下は通常クラスとtypeのクラスの定義で同様の挙動となります。

class Hoge(object):

    def function1(self, args):
        return args

    def function2(self, args):
        return args + 50
def func1(self, args):
    return args


def func2(self, args):
    return args + 50


# type(クラス名、親クラス、メンバー属性)になります
Hoge = type('Hoge', (object, ), {'function1': func1, 'function2': func2})

上記からわかるように、クラス定義は実はtypeのインスタンスだったということです。
type(Hoge) は type を返し、 isinstance(Hoge, type) は True を返します。

__init__と__new__について

Pythonでインスタンスの生成を行うと__init__が呼び出されインスタンスの初期化が行われると
理解してますが、__init__の前には暗黙的に__new__による処理が存在しています。
この__new__で上記のようなtypeのインスタンス化が自動的に行われクラスが定義されています。

__metaclass__について

上記で__new__でtypeのインスタンス化が行われていると説明しましたが、
このtypeのインスタンス化を別の定義で置き換えることができます。それが__metaclass__になります。
__metaclass__に関数やクラスを定義することでtypeのインスタンス化時にクラスを拡張することができます

class HogeMeta(type):

    def __new__(mcs, name, bases, dictionary):
        cls = type.__new__(mcs, name, bases, dictionary)
        setattr(cls, 'member1', 10)
        setattr(cls, 'member2', 20)
        return cls

class Hoge(object):

    __metaclass__ = HogeMeta

print Hoge().member1   -> 10
print Hoge().member2   -> 20

サンプル

複数のSkillクラス定義をMetaクラスで管理して、
skill_keyで任意のクラスを取得する場合。

class AttackSkill(object):
    name = u'特大攻撃'


class HealSkill(object):
    name = u'回復'


class PoisonSkill(object):
    name = u'毒攻撃'


class SkillMeta(type):

    def __new__(mcs, name, bases, dictionary):
        cls = type.__new__(mcs, name, bases, dictionary)
        skills = {'attack': AttackSkill,
                  'heal': HealSkill,
                  'poison': PoisonSkill}
        cls.SKILLS = skills
        return cls


class Skills(object):

    __metaclass__ = SkillMeta

    SKILLS = {}

    @classmethod
    def get(cls, skill_key):
        return cls.SKILLS[skill_key]

Skill = Skills.get

print Skill('attack').name   -> 特大攻撃
print Skill('heal').name     -> 回復

まとめ

サンプルでのやり方は、Metaプログラミングを利用せず、関数やdictを組み合せてもできるけど
前者でやった方がより拡張性が高く簡潔に書けそう。
あと、すべてクラスで完結できてるのでオブジェクト指向性が高い。

参考

http://www.yunabe.jp/docs/python_metaclass.html

fujimisakari
通りすがりのエセ力士
http://blog.fujimisakari.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした