Python 提供了完整的面向对象编程能力,将面向对象编程思想带到实际项目,可极大提高开发效率。因此,面向对象编程也是 Python 面试中必问的重要话题。
想要在 Python 项目中应用面向对象编程技术,除了掌握基本的理论概念外,还要理解 Python 对象模型、 类机制、继承与属性查找的关系、描述符以及元类等诸多知识。这些都是面试中经常考察的关键知识点。
本节精选若干典型面试题,以此抛砖引玉。
❓ 如何理解面向对象编程中的方法重写( overriding )和重载( overloading )?
请结合 Python 或其他编程语言进行说明。
方法重写 ( overriding )是指在子类中重新实现已在父类中定义的方法。
在面向对象编程语言中,子类可以继承父类中的方法,而无须重新编写相同的方法。但有时子类并不想原封不动地继承父类所有功能,想对父类中的某些方法进行修改,这就需要采用方法重写特性。方法重写不能发生在同一个类中,只能发生在子类中。
这是一个最简单的方法重写实例:
|
|
Dog 是一个普通狗类,实现了 eat 和 yelp 方法。猎犬 Sleuth 继承于 Dog 类,因此继承了父类的 eat 方法。注意到,我们对 yelp 方法进行 重写 ,以连续三个大写的 WOOF 突出猎犬铿锵有力的吠声。
这样一来,Sleuth 类继承了 Dog 中的 eat 方法,但自己的 yelp 方法覆盖了 Dog 中的相关定义:
|
|
重载 ( overloading )既可发生在同一个类的方法之间,一般称作方法重载;亦可发生在普通函数间,一般称作函数重载。这个特性允许开发人员定义名字相同,但输入参数不同的类方法或者普通函数,即同名方法/函数的不同版本。
当程序调用重载方法或函数时,编译器将根据 参数个数 及 参数类型 ,自动绑定正确的版本。由于方法/函数绑定时涉及类型检查,因此一般只有静态类型编程语言才支持重载特性。
Python 是一种动态类型编程语言,不支持方法重载,我们举一个简单的 C++ 程序作为例子:
|
|
程序定义了 print 函数,分为 3 个不同版本,分别以整型、双精度浮点以及常字符串为参数。main 函数中调用 print 函数时,编译器将根据参数类型,自动选择正确的 print 函数版本。以 print(10) 为例,由于参数 10 是一个整数,编译器可以据此推导出 void print(int i) 版本。
❓ Python 支持多继承吗?试说明多继承场景下实例对象类属性查找顺序?
Python 支持多继承,只需将基类按顺序逐一声明即可:
|
|
当子类实例对象查找某个类属性时,先在子类 Child 中查找,再按定义顺序到基类中逐个中查找。如果基类也继承于其他类的基类,Python 将沿着继承链逐级回溯,最终来到 object 。
类属性查找顺序决定程序的行为,不可不察,特别是在复杂多继承场景下。实际上,Python 类属性查找顺序是一个特殊的拓扑排序。这个拓扑排序首先是深度优先的,其次需要确保多继承基类按照定义的顺序查找。
接下来,我们构造一个多继承关系网,考察决定属性查找顺序的重要因素,例子如下:
|
|
例子涉及各个类的继承关系图如下:
子类总比父类先被搜索,因此必须满足以下关系,拓扑排序即可胜任:
- F 先于 D ;
- F 先于 E ;
- D 先于 C ;
- C 先于 A ;
- A 先于 object ;
- E 先于 A ;
- E 先于 B ;
- B 先于 object ;
而根据多继承基类列表顺序,必须保证:
- B 先于 A ;
- D 先于 E ;
因此,F 最先被搜索,接着是 D ,然后按照深度优先的原则来到 C ;由于 B 先于 A ,不能接着搜索 A ;这时只能先搜索 E 分支,然后是 B ,再到 A ;A 和 B 皆搜索过后才能搜索 object 。因此,完整的搜索顺序是这样的:
|
|
Python 完成类对象初始化后,通过 C3 算法计算类属性搜索顺序,并将其保存在 mro 属性中。我们可以据此确认推理结果:
|
|
如果规则前后矛盾,Python 将抛 TypeError 异常。这是一个典型的例子:
|
|
对于 F 类,基类 C 要求 A 先于 B 被搜索,而基类 D 要求 B 先于 A 被搜索,前后矛盾:
|
|
由于多继承存在一定的歧义性,实际项目开发一般不鼓励复杂的多继承关系。如果多继承不可避免,则需要严谨确认类属性搜索顺序。最好查看 mro 属性确认顺序符合预期,切勿想当然。
更多面试真题
❓ 试设计装饰器 mystaticmethod ,实现与 staticmethod 相同的功能
❓ Python 如何实现单例模式?试举例说明。
❓ 如果程序中有成千上万的 User 类实例对象,如何优化内存使用?
❓ 用 type 元类型创建一个等价的 MyFloat 类
上述的问题,你是否都能对答如流呢?点击 阅读原文,获取详细题解!
【Python源码剖析】系列文章首发于公众号【小菜学编程】,敬请关注: