Python面试题及详细答案150道(41-55) -- 面向对象编程篇
《前后端面试题
》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,SQL,Linux… 。
文章目录
- 一、本文面试题目录
- 41. 解释面向对象的三大特性:封装、继承、多态。
- 42. Python中如何定义类和创建对象?
- 43. 什么是`self`?它在类方法中的作用是什么?
- 44. 类的实例方法、类方法(`@classmethod`)、静态方法(`@staticmethod`)的区别。
- 45. 如何实现类的继承?子类如何调用父类的方法?
- 46. 什么是方法重写(Override)?
- 47. 什么是抽象类(Abstract Class)?如何在Python中定义抽象类?
- 48. 什么是魔术方法(Magic Method)?举例说明几个常用的魔术方法(如`__init__`、`__str__`、`__repr__`)。
- 49. `__new__`和`__init__`的区别是什么?
- 50. 什么是单例模式?如何在Python中实现单例模式?
- 52. 类的私有属性和私有方法如何定义?是否真的“私有”?
- 53. 什么是属性装饰器(`@property`)?如何使用?
- 54. 解释多继承中的MRO(方法解析顺序)。
- 55. 如何判断一个对象是否是某个类的实例?(`isinstance()`和`type()`的区别)
- 二、150道Python面试题目录列表
一、本文面试题目录
41. 解释面向对象的三大特性:封装、继承、多态。
面向对象编程(OOP)的三大核心特性是封装、继承和多态,它们共同构成了面向对象设计的基础:
-
封装(Encapsulation)
将数据(属性)和操作数据的方法(函数)捆绑在一起,隐藏内部实现细节,只通过公开接口与对象交互。- 作用:提高安全性(防止数据被意外修改)、简化使用(只需关注接口)。
示例:
class BankAccount:def __init__(self, balance):self.__balance = balance # 私有属性(封装)def deposit(self, amount):if amount > 0:self.__balance += amountdef get_balance(self): # 公开接口return self.__balanceaccount = BankAccount(100) account.deposit(50) print(account.get_balance()) # 150(通过接口访问) # print(account.__balance) # 错误:无法直接访问私有属性
- 作用:提高安全性(防止数据被意外修改)、简化使用(只需关注接口)。
-
继承(Inheritance)
子类(派生类)可以继承父类(基类)的属性和方法,并可添加新功能或重写父类方法。- 作用:代码复用、建立类之间的层次关系。
示例:
class Animal:def speak(self):passclass Dog(Animal): # 继承Animaldef speak(self): # 重写父类方法return "Woof"class Cat(Animal): # 继承Animaldef speak(self): # 重写父类方法return "Meow"
- 作用:代码复用、建立类之间的层次关系。
-
多态(Polymorphism)
不同类的对象对同一方法调用可产生不同结果,即“同一接口,多种实现”。- 作用:提高代码灵活性和可扩展性。
示例:
def make_speak(animal):print(animal.speak()) # 同一接口,不同实现dog = Dog() cat = Cat() make_speak(dog) # 输出:Woof make_speak(cat) # 输出:Meow
- 作用:提高代码灵活性和可扩展性。
42. Python中如何定义类和创建对象?
在Python中,使用class
关键字定义类,通过类名加括号()
创建对象(实例化)。
定义类的语法:
class 类名:# 类属性(所有实例共享)类变量 = 值# 构造方法(初始化实例)def __init__(self, 参数):self.实例变量 = 参数 # 实例属性# 实例方法def 方法名(self, 参数):方法体
创建对象(实例化):
对象名 = 类名(参数) # 调用__init__方法初始化
完整示例:
# 定义类
class Person:# 类属性(所有Person共享)species = "Homo sapiens"# 构造方法:初始化实例属性def __init__(self, name, age):self.name = name # 实例属性self.age = age # 实例属性# 实例方法def greet(self):return f"Hello, my name is {self.name}"# 创建对象(实例化)
person1 = Person("Alice", 30)
person2 = Person("Bob", 25)# 访问实例属性和方法
print(person1.name) # Alice
print(person1.greet()) # Hello, my name is Alice# 访问类属性
print(person1.species) # Homo sapiens
print(Person.species) # Homo sapiens(通过类名访问)
说明:
__init__
是构造方法,在创建对象时自动调用,用于初始化实例属性。- 实例属性通过
self.属性名
定义,每个对象有独立的实例属性。 - 类属性属于类本身,所有实例共享同一类属性。
43. 什么是self
?它在类方法中的作用是什么?
self
是类方法中第一个参数的约定名称,代表调用该方法的实例对象本身。
作用:
- 区分实例属性和局部变量:通过
self.属性名
访问或定义实例属性。 - 在方法中调用同一类的其他方法或属性。
- 标识当前对象,确保方法操作的是调用者自身的数据。
示例:
class Car:def __init__(self, color):self.color = color # self区分实例属性color和参数colordef describe(self):# self访问实例属性return f"This car is {self.color}"def repaint(self, new_color):self.color = new_color# self调用同一类的其他方法return self.describe()my_car = Car("red")
print(my_car.describe()) # This car is red
print(my_car.repaint("blue")) # This car is blue
注意:
self
不是Python的关键字,只是约定名称,理论上可替换为其他名称,但不推荐。- 调用实例方法时,Python会自动将当前对象作为第一个参数传递,无需手动传入。
my_car.describe() # 等价于 Car.describe(my_car)
- 类方法(
@classmethod
)中使用cls
代替self
,代表类本身。
44. 类的实例方法、类方法(@classmethod
)、静态方法(@staticmethod
)的区别。
Python类中有三种方法类型,用途和特性不同:
类型 | 定义方式 | 第一个参数 | 访问权限 | 用途 |
---|---|---|---|---|
实例方法 | 直接定义 | self (实例) | 可访问实例属性和类属性 | 操作实例数据 |
类方法 | 用@classmethod 装饰 | cls (类) | 可访问类属性,不可访问实例属性 | 操作类数据、创建备选构造方法 |
静态方法 | 用@staticmethod 装饰 | 无特殊参数 | 不可直接访问实例/类属性 | 提供与类相关的工具函数,逻辑独立于类数据 |
示例:
class MyClass:class_attr = "类属性" # 类属性def __init__(self, instance_attr):self.instance_attr = instance_attr # 实例属性# 实例方法def instance_method(self):print(f"实例方法:访问实例属性 {self.instance_attr},类属性 {self.class_attr}")# 类方法@classmethoddef class_method(cls):print(f"类方法:访问类属性 {cls.class_attr}")# print(cls.instance_attr) # 错误:类方法不能访问实例属性# 静态方法@staticmethoddef static_method(x, y):print(f"静态方法:计算结果 {x + y}")# print(self.instance_attr) # 错误:静态方法无self# print(cls.class_attr) # 错误:静态方法无cls# 使用示例
obj = MyClass("实例属性")# 调用实例方法
obj.instance_method() # 实例方法:访问实例属性 实例属性,类属性 类属性# 调用类方法(可通过实例或类调用)
obj.class_method() # 类方法:访问类属性 类属性
MyClass.class_method() # 类方法:访问类属性 类属性# 调用静态方法(可通过实例或类调用)
obj.static_method(2, 3) # 静态方法:计算结果 5
MyClass.static_method(4, 5) # 静态方法:计算结果 9
总结:
- 实例方法:依赖实例状态,用于对象的具体操作。
- 类方法:依赖类状态,常用于创建工厂方法或操作类级别的数据。
- 静态方法:独立于类和实例,更像类内部的普通函数,用于逻辑上与类相关的工具功能。
45. 如何实现类的继承?子类如何调用父类的方法?
类的继承是指子类(派生类)继承父类(基类)的属性和方法,通过在类定义时在括号中指定父类实现。
语法:
class 父类:# 父类属性和方法class 子类(父类): # 继承父类# 子类可添加新属性/方法,或重写父类方法
子类调用父类方法的方式:
- 使用
super().方法名()
(推荐,尤其多继承时)。 - 使用
父类名.方法名(self, 参数)
。
示例:
# 父类
class Animal:def __init__(self, name):self.name = namedef speak(self):return "Animal sound"# 子类继承父类
class Dog(Animal):def __init__(self, name, breed):# 调用父类的__init__方法super().__init__(name) # 方式1:super()# Animal.__init__(self, name) # 方式2:父类名self.breed = breed # 子类新增属性# 重写父类方法def speak(self):return "Woof"# 子类新增方法def fetch(self):return f"{self.name} is fetching"# 使用子类
dog = Dog("Buddy", "Golden Retriever")
print(dog.name) # Buddy(继承自父类的属性)
print(dog.breed) # Golden Retriever(子类新增属性)
print(dog.speak()) # Woof(重写的方法)
print(dog.fetch()) # Buddy is fetching(新增方法)
多继承示例:
class Flyable:def fly(self):return "Flying"class Bird(Animal, Flyable): # 继承多个父类def speak(self):return "Chirp"bird = Bird("Tweety")
print(bird.speak()) # Chirp(重写Animal的方法)
print(bird.fly()) # Flying(继承Flyable的方法)
说明:
- 子类可继承父类的所有非私有属性和方法。
super()
在单继承中指向父类,在多继承中遵循MRO(方法解析顺序)。- 多继承时,父类之间用逗号分隔。
46. 什么是方法重写(Override)?
方法重写(Method Override) 是指子类定义与父类同名的方法,从而覆盖父类方法的实现。子类通过重写可以修改或扩展父类方法的功能,是多态的基础。
作用:
- 使子类能够根据自身需求定制父类的方法。
- 保持接口一致(方法名相同)但实现不同,体现多态。
示例:
class Shape:# 父类方法def area(self):raise NotImplementedError("子类必须重写area方法")# 子类重写父类方法
class Circle(Shape):def __init__(self, radius):self.radius = radius# 重写area方法def area(self):return 3.14 * self.radius **2# 子类重写父类方法
class Rectangle(Shape):def __init__(self, width, height):self.width = widthself.height = height# 重写area方法def area(self):return self.width * self.height# 多态体现:同一方法名,不同实现
shapes = [Circle(5), Rectangle(4, 6)]
for shape in shapes:print(f"面积:{shape.area()}") # 分别调用子类的area方法# 输出:
# 面积:78.5
# 面积:24
重写时扩展父类功能:
子类可在重写方法中调用父类方法,再添加新逻辑:
class Parent:def greet(self):return "Hello from Parent"class Child(Parent):def greet(self):# 调用父类方法parent_greeting = super().greet()# 扩展功能return f"{parent_greeting}\nHello from Child"child = Child()
print(child.greet())
# 输出:
# Hello from Parent
# Hello from Child
注意:
- 重写方法的参数列表应与父类保持一致(或兼容),否则可能导致调用错误。
- 如果父类方法是抽象方法(如示例中的
Shape.area
),子类必须重写该方法,否则实例化会报错。
47. 什么是抽象类(Abstract Class)?如何在Python中定义抽象类?
抽象类(Abstract Class) 是一种不能被实例化的类,用于定义子类必须实现的接口(方法)。抽象类可以包含抽象方法(只有声明没有实现)和具体方法(有实现)。
作用:
- 强制子类遵循统一的接口规范(必须实现抽象方法)。
- 作为多个子类的基类,提取公共逻辑。
在Python中定义抽象类:
需通过abc
模块(Abstract Base Classes)的ABCMeta
元类和@abstractmethod
装饰器实现。
示例:
from abc import ABCMeta, abstractmethod# 定义抽象类(继承ABCMeta)
class Vehicle(metaclass=ABCMeta):# 抽象方法(必须被子类实现)@abstractmethoddef start(self):pass# 抽象方法@abstractmethoddef stop(self):pass# 具体方法(可被继承或重写)def honk(self):return "Honking!"# 子类必须实现所有抽象方法
class Car(Vehicle):def start(self):return "Car started"def stop(self):return "Car stopped"class Bike(Vehicle):def start(self):return "Bike started"def stop(self):return "Bike stopped"# 使用子类
car = Car()
print(car.start()) # Car started
print(car.honk()) # Honking!bike = Bike()
print(bike.start()) # Bike started# 错误:抽象类不能实例化
# vehicle = Vehicle() # TypeError: Can't instantiate abstract class Vehicle with abstract methods start, stop# 错误:子类未实现所有抽象方法
class Truck(Vehicle):def start(self):return "Truck started"# 未实现stop()方法# truck = Truck() # TypeError: Can't instantiate abstract class Truck with abstract method stop
说明:
- 抽象类不能直接实例化,必须通过子类实例化。
- 子类必须实现抽象类中的所有抽象方法,否则子类仍为抽象类,无法实例化。
- 抽象类可以包含具体方法,提供子类可复用的功能。
48. 什么是魔术方法(Magic Method)?举例说明几个常用的魔术方法(如__init__
、__str__
、__repr__
)。
魔术方法(Magic Method) 是Python中以双下划线__
开头和结尾的特殊方法,用于定义类的行为(如初始化、字符串表示、运算符重载等)。它们会在特定场景下自动调用,无需手动调用。
常用魔术方法示例:
1.__init__(self, ...)
:构造方法
对象实例化时自动调用,用于初始化实例属性。
class Person:def __init__(self, name, age):self.name = nameself.age = agep = Person("Alice", 30) # 自动调用__init__
2.__str__(self)
:字符串表示
当使用str(obj)
或print(obj)
时调用,返回可读性高的字符串。
class Person:def __init__(self, name, age):self.name = nameself.age = agedef __str__(self):return f"Person: {self.name}, {self.age}岁"p = Person("Alice", 30)
print(p) # 自动调用__str__ → Person: Alice, 30岁
3.__repr__(self)
:官方字符串表示
当使用repr(obj)
时调用,返回用于调试的官方字符串(通常可用于重建对象)。
class Person:def __init__(self, name, age):self.name = nameself.age = agedef __repr__(self):return f"Person('{self.name}', {self.age})"p = Person("Alice", 30)
print(repr(p)) # 输出:Person('Alice', 30)
注:如果未定义__str__
,print(obj)
会使用__repr__
的结果。
4.__len__(self)
:长度计算
当使用len(obj)
时调用,返回对象的“长度”。
class MyList:def __init__(self, items):self.items = itemsdef __len__(self):return len(self.items)ml = MyList([1, 2, 3])
print(len(ml)) # 自动调用__len__ → 3
5.__add__(self, other)
:加法运算符重载
当使用obj1 + obj2
时调用,定义对象的加法行为。
class Point:def __init__(self, x, y):self.x = xself.y = ydef __add__(self, other):return Point(self.x + other.x, self.y + other.y)def __str__(self):return f"({self.x}, {self.y})"p1 = Point(1, 2)
p2 = Point(3, 4)
p3 = p1 + p2 # 自动调用__add__
print(p3) # (4, 6)
其他常用魔术方法:
__eq__(self, other)
:定义==
运算符行为。__getitem__(self, key)
:定义obj[key]
索引访问。__call__(self, ...)
:使对象可像函数一样被调用(obj()
)。
49. __new__
和__init__
的区别是什么?
__new__
和__init__
都是Python中的魔术方法,与对象创建相关,但作用和调用时机不同:
特性 | __new__ | __init__ |
---|---|---|
作用 | 创建对象(实例化),返回新对象 | 初始化对象,设置实例属性 |
第一个参数 | cls (类本身) | self (已创建的实例) |
返回值 | 必须返回一个实例(通常是cls 的实例) | 无返回值(None ) |
调用时机 | 在对象创建前调用 | 在对象创建后(__new__ 之后)调用 |
使用场景 | 控制实例创建过程(如单例模式) | 初始化实例属性 |
示例:
class MyClass:def __new__(cls, *args, **kwargs):print("__new__被调用,创建对象")# 调用父类的__new__创建实例instance = super().__new__(cls)return instance # 必须返回实例def __init__(self, value):print("__init__被调用,初始化对象")self.value = value # 设置实例属性# 创建对象的过程
obj = MyClass(10)
# 输出:
# __new__被调用,创建对象
# __init__被调用,初始化对象print(obj.value) # 10
__new__
的特殊用途:
-
单例模式:确保类只有一个实例
class Singleton:_instance = Nonedef __new__(cls):if cls._instance is None:cls._instance = super().__new__(cls)return cls._instancea = Singleton() b = Singleton() print(a is b) # True(a和b是同一实例)
-
不可变类的子类化:如自定义
int
、str
等不可变类型class PositiveInt(int):def __new__(cls, value):# 确保值为正数if value <= 0:raise ValueError("必须是正数")return super().__new__(cls, value)num = PositiveInt(10) # num2 = PositiveInt(-5) # 报错:ValueError
总结:
__new__
负责“创建”对象,是类级别的方法。__init__
负责“初始化”对象,是实例级别的方法。- 多数情况下只需重写
__init__
,__new__
仅在需要控制实例创建时使用。
50. 什么是单例模式?如何在Python中实现单例模式?
单例模式(Singleton Pattern) 是一种设计模式,确保一个类只能创建一个实例,并提供全局访问点。
应用场景:
- 配置管理(全局唯一配置)
- 日志记录器(避免多个日志实例冲突)
- 数据库连接池(控制连接数量)
Python中实现单例模式的方法:
1.** 使用__new__
方法 **(最常用)
class Singleton:_instance = None # 存储唯一实例def __new__(cls, *args, **kwargs):# 如果实例不存在,则创建if not cls._instance:cls._instance = super().__new__(cls)return cls._instance# 测试
s1 = Singleton()
s2 = Singleton()
print(s1 is s2) # True(同一实例)
2.** 使用装饰器 **```python
def singleton(cls):
instances = {} # 缓存实例
def wrapper(*args, **kwargs):if cls not in instances:instances[cls] = cls(*args, **kwargs)return instances[cls]return wrapper
@singleton
class MyClass:
pass
测试
m1 = MyClass()
m2 = MyClass()
print(m1 is m2) # True
3.** 使用模块 **(Python特有,最简单)
Python模块在第一次导入时执行,后续导入直接引用已加载的模块对象,天然是单例。
```python
# singleton_module.py
class Singleton:def some_method(self):return "This is a singleton"# 创建唯一实例
instance = Singleton()# 使用方式
# from singleton_module import instance
# a = instance
# b = instance
# print(a is b) # True
4.** 使用元类(Metaclass)**```python
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):if cls not in cls._instances:cls._instances[cls] = super().__call__(*args, **kwargs)return cls._instances[cls]
应用元类
class MySingleton(metaclass=SingletonMeta):
pass
测试
s1 = MySingleton()
s2 = MySingleton()
print(s1 is s2) # True
**注意**:
- 单例模式可能导致全局状态,增加代码耦合度,应谨慎使用。
- 在多线程环境下,需添加线程锁确保单例安全性。### 51. 什么是Mixin模式?它的作用是什么?**Mixin模式**(混合模式)是一种通过多继承复用类功能的设计模式。Mixin类是包含一组可复用方法的类,本身不单独实例化,而是被其他类继承以扩展功能。**作用**:
- 实现代码复用,避免重复编写相同功能。
- 灵活组合功能,无需复杂的继承层次。
- 解决单继承的局限性,实现“多继承”的优势而避免其复杂性。**示例**:
```python
# Mixin类:提供飞行功能
class FlyableMixin:def fly(self):return f"{self.name} is flying"# Mixin类:提供游泳功能
class SwimmableMixin:def swim(self):return f"{self.name} is swimming"# 基础类
class Animal:def __init__(self, name):self.name = name# 继承基础类和Mixin类,组合功能
class Duck(Animal, FlyableMixin, SwimmableMixin):def quack(self):return "Quack!"# 使用
duck = Duck("Donald")
print(duck.quack()) # Quack!(自身方法)
print(duck.fly()) # Donald is flying(来自FlyableMixin)
print(duck.swim()) # Donald is swimming(来自SwimmableMixin)
Mixin设计原则:
- 单一职责:每个Mixin类专注于一组相关功能。
- 不单独实例化:Mixin类仅用于被继承,自身不创建实例。
- 依赖约定:Mixin类通常假设被继承的类有特定属性或方法(如示例中假设存在
name
属性)。 - 命名规范:Mixin类名通常以
Mixin
结尾,明确其用途。
应用场景:
- 为类添加通用功能(如日志、缓存、序列化)。
- 在框架中扩展组件功能(如Django的
LoginRequiredMixin
)。
示例:Django中的Mixin
# Django视图中使用Mixin添加登录验证
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateViewclass MyView(LoginRequiredMixin, TemplateView):template_name = "my_template.html"# 未登录用户会被重定向到登录页(功能来自LoginRequiredMixin)
52. 类的私有属性和私有方法如何定义?是否真的“私有”?
在Python中,通过在属性或方法名前加双下划线__
定义私有属性和私有方法,目的是限制外部直接访问。
定义方式:
class MyClass:def __init__(self):self.public_attr = "公共属性"self.__private_attr = "私有属性" # 私有属性def public_method(self):return "公共方法"def __private_method(self): # 私有方法return "私有方法"def access_private(self):# 类内部可访问私有属性和方法return f"{self.__private_attr}, {self.__private_method()}"
外部访问限制:
obj = MyClass()# 访问公共成员
print(obj.public_attr) # 公共属性
print(obj.public_method()) # 公共方法# 直接访问私有成员会报错
# print(obj.__private_attr) # AttributeError
# print(obj.__private_method()) # AttributeError# 类内部可访问私有成员
print(obj.access_private()) # 私有属性, 私有方法
是否真的“私有”?
Python的私有机制是通过“名称修饰(Name Mangling)”实现的,并非真正的私有:
- 解释器会将私有成员名
__name
修改为_类名__name
,可通过该名称在外部访问。
# 间接访问私有成员(不推荐)
print(obj._MyClass__private_attr) # 私有属性
print(obj._MyClass__private_method()) # 私有方法
总结:
- 私有成员的目的是“约定”而非强制限制,提醒开发者不要外部访问。
- 名称修饰是一种保护机制,防止子类意外覆盖父类的私有成员。
- 通常使用单下划线
_
表示“受保护”成员(约定不外部访问,无实际限制)。
53. 什么是属性装饰器(@property
)?如何使用?
@property
是Python的装饰器,用于将类的方法转换为属性,使方法可以像属性一样被访问(无需加括号调用)。
作用:
- 提供统一的属性访问接口,隐藏内部实现细节。
- 允许在获取/设置属性时添加逻辑(如验证、计算)。
- 使代码更简洁,符合“开放-封闭”原则。
基本用法:
class Person:def __init__(self, first_name, last_name):self.first_name = first_nameself.last_name = last_name# 定义属性:full_name@propertydef full_name(self):# 计算属性值return f"{self.first_name} {self.last_name}"person = Person("John", "Doe")
print(person.full_name) # 像属性一样访问,无需加括号 → John Doe
带设置器(Setter)和删除器(Deleter):
class Person:def __init__(self, age):self._age = age # 用单下划线表示受保护属性# getter:获取属性值@propertydef age(self):return self._age# setter:设置属性值(需与属性同名)@age.setterdef age(self, value):# 添加验证逻辑if value < 0 or value > 120:raise ValueError("年龄必须在0-120之间")self._age = value# deleter:删除属性@age.deleterdef age(self):print("删除年龄属性")del self._ageperson = Person(30)
print(person.age) # 30(调用getter)person.age = 35 # 调用setter
print(person.age) # 35# person.age = 150 # 报错:ValueErrordel person.age # 调用deleter
应用场景:
- 计算属性:如示例中的
full_name
,值由其他属性计算而来。 - 属性验证:在设置属性时检查值的合法性(如年龄范围)。
- 兼容旧接口:当需要将方法改为属性时,不破坏现有代码。
- 延迟计算:属性值在第一次访问时才计算,提高性能。
@property
使属性访问既简洁又灵活,是Python面向对象编程中封装的重要工具。
54. 解释多继承中的MRO(方法解析顺序)。
MRO(Method Resolution Order,方法解析顺序) 是Python在多继承中确定方法调用顺序的规则,用于解决多个父类中存在同名方法时的调用冲突。
为什么需要MRO?
在多继承中,若多个父类有同名方法,MRO决定了子类调用该方法时的搜索顺序。
Python的MRO规则:
Python 3使用“C3线性化”算法,遵循以下原则:
- 子类优先于父类:子类的方法优先于父类。
- 同一层级的父类按继承顺序搜索:
class C(A, B)
中A优先于B。 - 保持父类的MRO顺序:确保父类的方法搜索顺序不变。
查看MRO的方式:
- 通过类的
__mro__
属性。 - 通过
cls.mro()
方法。
示例:
class A:def method(self):print("A.method")class B(A):def method(self):print("B.method")class C(A):def method(self):print("C.method")class D(B, C):pass # 继承B和C# 查看D的MRO
print(D.__mro__)
# 输出:(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)# 调用method(),按MRO顺序搜索
d = D()
d.method() # 输出:B.method(D→B→C→A→object)
复杂多继承示例:
class X:def method(self):print("X.method")class Y:def method(self):print("Y.method")class A(X, Y):passclass B(Y, X):passclass C(A, B):passprint(C.mro())
# 输出:[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.X'>, <class '__main__.B'>, <class '__main__.Y'>, <class 'object'>]c = C()
c.method() # 输出:X.method(按MRO顺序找到A→X的method)
注意:
- MRO确保每个类只被访问一次。
- 多继承可能导致MRO复杂,应尽量避免过深的多继承层次。
- 可通过
super()
函数按MRO顺序调用父类方法。
55. 如何判断一个对象是否是某个类的实例?(isinstance()
和type()
的区别)
在Python中,可通过isinstance()
和type()
判断对象类型,但二者有重要区别:
1.isinstance(obj, cls)
:
判断对象obj
是否是类cls
或其子类的实例,返回布尔值。
2.type(obj)
:
返回对象obj
的实际类型(类对象),可用于类型比较。
示例:
class Animal:passclass Dog(Animal): # Dog是Animal的子类passdog = Dog()# 使用isinstance()
print(isinstance(dog, Dog)) # True(是Dog的实例)
print(isinstance(dog, Animal)) # True(是父类Animal的实例)
print(isinstance(dog, object)) # True(所有类都继承自object)# 使用type()
print(type(dog) is Dog) # True(实际类型是Dog)
print(type(dog) is Animal) # False(实际类型不是Animal)
print(type(dog)) # <class '__main__.Dog'>(返回类型对象)
关键区别:
isinstance()
考虑继承关系(子类实例也是父类的实例)。type()
只检查对象的实际类型,不考虑继承关系。
使用场景:
-
类型检查:优先使用
isinstance()
,因为它支持多态,更符合面向对象思想。def feed(animal):if isinstance(animal, Animal): # 接受所有Animal子类print("Feeding the animal")
-
精确类型判断:当需要严格区分子类和父类时,使用
type()
。def get_type_name(obj):return type(obj).__name__ # 返回实际类型的名称
注意:
- 不要过度使用类型检查,Python更倾向于“鸭子类型”(关注对象行为而非类型)。
isinstance()
的第二个参数可以是元组,检查对象是否是其中任一类型的实例:print(isinstance(5, (int, float))) # True(5是int类型)
二、150道Python面试题目录列表
文章序号 | Python面试题150道 |
---|---|
1 | Python面试题及详细答案150道(01-15) |
2 | Python面试题及详细答案150道(16-30) |
3 | Python面试题及详细答案150道(31-40) |
4 | Python面试题及详细答案150道(41-55) |
5 | Python面试题及详细答案150道(56-70) |
6 | Python面试题及详细答案150道(71-80) |
7 | Python面试题及详细答案150道(81-90) |
8 | Python面试题及详细答案150道(91-100) |
9 | Python面试题及详细答案150道(101-115) |
10 | Python面试题及详细答案150道(116-125) |
11 | Python面试题及详细答案150道(126-135) |
12 | Python面试题及详细答案150道(136-150) |