I need to define custom attributes for a class, but redefining __getattr__ works only for the instance, not for the class itself, and making it static doesn't really help. I know that something like this works for Python 2, but I couldn't find anything similar on Python 3, I suspect due to changing the way metaclasses work. How would I achieve similar result?
2 Answers
You need to change the way you specify metaclasses in Python 3. It was changed from a dunder attribute __metaclass__ to a kwarg you supply after the base classes. Other than that, the solution provided there suffices:
class MyClass(metaclass = FooType): pass
Now MyClass.Foo or MyClass.Bar call the methods _foo_func and _bar_func respectively.
Note that the custom descriptor object, the second answer in the linked question, is:
- More portable granted you explicitly inherit from
objectin your class definitions. - More maintainable than creating a custom metaclass. Metaclasses might lead to confusion and weird conflicts down the line, descriptors are simple after you get a hang of them
Comments
Adding to Jims answer: If you need Python2 and 3 compatibility you can use the six.add_metaclass class decorator:
import six
@six.add_metaclass(your_metaclass)
class Yourclass(): # no need to add "metaclass = your_metaclass" here!
# no need to define "__metaclass__ = your_metaclass" here
Like the documentation states, this:
@six.add_metaclass(Meta)
class MyClass(object):
pass
is identical to (python2):
class MyClass(object):
__metaclass__ = Meta
or (python3):
class MyClass(object, metaclass=Meta):
pass