gpt4 book ai didi

python - 为什么元类应该从类型继承?

转载 作者:行者123 更新时间:2023-12-03 23:15:12 25 4
gpt4 key购买 nike

我们可以将函数用作元类,我的理解是它们不是从类型派生的,如下所示:

def test_meta(name, bases, atts):
print("testmeta called for " + name)
return type(name,bases,atts);

class Computer:
__metaclass__ = test_meta
def __init__(self,brand,model,price):
self.brand = brand
self.model = model
self.price = price

#
#
ob = Computer('p1','core2duo',21985.25)

但是,当我们编写元类时,它应该从类型继承,我无法理解这背后的原因:
class MyMeta:
def __new__(meta, name, bases, dct):
print ('-----------------------------------')
print ("Allocating memory for class", name)
print (meta)
print (bases)
print (dct)
return type.__new__(meta, name, bases, dct)

def __init__(cls, name, bases, dct):
print ('-----------------------------------')
print ("Initializing class", name)
print (cls)
print (bases)
print (dct)
type.__init__(cls,name, bases, dct)

def __call__(mcs, *args, **kwargs):
print ('-----------------------------------')
print ("calling class")
print mcs

class Computer:
__metaclass__ = MyMeta
def __init__(self,brand,model,price):
self.brand = brand
self.model = model
self.price = price

#
#
ob = Computer('p1','core2duo',21985.25)

例如在上面的代码中,我无法理解为什么 我的元 类应该是 继承 来自 类型 当我们显式调用类型函数时,即 , 初始化 , 调用 .
此外,只有在创建 i=instance (ob) 时,才会出现错误“descriptor ' init ' requires a 'type' object but received a 'instance'”。

最佳答案

在普通 Python 代码中,唯一真正创建内存中类对象的调用,具有二进制结构和所需的所有字段是 type.__new__ .使用像元类一样可调用的函数将只需要实例化 type本身,或创建根本不是类的东西(见下文)。

可以使用 native C 代码甚至在纯 Python 中创建另一个“基本元类”,调用 native OS 内存分配函数并填写相同的 structure defined for a "type object" , - 但是,这只会完成完全相同的任务type.__new__已经这样做了,所以它只是一个无法进一步改进的复杂且容易出错的轮子重新发明,因为生成的二进制布局必须与该结构中定义的相同(即实现“魔术功能”的方法的指针",如 __init____geitem__ 等,必须与该结构中的偏移量相同)

(附加字段,甚至此结构中数据的精细值都可以通过代码继承类型来完成 - 因此无论如何都可以通过普通的元类)

正如你所说,任何可调用的——即使是一个简单的函数,都可以在类主体上表示为“元类”(在 Python 2 和 Python 3 中)——但是,无论这个可调用做什么,在某个点上它都必须调用type.__new__ (函数通过调用 type 间接做到这一点)。但是,一旦构建了类,它本身就是一个 Python 对象,它是一个类的实例 - 类的类型(它的 __class__ 属性中的内容)是有效的元类。如果元类在代码中指向 __metaclass__属性或作为 Python 3 中的元类 kwarg,是 type 的子类,那也将是正确的元类。否则,如果它是一个普通函数,只是充当类工厂调用 type在它的主体中,有效的元类就是类型。

换句话说:

In [1]: def function_meta(name, bases, ns):
...: return type(name, bases, ns)
...:

In [2]: class test(metaclass=function_meta):
...: pass
...:

In [3]: type(test)
Out[3]: type

In [4]: class ClassMeta(type):
...: pass
...:
...:

In [5]: class test2(metaclass=ClassMeta):
...: pass
...:

In [6]: type(test2)
Out[6]: __main__.ClassMeta

那么,为什么不能从 type 继承的类?使用?

问题不在于指定的元类不继承自类型 - 可以使用任何可调用对象,如上所示。
当您尝试这样做时遇到的错误是由于调用 type.__new__以非子类类型作为第一个参数:
In [11]: class InheritFromOther(object):
...: def __new__(mcls, name, bases, ns):
...: return type.__new__(mcls, name, bases, ns)
...: # the line above is the one that errors - as
...: # mcls here is not a subclass of type.
...: # type(name, bases, ns) would work.

In [12]: class test4(metaclass=InheritFromOther):
...: pass
...:
...:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-12-bf5b1fa4bb7f> in <module>()
----> 1 class test4(metaclass=InheritFromOther):
2 pass

<ipython-input-11-62d1fe46490b> in __new__(mcls, name, bases, ns)
1 class InheritFromOther(object):
2 def __new__(mcls, name, bases, ns):
----> 3 return type.__new__(mcls, name, bases, ns)
4

TypeError: type.__new__(InheritFromOther): InheritFromOther is not a subtype of type

现在,如果我们调用 type.__new__使用类型的有效子类作为第一个参数:
In [13]: class InheritFromOtherTake2(object):
...: def __new__(mcls, name, bases, ns):
...: return type.__new__(type, name, bases, ns)
...:

In [14]: class test5(metaclass=InheritFromOtherTake2):
...: pass
...:

In [15]: type(test5)
Out[15]: type

只是为了完整性,如上所述,用作元类的可调用对象确实有可能返回类型实例(或其子类)以外的东西。在这种情况下, class 产生的对象语句体根本不会是一个类,但无论可调用返回什么:
In [7]: def dict_maker_meta(name, bases, ns):
...: return ns
...:

In [8]: class test3(metaclass=dict_maker_meta):
...: a = 1
...: b = 2
...: c = 'test'
...:

In [9]: type(test3)
Out[9]: dict

In [10]: test3
Out[10]:
{'__module__': '__main__',
'__qualname__': 'test3',
'a': 1,
'b': 2,
'c': 'test'}

关于python - 为什么元类应该从类型继承?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52327384/

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