- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
在这个众所周知的answer这解释了 Python 中的元类。它提到 __metaclass__
属性不会被继承。
但事实上,我在 Python 中尝试过:
class Meta1(type):
def __new__(cls, clsname, bases, dct):
print "Using Meta1"
return type.__new__(cls, clsname, bases, dct)
# "Using Meta1" printed
class Foo1:
__metaclass__ = Meta1
# "Using Meta1" printed
class Bar1(Foo1):
pass
正如预期的那样,Foo
和 Bar
都使用 Meta1
作为元类并按预期打印字符串。
但在下面的示例中,当返回 type(...)
而不是 type.__new__(...)
时,元类不再被继承:
class Meta2(type):
def __new__(cls, clsname, bases, dct):
print "Using Meta2"
return type(clsname, bases, dct)
# "Using Meta2" printed
class Foo2:
__metaclass__ = Meta2
# Nothing printed
class Bar2(Foo2):
pass
检查 __metaclass__
和 __class__
属性,我可以看到:
print Foo1.__metaclass__ # <class '__main__.Meta1'>
print Bar1.__metaclass__ # <class '__main__.Meta1'>
print Foo2.__metaclass__ # <class '__main__.Meta2'>
print Bar2.__metaclass__ # <class '__main__.Meta2'>
print Foo1.__class__ # <class '__main__.Meta1'>
print Bar1.__class__ # <class '__main__.Meta1'>
print Foo2.__class__ # <type 'type'>
print Bar2.__class__ # <type 'type'>
总结:
__metaclass__
和 __class__
都会继承自基类。
Meta2
定义的创建行为将用于Foo2
,虽然Foo2.__class__
实际上是type
.
Bar2
中的__metaclass__
属性是Meta2
,但是Bar2
的创建行为不是做作的。换句话说,Bar2
使用 type
作为其“真正的”元类,而不是 Meta2
。
这些观察结果让我对 __metaclass__
的继承机制有点模糊。
我的猜测是:
当直接将类(例如Meta1
)分配给另一个类'Foo1'的__metaclass__
属性时,它是__metaclass__
属性生效。
当子类在定义时没有显式设置__metaclass__
属性。基类的 __class__
属性而不是 __metaclass__
属性将决定子类的“真实”元类。
我的猜测正确吗? Python如何处理元类的继承?
最佳答案
你在猜测很多,而 Python 的极简主义和“特殊情况还不足以打破规则”。指令,让它更容易理解。
在 Python2 中,类主体中的 __metaclass__
属性在类创建时用于调用该类将成为的“类”。通常它是名为 type
的类。需要澄清的是,那一刻是在解析器解析了类主体之后,在编译器将其编译为代码对象之后,并且在程序运行时实际运行之后,并且只有 __metaclass__
是显式的在该类(class)机构中提供。
所以让我们检查一下这样的情况:
class A(object):
__metaclass__ = MetaA
class B(A):
pass
A
的主体中有 __metaclass__
- MetaA
被调用而不是 type
以使其成为“类”目的”。B
的主体中没有 __metaclass__
。创建后,如果您只是尝试访问 __metaclass__
属性,它是一个与其他任何属性一样的属性,它将是可见的,因为 Python 将从父类(super class) A
中获取它。如果您检查 A.__dict__
,您将看到 __metaclass__
,如果您检查 B.__dict__
,则不会。
创建 B 时,A.__metaclass__
属性根本未使用。如果在声明 B
之前在 A
中更改它,仍将使用与 A
相同的元类 - 因为 Python 确实使用父类的类型作为缺少显式 __metaclass__
声明的元类。
举例说明:
In [1]: class M(type): pass
In [2]: class A(object): __metaclass__ = M
In [3]: print "class: {}, metaclass_attr: {}, metaclass_in_dict: {}, type: {}".format(A.__class__, A.__metaclass__, A.__dict__.get("__metaclass__"), type(A))
class: <class '__main__.M'>, metaclass_attr: <class '__main__.M'>, metaclass_in_dict: <class '__main__.M'>, type: <class '__main__.M'>
In [4]: class B(A): pass
In [5]: print "class: {}, metaclass_attr: {}, metaclass_in_dict: {}, type: {}".format(B.__class__, B.__metaclass__, B.__dict__.get("__metaclass__"), type(B))
class: <class '__main__.M'>, metaclass_attr: <class '__main__.M'>, metaclass_in_dict: None, type: <class '__main__.M'>
In [6]: A.__metaclass__ = type
In [8]: class C(A): pass
In [9]: print "class: {}, metaclass_attr: {}, metaclass_in_dict: {}, type: {}".format(C.__class__, C.__metaclass__, C.__dict__.get("__metaclass__"), type(C))
class: <class '__main__.M'>, metaclass_attr: <type 'type'>, metaclass_in_dict: None, type: <class '__main__.M'>
此外,如果您尝试通过调用 type
而不是使用带有 class
语句的主体来创建类,__metaclass__
也只是一个普通的属性:
In [11]: D = type("D", (object,), {"__metaclass__": M})
In [12]: type(D)
type
到目前为止的总结:Python 2 中的 __metaclass__
属性只有在作为 class
block 语句。它是一个普通属性,之后没有特殊属性。
Python3 都摆脱了这种奇怪的“__metaclass__
属性现在不好”,并允许通过更改语法以指定元类来进一步自定义类主体。 (就像在 class
语句本身上声明它是一个“metaclass
named parameter”一样)
现在,对于引起您怀疑的第二部分:如果在元类的 __new__
方法中调用 type
而不是 type.__new__
,Python 无法“知道”正在从派生元类调用 type
。当您调用 type.__new__
时,您将 cls
属性作为其第一个参数传递给您的元类的 __new__
本身由运行时传递:这就是将生成的类标记为 type
的子类的实例。 这就像继承适用于 Python 中的任何其他类一样 - 所以这里“没有特殊行为”:
所以,找出不同之处:
class M1(type):
def __new__(metacls, name, bases, attrs):
cls = type.__new__(metacls, name, bases, attrs)
# cls now is an instance of "M1"
...
return cls
class M2(type):
def __new__(metacls, name, bases, attrs):
cls = type(name, bases, attrs)
# Type does not "know" it was called from within "M2"
# cls is an ordinary instance of "type"
...
return cls
在交互提示中可以看到:
In [13]: class M2(type):
....: def __new__(metacls, name, bases, attrs):
....: return type(name, bases, attrs)
....:
In [14]: class A(M2): pass
In [15]: type(A)
Out[15]: type
In [16]: class A(M2): __metaclass__ = M2
In [17]: A.__class__, A.__metaclass__
Out[17]: (type, __main__.M2)
(请注意,元类 __new__
方法的第一个参数是元类本身,因此更恰本地命名为 metacls
而不是 cls
在您的代码中,并且在很多代码中“在野外”)
关于python - 元类的继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37410692/
我使用的是 PHP 5.3 稳定版,有时会遇到非常不一致的行为。据我所知,在继承中,父类(super class)中的所有属性和方法(私有(private)、公共(public)和 protected
所以我一直在努力寻找正确的方法来让应该非常简单的继承发挥作用(以我想要的方式 ;)),但我失败得很惨。考虑一下: class Parent { public String name = "Pare
给定这些类: class Father { public Father getMe() { return this; } } class Child extends Father {
为什么最后打印“I'm a Child Class”。 ? public class Parent { String parentString; public Parent()
我知道有很多类似的问题对此有很多很好的答案。我试着看看经典的继承方法,或者那些闭包方法等。不知何故,我认为它们对我来说或多或少是“hack”方法,因为它并不是 javascript 设计的真正目的。
我已经使用表单继承有一段时间了,但没有对以下方法进行太多研究。只需创建一个新类而不是表单并从现有表单继承并根据需要将所需控件转换为 protected 。 Visual Studio 2010 设计器
我原以为下面的代码片段会产生编译错误,因为派生类不会有我试图在 pub_fun() 中访问的 priv_var。但是它编译了,我得到了下面提到的输出。有人可以解释这背后的理论吗? class base
继承的替代方案有哪些? 最佳答案 Effective Java:优先考虑组合而不是继承。 (这实际上也来自《四人帮》)。 他提出的情况是,如果扩展类没有明确设计为继承,继承可能会导致许多不恰当的副作用
我有2个类别:动物( parent )和狗(动物的“ child ”),当我创建一个 Animal 对象并尝试提醒该动物的名称时,我得到了 undefined ,而不是她的真名。为什么?(抱歉重复发帖
我试图做继承,但没想到this.array会像静态成员一样。我怎样才能让它成为“ protected /公开的”: function A() { this.array = []; } func
在创建在父类中使用的 lambda 时,我试图访问子类方法和字段。代码更容易解释: class Parent { List> processors; private void do
如果我有一个对象,我想从“ super 对象”“继承”方法以确保一致性。它们将是混合变量。 修订 ParentObj = function() { var self = this; t
class Base { int x=1; void show() { System.out.println(x); } } class Chi
目前我正在尝试几种不同的 Javascript 继承方法。我有以下代码: (“借用”自 http://www.kevlindev.com/tutorials/javascript/inheritanc
我在 .popin-foto 元素中打开一个 popin。当我尝试在同一元素中打开子类 popin 时,它不起作用。 代码 这是 parent function Popin(container, ti
我有以下两个类: class MyClass { friend ostream& operatorvalue +=1; return *this; } 现在
有没有办法完全忽略导入到 html 文件中的 header 中的 CSS 文件? 我希望一个页面拥有自己独立的 CSS,而不是从任何其他 CSS 源继承。 最佳答案 您可以在本地样式表中使用 !imp
Douglas Crockford似乎喜欢下面的继承方式: if (typeof Object.create !== 'function') { Object.create = functio
假设我有以下代码: interface ISomeInterface { void DoSomething(); void A(); void B(); } public
class LinkedList{ public: int data; LinkedList *next; }; class NewLinkedList: public Lin
我是一名优秀的程序员,十分优秀!