python的基础元类:纯粹的蟒蛇模拟?

时间:2014-03-20 23:01:57

标签: python metaclass

我真的不明白基本元类是如何工作的(又名type)。有没有人知道它的功能的纯python模拟?

python文档经常为C级代码执行此操作,这些代码很难用英语完全描述(例如,请参阅the explaination of __getattribute__),但不适用于type

我知道怎么开始。由于使用类型的子类定义type的行为有点像说'#34;类型工作方式类型工作",我定义了一个鸭类型元类。它有些功能,但还不够。

class MetaClassDuck(object):
    @classmethod
    def __new__(self, mcs, name, bases, attrs):
        """Create a new class object."""
        newcls = super(MetaClassDuck, self).__new__(mcs)
        newcls.__dict__.update(attrs)
        newcls.__name__ = name
        newcls.__bases__ = bases
        return newcls

    def __call__(cls, *args, **kwargs):
        """Calling a class results in an object instance."""
        ###########################################################
        # Fill in the blank:
        # I don't see a way to implement this without type.__new__
        ###########################################################
        return newobj

class MyClass(object):
    __metaclass__ = MetaClassDuck

    one = 1
    _two = 2

    @property
    def two(self):
        return self._two

# This bit works fine.
assert type(MyClass) is MetaClassDuck
assert MyClass.one == 1
assert isinstance(MyClass.two, property)

myobj = MyClass()
# I crash here:
assert myobj.one == 1
assert myobj.two == 2


class MyClass2(MyClass):
    three = 3

assert type(MyClass2) is MetaClassDuck
assert MyClass2.one == 1
assert isinstance(MyClass2.two, property)
assert MyClass2.three == 3

myobj2 = MyClass2()
assert myobj2.one == 1
assert myobj2.two == 2
assert myobj2.three == 3

2 个答案:

答案 0 :(得分:0)

__new__负责创建新实例,而不是__call____call__只是将实例创建工作传递给__new__,并返回__new__返回的内容,并在需要时调用__init__

回答这个type(双关语)的最好方法是挖掘C代码。只需下载源代码,解压缩它和vim Objects/typeobject.c或者你用来阅读和调整代码的任何内容。

如果你看一下,你会发现type元类的所有组件的C实现。 __new__非常大,FIY。

def __call__(cls, *args, *kwds):看起来像是:

实际C代码

static PyObject *
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    PyObject *obj;

    if (type->tp_new == NULL) {
        PyErr_Format(PyExc_TypeError,
                     "cannot create '%.100s' instances",
                     type->tp_name);
        return NULL;
    }

    obj = type->tp_new(type, args, kwds);
    if (obj != NULL) {
#        /* Ugly exception: when the call was type(something),
#           don`t call tp_init on the result. */
        if (type == &PyType_Type &&
            PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 &&
            (kwds == NULL ||
             (PyDict_Check(kwds) && PyDict_Size(kwds) == 0)))
            return obj;
#        /* If the returned object is not an instance of type,
#           it won`t be initialized. */
        if (!PyType_IsSubtype(obj->ob_type, type))
            return obj;
        type = obj->ob_type;
        if (PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS) &&
            type->tp_init != NULL &&
            type->tp_init(obj, args, kwds) < 0) {
            Py_DECREF(obj);
            obj = NULL;
        }
    }
    return obj;
}
我添加了

#来帮助Stackoverflow的语法高亮显示器正确呈现注释

大致相等的Python实现

这只是我理解type.__call__所做的一个pythonic解释。 这不是重新实现的!

我可能忽略了一些方面,因为我对PyC API很新,所以请随时纠正我。但我会按如下方式实现它:

def __call__(cls, *args, **kwds):
    #We`ll be naming the class reference cls here, in the C code it's called type.
    try:
        obj = cls.__new__(cls, args, kwds)
    except AttributeError:      
        #The code first checks whether there is a __new__ method, we just catch the AttributeError 
        #exception.
        raise TypeError('cannot create {} instances', cls.__name__)
    else:
        #The last if block checks that no errors occurred *inside* cls.__new__ 
        #(in the C code: type->tp_new)                        
        cls.__init__(obj, args, kwds)
        #The last if block checks whether any exception occurred while calling __init__ 
        #(return NULL or return -1 tells the calling function that an error/exception occurred,               
        #IDK the difference between the two.)
        return obj

最后的笔记

  • 我会检查__new__实现(它叫做type_new)
  • 如果您想了解Python内部的工作原理,请尝试学习C API,然后阅读C源代码。
  • 我是Python C源代码的新手,所以我可能忽略了一些东西。请纠正我,任何人都知道!

答案 1 :(得分:0)

我不知道任何Python类似物;但是,如果您想知道完全的类型,您需要深入了解c来源。

通常,它执行任何元类的操作:根据各种规范对结果类进行调整。

例如:

--> huh = type('my_type', (), {'some_var':7})
--> huh
<class '__main__.my_type'>
--> h = huh()
--> huh.some_var
7

此处,type正在创建一个名为my_type的新类和一个名为some_var的类属性,其初始值为7

如果你想在stdlib中看到一个有用的,有些复杂的元类例子,请查看3.4中的新Enum data type