我看过这样的帖子:
但不知怎的,我感到困惑。许多混淆如:
我何时以及为何要做以下事情?
# Refer link1
return super(MyType, cls).__new__(cls, name, bases, newattrs)
或
# Refer link2
return super(MetaSingleton, cls).__call__(*args, **kw)
或
# Refer link2
return type(self.__name__ + other.__name__, (self, other), {})
超级工作如何完成?
link1中的类注册表和取消注册是什么以及它究竟是如何工作的? (我认为它与singleton有关。我可能错了,来自C背景。我的编码风格仍然是功能和OO的混合。)
类实例化(子类,元类,超类型)和方法调用的流程是什么(
metaclass->__new__, metaclass->__init__, super->__new__, subclass->__init__ inherited from metaclass
)具有良好评论的工作代码(虽然第一个链接非常接近,但它没有谈论cls关键字和超级(..)和注册表)。最好是具有多重继承的示例。
P.S。:我将最后一部分作为代码,因为Stack Overflow格式化正在转换文本metaclass->__new__
到元类 - > 新
答案 0 :(得分:21)
好的,你在这里混合了很多概念!我将提出你遇到的一些具体问题。
一般来说,理解super,MRO和metclasses变得更加复杂,因为在最后几个版本的Python中,这个棘手的领域发生了很多变化。
Python's own documentation是一个非常好的参考,并且完全是最新的。有一个IBM developerWorks article作为介绍很好,并采用了更多基于教程的方法,但请注意它已经有五年了,并且花了很多时间讨论旧式的元类方法。 / p>
super
是您访问对象超类的方法。它比(例如)Java的super
关键字更复杂,主要是因为Python中的多重继承。正如Super Considered Harmful所解释的那样,使用super()
会导致您隐式使用超类的链,其顺序由Method Resolution Order(MRO)定义。
通过在类(而不是实例)上调用mro()
,您可以轻松地查看类的MRO。请注意,元类不在对象的超类层次结构中。
元类是类的类。 就像一个类定义一个实例 该类的行为,一个元类 定义类的行为方式。一类 是元类的一个实例。
在您给出的示例中,这是正在发生的事情:
正在调用__new__
冒泡到了下一件事
MRO。在这种情况下,super(MyType,
cls)
将解析为type
;
调用type.__new__
可以让Python
完成它的正常实例
创作步骤。
此示例使用元类
强制执行单身人士。他是
覆盖__call__
元类使每当一个类
实例被创建,他拦截
那,并且可以绕过实例
创造,如果已经有一个
(存储在cls.instance
)。注意
在...中覆盖__new__
元类不够好,
因为那只是在什么时候被召唤
创建类。重写
课上__new__
会奏效,
但是。
这显示了一种动态方式 创建一个类。这是他的 附加提供的类的名称 到创建的类名,和 将其添加到类层次结构中 太
我不确定你正在寻找什么样的代码示例,但这里有一个显示元类,继承和方法解析的简短示例:
class MyMeta(type):
def __new__(cls, name, bases, dct):
print "meta: creating %s %s" % (name, bases)
return type.__new__(cls, name, bases, dct)
def meta_meth(cls):
print "MyMeta.meta_meth"
__repr__ = lambda c: c.__name__
class A(object):
__metaclass__ = MyMeta
def __init__(self):
super(A, self).__init__()
print "A init"
def meth(self):
print "A.meth"
class B(object):
__metaclass__ = MyMeta
def __init__(self):
super(B, self).__init__()
print "B init"
def meth(self):
print "B.meth"
class C(A, B):
__metaclass__ = MyMeta
def __init__(self):
super(C, self).__init__()
print "C init"
>>> c_obj = C()
meta: creating A (<type 'object'>,)
meta: creating B (<type 'object'>,)
meta: creating C (A, B)
B init
A init
C init
>>> c_obj.meth()
A.meth
>>> C.meta_meth()
MyMeta.meta_meth
>>> c_obj.meta_meth()
Traceback (most recent call last):
File "mro.py", line 38, in <module>
c_obj.meta_meth()
AttributeError: 'C' object has no attribute 'meta_meth'
答案 1 :(得分:9)
这是更实用的答案。
很少重要
“What is a metaclass in Python”。底线type
是所有类的元类。你几乎没有实际用途。
class X(object):
pass
type(X) == type
“What are your (concrete) use cases for metaclasses in Python?”。底线。无。
“Python's Super is nifty, but you can't use it”。有趣的是,但实用价值不大。您永远不需要解析复杂的多继承网络。通过使用明确的策略设计而不是多重继承,可以轻松防止出现此问题。
这是我在过去7年的Python编程方面的经验。
一个班级有一个或多个超类,形成一个从我班级到object
的简单链。
“class”的概念由名为type
的元类定义。我可能想扩展“阶级”的概念,但到目前为止,它从未在实践中出现过。不止一次。 type
始终做正确的事。
在实践中使用super
非常有效。它允许子类遵循它的超类。它恰好出现在这些元类示例中,因为它们扩展了内置元类type
。
但是,在所有子类情况下,您将使用super
来扩展超类。
<强>元类强>
元类问题是:
每个对象都引用了它的类型定义或“类”。
class
本身也是一个对象。
因此class
类型的对象引用了它的类型或“类”。 “类”的“类”是元类。
由于“class”不是C ++运行时对象,因此在C ++中不会发生这种情况。它确实发生在Java,Smalltalk和Python中。
元类定义了类对象的行为。
您与班级互动的90%是要求班级创建新对象。
10%的情况下,您将使用类方法或类变量(C ++或Java用语中的“静态”。)
我找到了一些用于类级方法的用例。我几乎没有类变量的用例。我从来没有改变对象构建方式的情况。