yarbelk yarbelk - 2 months ago 16
Python Question

Python metaclass arguments

I'm trying to dynamically generate classes in python 2.7, and am wondering if you can easily pass arguments to the metaclass from the class object.

I've read this post, which is awesome, but doesn't quite answer the question. at the moment I am doing:

def class_factory(args, to, meta_class):
Class MyMetaClass(type):
def __new__(cls, class_name, parents, attrs):
attrs['args'] = args
attrs['to'] = to
attrs['eggs'] = meta_class

class MyClass(object):
metaclass = MyMetaClass
...


but this requires me to do the following

MyClassClass = class_factory('spam', 'and', 'eggs')
my_instance = MyClassClass()


Is there a cleaner way of doing this?

Answer

Yes, there's an easy way to do it. In the metaclass's __new__() method just check in the class dictionary passed as the last argument. Anything defined in the class statement will be there. For example:

class MyMetaClass(type):
    def __new__(cls, class_name, parents, attrs):
        if 'meta_args' in attrs:
            meta_args = attrs['meta_args']
            attrs['args'] = meta_args[0]
            attrs['to'] = meta_args[1]
            attrs['eggs'] = meta_args[2]
            del attrs['meta_args'] # clean up
        return type.__new__(cls, class_name, parents, attrs)

class MyClass(object):
    __metaclass__ = MyMetaClass
    meta_args = ['spam', 'and', 'eggs']

myobject = MyClass()

from pprint import pprint
pprint(dir(myobject))
print myobject.args, myobject.to, myobject.eggs

Output:

['__class__',
 '__delattr__',
 '__dict__',
 '__doc__',
 '__format__',
 '__getattribute__',
 '__hash__',
 '__init__',
 '__metaclass__',
 '__module__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 'args',
 'eggs',
 'to']
spam and eggs