Python中的基本多态性混淆

Python中的基本多态性混淆,python,inheritance,polymorphism,Python,Inheritance,Polymorphism,我正在阅读Python3面向对象编程,对其中一个示例感到有点困惑。这是第三章,p。78: class AudioFile: def __init__(self, filename): if not filename.endswith(self.ext): raise Exception("Invalid file format") self.filename = filename class MP3File(AudioFile):

我正在阅读Python3面向对象编程,对其中一个示例感到有点困惑。这是第三章,p。78:

class AudioFile:
    def __init__(self, filename):
        if not filename.endswith(self.ext):
            raise Exception("Invalid file format")
        self.filename = filename

class MP3File(AudioFile):
    ext = "mp3"
    def play(self):
        print("playing {} as mp3".format(self.filename))
因此
MP3File
继承自
AudioFile
。超类
AudioFile
如何访问
self.ext
?例如,Java有抽象类,所以不能保证AudioFile必须实例化/具有
ext
字段。更重要的是,我认为子类继承了来自超类的所有信息,但没有其他方向的信息流

看来我错了

任何澄清都很好


b外行

理想情况下,
音频文件
应该是一个,因为它确实定义了字段(self.ext)。如果您尝试实例化
AudioFile
,您应该会得到一个属性错误


我想你是对的。。示例只是还不想进入abc。

您是对的,不能保证音频文件将具有
ext
属性。如果要直接实例化AudioFile,或者编写一个没有定义
ext
的子类并实例化它,那么尝试访问
self.ext
确实会失败

<>你可以认为AudioFILE是一个抽象类,因为它依赖于它的子类填充细节,以便音频文件本身能够正常工作。但在Python中,这种抽象性不是由语言编码的;您只需记录人们必须编写音频文件的子类来定义
ext
,如果他们不这样做,那么他们可能会遇到错误。(一些其他类型的抽象性可以由模块处理,尽管在实践中它们通常也通过文档约定来处理。)

至于AudioFile如何访问存在的属性。它在实例上访问它,而不是在类上。一旦您使用类似于
obj=MP3File()
的东西实例化了
MP3File
,您就拥有了一个实例对象
obj
。对该对象执行
obj.ext
操作将返回其
ext
属性,或者,如果实例本身没有属性,它将在其类上(然后在其超类上)查找此类属性。每次尝试访问属性时,此属性查找都会动态进行;您不可以也不可以“predeclare”找到属性的位置(在实例、类或层次结构上的某个超类上)。因此,当
AudioFile
也是
MP3File
self.ext
时,它会在
MP3File
上找到属性,因为
self
MP3File
的一个实例


如果这本书在这一点上没有解释这一点,那么这个例子可能不是最好的。它是有效的,但是对于具有不同OO语义的其他语言的用户来说,它是如何工作的并不明显。此外,即使您确实了解Python,在现实世界中,让文档告诉您如何使用
AudioFile
(例如,说“您必须将其子类化,并且您的子类必须定义
ext
).

它无法访问
self.ext
它将抛出一个错误
AttributeError:“AudioFile”对象没有属性“ext”
我想我认为MP3File会从AudioFile继承所有函数和字段,但这会在实例化之前发生。听起来像是在说,“不,MP3File被实例化,并有一个名为
ext
的字段,因此MP3File继承了一个使用该字段的函数。对抱歉打扰了,但我想了解到底发生了什么,而不是把它归因于“Python魔法”@bclayman:基本上是的。一般来说,Python中在实例化之前发生的事情要比动态性较差的语言少得多。在Python中,在实例化之前几乎什么都不会发生。特别是,在实例化每个实例时,都会为其运行
\uuuuu init\uuuu
方法。对
self.ext
的访问发生在
\uuuu init\uuuu
中,因此在运行时,对象已经实例化。当您定义子类时,继承的东西不会静态地“复制”到子类中;继承只是指定了一个查找路径,每次尝试访问属性时都会“动态”搜索该路径。