web-dev-qa-db-ja.com

__metaclass__ in Python 3

Python2.7では、このコードは非常にうまく機能します。__getattr__ in MetaTableが実行されます。しかし、Python 3では、動作しません。

class MetaTable(type):
    def __getattr__(cls, key):
        temp = key.split("__")
        name = temp[0]
        alias = None

        if len(temp) > 1:
            alias = temp[1]

        return cls(name, alias)


class Table(object):
    __metaclass__ = MetaTable

    def __init__(self, name, alias=None):
        self._name = name
        self._alias = alias


d = Table
d.student__s

しかしPython 3.5では、代わりに属性エラーが発生します。

Traceback (most recent call last):
  File "/Users/wyx/project/python3/sql/dd.py", line 31, in <module>
    d.student__s
AttributeError: type object 'Table' has no attribute 'student__s'
15
wyx

Python 3 は、メタクラス の指定方法を変更しました。__metaclass__はチェックされなくなりました。

クラスでmetaclass=...を使用しますsignature

class Table(object, metaclass=MetaTable):

デモ:

>>> class MetaTable(type):
...     def __getattr__(cls, key):
...         temp = key.split("__")
...         name = temp[0]
...         alias = None
...         if len(temp) > 1:
...             alias = temp[1]
...         return cls(name, alias)
...
>>> class Table(object, metaclass=MetaTable):
...     def __init__(self, name, alias=None):
...         self._name = name
...         self._alias = alias
...
>>> d = Table
>>> d.student__s
<__main__.Table object at 0x10d7b56a0>

コードベースでPython 2と3の両方をサポートする必要がある場合は、 six.with_metaclass() baseclass generator を使用できます。または、メタクラスを指定する @six.add_metaclass() class decorator

33
Martijn Pieters