我知道不再推荐旧式Python类,特别是因为Python 3删除了它们。但是,我仍然想了解这里发生了什么:
class MyClass:
pass
my_instance = MyClass()
str(my_instance)
此代码段打印以下内容:
'< main .MyClass实例位于0x108ec4290>'
所以,我没有任何明确的继承,我没有重载 str 方法。但是,这并没有引起所谓的遗漏方法的异常。为什么呢?
我知道旧式课程具有“实例”和“类型”的概念,新式课程旨在统一这些概念。那么Python是否在我的实例隐式连接的'instance'类型上找到并调用 str 方法?
以下是一些线索:
dir(my_instance) - 返回:
['__doc__', '__module__']
type(my_instance) - 返回:
<type 'instance'>
dir(type(my_instance)) - 返回:
['__abs__', '__add__', '__and__', '__call__', '__class__', '__cmp__', '__coerce__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__div__', '__divmod__', '__doc__', '__eq__', '__float__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__hex__', '__iadd__', '__iand__', '__idiv__', '__ifloordiv__', '__ilshift__', '__imod__', '__imul__', '__index__', '__init__', '__int__', '__invert__', '__ior__', '__ipow__', '__irshift__', '__isub__', '__iter__', '__itruediv__', '__ixor__', '__le__', '__len__', '__long__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__xor__', 'next']
任何人都可以准确解释旧式类中的类和类型之间的关系以及这里发生了什么?
答案 0 :(得分:1)
我相信其他人可以给你更具体的理由,但是这里引用了类似的讨论:old-style class
object
是任何继承树顶部的基类。 我认为,坚持基类的目的是统一 对象行为不需要太多“魔法”。也就是说,之前 新式的类,对象只是神奇地拥有像__doc__
这样的属性 和__str__
;现在,他们有他们是有原因的:因为他们继承了 他们来自基地。
关于“神奇”的部分,我相信只是......黑盒魔术。显然,旧样式类的MRO(方法解析顺序)更加神奇,因为它可能必须检查instance
对象以及type
上的显式定义。无论是旧样式类的机制还是其中的一部分,当无法找到它时,它总是提供默认的__str__
方法。
现在使用新式类会不那么神奇,因为由于继承,方法实际上就在实例上。
以下是另一个网站,其中包含一些好的引用和示例:Principle of Biggest Surprise
对于旧式类,所有查找都在实例中完成。
对于新式类的实例,所有特殊方法查找都是在类struct
中完成的。
新风格:强>
class Foo(object):
def __str__(self):
return "old str"
foo = Foo()
foo.__str__ = lambda: "new str"
print str(foo)
print foo.__str__()
# old str
# new str
<强>旧式:强>
class Foo:
def __str__(self):
return "old str"
foo = Foo()
foo.__str__ = lambda: "new str"
print str(foo)
print foo.__str__()
# new str
# new str