項目35は言語に取り込まれた
Python 3.6がリリースされた。
Python 3.6で導入された新機能の一つに__init_subclass__
がある、というのは前回の流れと同じ。
項目35「クラス属性をメタクラスで注釈する」はクラス定義後にプロパティを修正したり注釈を加えるといった機能をメタクラスで実現するという内容である。
class Meta(type): def __new__(meta, name, bases, class_dict): for key, value in class_dict.items(): if isinstance(value, Field): value.name = key value.internal_name = '_' + key cls = type.__new__(meta, name, bases, class_dict) return cls class Field(object): def __init__(self): self.name = None self.internal_name = None def __get__(self, instance, instance_type): if instance is None: return self return getattr(instance, self.internal_name, '') def __set__(self, instance, value): setattr(instance, self.internal_name, value) class DatabaseRow(object, metaclass=Meta): pass class Customer(DatabaseRow): first_name = Field() last_name = Field() prefix = Field() suffix = Field() if __name__ == '__main__': foo = Customer() print('Before:', repr(foo.first_name), foo.__dict__) foo.first_name = 'Euler' print('After: ', repr(foo.first_name), foo.__dict__)
この項目も PEP 487 -- Simpler customisation of class creation | Python.orgにある__set_name__
を使うと簡単に書くことができる。
class Field(object): def __init__(self): self.name = None self.internal_name = None def __get__(self, instance, instance_type): if instance is None: return self return getattr(instance, self.internal_name, '') def __set__(self, instance, value): setattr(instance, self.internal_name, value) def __set_name__(self, owner, name): self.name = name self.internal_name = '_' + name class Customer(object): first_name = Field() last_name = Field() prefix = Field() suffix = Field() if __name__ == '__main__': foo = Customer() print('Before:', repr(foo.first_name), foo.__dict__) foo.first_name = 'Euler' print('After: ', repr(foo.first_name), foo.__dict__)
このように__set_name__
を使えばメタクラスを定義せずに所望の内容を実現できる。
一連のエントリを振り返ると、項目33,34そして35はいずれもメタクラスを利用する内容であるが、Python 3.6からは__init_subclass__
及び__set_name__
で書き換えることができる。
メタクラスを使うとどうしても複雑になってしまうが、__init_subclass__
及び__set_name__
を使えばシンプルに書くことができる。
将来、『Effective Python』の項目33, 34, 35はメタクラスを使わない内容に更新されるであろう。