gpt4 book ai didi

python 的基本元类 : a pure-python analogue?

转载 作者:太空狗 更新时间:2023-10-30 00:19:36 24 4
gpt4 key购买 nike

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

Python 文档通常会为难以用英语完整描述的 C 级代码执行此操作(例如,请参阅 the explaination of __getattribute__ ),但不会为 type 执行此操作。

我确实知道如何开始。由于使用 type 的子类定义 type 的行为有点像说“type works the way type works”,所以我定义了一个 duck-typed 元类。它有一些作用,但还不够。

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

最佳答案

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

回答这个类型(双关语意)问题的最好方法是深入研究 C 代码。只需下载源代码,解压它和 vim Objects/typeobject.c 或任何您用来阅读和摆弄代码的东西。

如果您查看它,您会发现 type 元类的所有组件的 C 实现。 __new__大得离谱,你猜。

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 源代码还很陌生,所以我可能忽略了一些东西。请知道的人指正!

关于python 的基本元类 : a pure-python analogue?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22546969/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com