3

我知道不再推荐旧式 Python 类,尤其是在 Python 3 删除了它们之后。但是,我仍然想了解这里发生了什么:

class MyClass:
  pass

my_instance = MyClass()
str(my_instance)

此代码段打印以下内容:

'<位于 0x108ec4290 的.MyClass 实例>'

所以,我没有任何显式继承,也没有重载str方法。但是,这不会为所谓的缺失方法引发异常。为什么?

我知道旧式类具有“实例”和“类型”的概念,而新式类旨在统一这些概念。Python 是否会在我的实例隐式连接到的“实例”类型上查找并调用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']

谁能准确解释旧式类中的类和类型之间的关系以及这里发生了什么?

4

1 回答 1

1

我相信其他人可以给你更具体的理由,但是这里有一个类似讨论的引用:old-style class

object是位于任何继承树顶部的基类。我相信坚持基类的目的是统一对象行为而不需要太多的“魔法”。也就是说,在新式类之前,对象只是神奇地具有像__doc__ 和这样的属性__str__;现在,他们拥有它们是有原因的:因为他们从基类继承了它们。

我相信关于“魔法”的那部分就是……黑盒魔法。显然,旧样式类的 MRO(方法解析顺序)更加神奇,因为它可能必须检查instance对象上的显式定义以及type. __str__要么,要么旧样式类的部分机制是在找不到方法时始终提供默认方法。

现在使用新样式的类就不会那么神奇了,因为由于继承,方法确实就在实例上。

这是另一个有一些很好的引用和例子的网站:最大惊喜的原则

对于旧式类,所有查找都在实例中完成。

对于新式类的实例,所有隐式完成的特殊方法查找都在类结构中完成

新风格:

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
于 2012-09-01T00:22:00.013 回答