34

In Python2.7 this code can work very well, __getattr__ in MetaTable will run. But in Python 3 it doesn't work.

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 

But in Python 3.5 I get an attribute error instead:

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' 

1 Answer 1

57

Python 3 changed how you specify a metaclass, __metaclass__ is no longer checked.

Use metaclass=... in the class signature:

class Table(object, metaclass=MetaTable): 

Demo:

>>> 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> 

If you need to provide support for both Python 2 and 3 in your codebase, you can use the six.with_metaclass() baseclass generator or the @six.add_metaclass() class decorator to specify the metaclass.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for this. It got my favourite plugin system working in python 3.
It would be possible to leave the existing __metaclass__ syntax in place. python.org/dev/peps/pep-3115
@CodeFarmer: yes, but it doesn't do anything any more.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.