如何从类定义将参数传递给元类? [英] How to pass arguments to the metaclass from the class definition?

查看:74
本文介绍了如何从类定义将参数传递给元类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在python 2.7中动态生成类,并且想知道是否可以轻松地从类对象将参数传递给元类.

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

有没有更清洁的方法?

推荐答案

是的,有一种简单的方法.在元类的__new__()方法中,只需检入作为最后一个参数传递的类字典. class语句中定义的所有内容都将存在.例如:

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

输出:

['__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

更新

上面的代码仅在Python 2中可用,因为用于指定元类的语法在Python 3中以不兼容的方式进行了更改.

The code above will only work in Python 2 because syntax for specifying a metaclass was changed in an incompatible way in Python 3.

使其在Python 3中工作(但不再在Python 2中工作)非常简单,只需将MyClass的定义更改为:

To make it work in Python 3 (but no longer in Python 2) is super simple to do and only requires changing the definition of MyClass to:

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

还可以通过即时"创建基类来解决语法差异并生成适用于Python 2和3的代码,这涉及显式调用元类并使用创建的基类作为基类.其中一个被定义.

It's also possible to workaround the syntax differences and produce code that works in both Python 2 and 3 by creating base classes "on-the-fly" which involves explicitly invoking the metaclass and using the class that is created as the base class of the one being defined.

class MyClass(MyMetaClass("NewBaseClass", (object,), {})):
    meta_args = ['spam', 'and', 'eggs']

Python 3中的类构造也已进行了修改,并添加了支持,该支持允许使用其他方式传递参数,在某些情况下,使用它们可能比此处显示的技术更容易.这完全取决于您要完成的工作.

Class construction in Python 3 has also been modified and support was added that allows other ways of passing arguments, and in some cases using them might be easier than the technique shown here. It all depends on what you're trying to accomplish.

请参阅@John Crawford的详细答案,以获取有关新版本Python中该过程的描述.

See @John Crawford's detailed answer for a description of of the process in the new versions of Python.

这篇关于如何从类定义将参数传递给元类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆