Python面试题及详细答案150道(41-55) -- 面向对象编程篇

前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,SQL,Linux... 。

前后端面试题-专栏总目录

文章目录

  • 一、本文面试题目录
      • [41. 解释面向对象的三大特性:封装、继承、多态。](#41. 解释面向对象的三大特性:封装、继承、多态。)
      • [42. Python中如何定义类和创建对象?](#42. Python中如何定义类和创建对象?)
      • [43. 什么是`self`?它在类方法中的作用是什么?](#43. 什么是self?它在类方法中的作用是什么?)
      • [44. 类的实例方法、类方法(`@classmethod`)、静态方法(`@staticmethod`)的区别。](#44. 类的实例方法、类方法(@classmethod)、静态方法(@staticmethod)的区别。)
      • [45. 如何实现类的继承?子类如何调用父类的方法?](#45. 如何实现类的继承?子类如何调用父类的方法?)
      • [46. 什么是方法重写(Override)?](#46. 什么是方法重写(Override)?)
      • [47. 什么是抽象类(Abstract Class)?如何在Python中定义抽象类?](#47. 什么是抽象类(Abstract Class)?如何在Python中定义抽象类?)
      • [48. 什么是魔术方法(Magic Method)?举例说明几个常用的魔术方法(如`init`、`str`、`repr`)。](#48. 什么是魔术方法(Magic Method)?举例说明几个常用的魔术方法(如__init____str____repr__)。)
      • [49. `new`和`init`的区别是什么?](#49. __new____init__的区别是什么?)
      • [50. 什么是单例模式?如何在Python中实现单例模式?](#50. 什么是单例模式?如何在Python中实现单例模式?)
      • [52. 类的私有属性和私有方法如何定义?是否真的"私有"?](#52. 类的私有属性和私有方法如何定义?是否真的“私有”?)
      • [53. 什么是属性装饰器(`@property`)?如何使用?](#53. 什么是属性装饰器(@property)?如何使用?)
      • [54. 解释多继承中的MRO(方法解析顺序)。](#54. 解释多继承中的MRO(方法解析顺序)。)
      • [55. 如何判断一个对象是否是某个类的实例?(`isinstance()`和`type()`的区别)](#55. 如何判断一个对象是否是某个类的实例?(isinstance()type()的区别))
  • 二、150道Python面试题目录列表

一、本文面试题目录

41. 解释面向对象的三大特性:封装、继承、多态。

面向对象编程(OOP)的三大核心特性是封装、继承和多态,它们共同构成了面向对象设计的基础:

  1. 封装(Encapsulation)

    将数据(属性)和操作数据的方法(函数)捆绑在一起,隐藏内部实现细节,只通过公开接口与对象交互。

    • 作用:提高安全性(防止数据被意外修改)、简化使用(只需关注接口)。
      示例:
    python 复制代码
    class BankAccount:
        def __init__(self, balance):
            self.__balance = balance  # 私有属性(封装)
        
        def deposit(self, amount):
            if amount > 0:
                self.__balance += amount
        
        def get_balance(self):  # 公开接口
            return self.__balance
    
    account = BankAccount(100)
    account.deposit(50)
    print(account.get_balance())  # 150(通过接口访问)
    # print(account.__balance)  # 错误:无法直接访问私有属性
  2. 继承(Inheritance)

    子类(派生类)可以继承父类(基类)的属性和方法,并可添加新功能或重写父类方法。

    • 作用:代码复用、建立类之间的层次关系。
      示例:
    python 复制代码
    class Animal:
        def speak(self):
            pass
    
    class Dog(Animal):  # 继承Animal
        def speak(self):  # 重写父类方法
            return "Woof"
    
    class Cat(Animal):  # 继承Animal
        def speak(self):  # 重写父类方法
            return "Meow"
  3. 多态(Polymorphism)

    不同类的对象对同一方法调用可产生不同结果,即"同一接口,多种实现"。

    • 作用:提高代码灵活性和可扩展性。
      示例:
    python 复制代码
    def make_speak(animal):
        print(animal.speak())  # 同一接口,不同实现
    
    dog = Dog()
    cat = Cat()
    make_speak(dog)  # 输出:Woof
    make_speak(cat)  # 输出:Meow

42. Python中如何定义类和创建对象?

在Python中,使用class关键字定义类,通过类名加括号()创建对象(实例化)。

定义类的语法

python 复制代码
class 类名:
    # 类属性(所有实例共享)
    类变量 = 值
    
    # 构造方法(初始化实例)
    def __init__(self, 参数):
        self.实例变量 = 参数  # 实例属性
    
    # 实例方法
    def 方法名(self, 参数):
        方法体

创建对象(实例化)

python 复制代码
对象名 = 类名(参数)  # 调用__init__方法初始化

完整示例

python 复制代码
# 定义类
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是类方法中第一个参数的约定名称,代表调用该方法的实例对象本身。

作用

  1. 区分实例属性和局部变量:通过self.属性名访问或定义实例属性。
  2. 在方法中调用同一类的其他方法或属性。
  3. 标识当前对象,确保方法操作的是调用者自身的数据。

示例

python 复制代码
class Car:
    def __init__(self, color):
        self.color = color  # self区分实例属性color和参数color
    
    def 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会自动将当前对象作为第一个参数传递,无需手动传入。

    python 复制代码
    my_car.describe()  # 等价于 Car.describe(my_car)
  • 类方法(@classmethod)中使用cls代替self,代表类本身。

44. 类的实例方法、类方法(@classmethod)、静态方法(@staticmethod)的区别。

Python类中有三种方法类型,用途和特性不同:

类型 定义方式 第一个参数 访问权限 用途
实例方法 直接定义 self(实例) 可访问实例属性和类属性 操作实例数据
类方法 @classmethod装饰 cls(类) 可访问类属性,不可访问实例属性 操作类数据、创建备选构造方法
静态方法 @staticmethod装饰 无特殊参数 不可直接访问实例/类属性 提供与类相关的工具函数,逻辑独立于类数据

示例

python 复制代码
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}")
    
    # 类方法
    @classmethod
    def class_method(cls):
        print(f"类方法:访问类属性 {cls.class_attr}")
        # print(cls.instance_attr)  # 错误:类方法不能访问实例属性
    
    # 静态方法
    @staticmethod
    def 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. 如何实现类的继承?子类如何调用父类的方法?

类的继承是指子类(派生类)继承父类(基类)的属性和方法,通过在类定义时在括号中指定父类实现。

语法

python 复制代码
class 父类:
    # 父类属性和方法

class 子类(父类):  # 继承父类
    # 子类可添加新属性/方法,或重写父类方法

子类调用父类方法的方式

  1. 使用super().方法名()(推荐,尤其多继承时)。
  2. 使用父类名.方法名(self, 参数)

示例

python 复制代码
# 父类
class Animal:
    def __init__(self, name):
        self.name = name
    
    def 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(新增方法)

多继承示例

python 复制代码
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) 是指子类定义与父类同名的方法,从而覆盖父类方法的实现。子类通过重写可以修改或扩展父类方法的功能,是多态的基础。

作用

  • 使子类能够根据自身需求定制父类的方法。
  • 保持接口一致(方法名相同)但实现不同,体现多态。

示例

python 复制代码
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 = width
        self.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

重写时扩展父类功能

子类可在重写方法中调用父类方法,再添加新逻辑:

python 复制代码
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装饰器实现。

示例

python 复制代码
from abc import ABCMeta, abstractmethod

# 定义抽象类(继承ABCMeta)
class Vehicle(metaclass=ABCMeta):
    # 抽象方法(必须被子类实现)
    @abstractmethod
    def start(self):
        pass
    
    # 抽象方法
    @abstractmethod
    def 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, ...) :构造方法

对象实例化时自动调用,用于初始化实例属性。

python 复制代码
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person("Alice", 30)  # 自动调用__init__

2.__str__(self) :字符串表示

当使用str(obj)print(obj)时调用,返回可读性高的字符串。

python 复制代码
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __str__(self):
        return f"Person: {self.name}, {self.age}岁"

p = Person("Alice", 30)
print(p)  # 自动调用__str__ → Person: Alice, 30岁

3.__repr__(self) :官方字符串表示

当使用repr(obj)时调用,返回用于调试的官方字符串(通常可用于重建对象)。

python 复制代码
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __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)时调用,返回对象的"长度"。

python 复制代码
class MyList:
    def __init__(self, items):
        self.items = items
    
    def __len__(self):
        return len(self.items)

ml = MyList([1, 2, 3])
print(len(ml))  # 自动调用__len__ → 3

5.__add__(self, other) :加法运算符重载

当使用obj1 + obj2时调用,定义对象的加法行为。

python 复制代码
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __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__之后)调用
使用场景 控制实例创建过程(如单例模式) 初始化实例属性

示例

python 复制代码
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__的特殊用途

  1. 单例模式:确保类只有一个实例

    python 复制代码
    class Singleton:
        _instance = None
        
        def __new__(cls):
            if cls._instance is None:
                cls._instance = super().__new__(cls)
            return cls._instance
    
    a = Singleton()
    b = Singleton()
    print(a is b)  # True(a和b是同一实例)
  2. 不可变类的子类化 :如自定义intstr等不可变类型

    python 复制代码
    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__方法 **(最常用)

python 复制代码
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设计原则

  1. 单一职责:每个Mixin类专注于一组相关功能。
  2. 不单独实例化:Mixin类仅用于被继承,自身不创建实例。
  3. 依赖约定 :Mixin类通常假设被继承的类有特定属性或方法(如示例中假设存在name属性)。
  4. 命名规范 :Mixin类名通常以Mixin结尾,明确其用途。

应用场景

  • 为类添加通用功能(如日志、缓存、序列化)。
  • 在框架中扩展组件功能(如Django的LoginRequiredMixin)。

示例:Django中的Mixin

python 复制代码
# Django视图中使用Mixin添加登录验证
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView

class MyView(LoginRequiredMixin, TemplateView):
    template_name = "my_template.html"
    # 未登录用户会被重定向到登录页(功能来自LoginRequiredMixin)

52. 类的私有属性和私有方法如何定义?是否真的"私有"?

在Python中,通过在属性或方法名前加双下划线__定义私有属性和私有方法,目的是限制外部直接访问。

定义方式

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()}"

外部访问限制

python 复制代码
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,可通过该名称在外部访问。
python 复制代码
# 间接访问私有成员(不推荐)
print(obj._MyClass__private_attr)    # 私有属性
print(obj._MyClass__private_method())  # 私有方法

总结

  • 私有成员的目的是"约定"而非强制限制,提醒开发者不要外部访问。
  • 名称修饰是一种保护机制,防止子类意外覆盖父类的私有成员。
  • 通常使用单下划线_表示"受保护"成员(约定不外部访问,无实际限制)。

53. 什么是属性装饰器(@property)?如何使用?

@property是Python的装饰器,用于将类的方法转换为属性,使方法可以像属性一样被访问(无需加括号调用)。

作用

  • 提供统一的属性访问接口,隐藏内部实现细节。
  • 允许在获取/设置属性时添加逻辑(如验证、计算)。
  • 使代码更简洁,符合"开放-封闭"原则。

基本用法

python 复制代码
class Person:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name
    
    # 定义属性:full_name
    @property
    def full_name(self):
        # 计算属性值
        return f"{self.first_name} {self.last_name}"

person = Person("John", "Doe")
print(person.full_name)  # 像属性一样访问,无需加括号 → John Doe

带设置器(Setter)和删除器(Deleter)

python 复制代码
class Person:
    def __init__(self, age):
        self._age = age  # 用单下划线表示受保护属性
    
    #  getter:获取属性值
    @property
    def age(self):
        return self._age
    
    #  setter:设置属性值(需与属性同名)
    @age.setter
    def age(self, value):
        # 添加验证逻辑
        if value < 0 or value > 120:
            raise ValueError("年龄必须在0-120之间")
        self._age = value
    
    #  deleter:删除属性
    @age.deleter
    def age(self):
        print("删除年龄属性")
        del self._age

person = Person(30)
print(person.age)  # 30(调用getter)

person.age = 35    # 调用setter
print(person.age)  # 35

# person.age = 150  # 报错:ValueError

del person.age     # 调用deleter

应用场景

  1. 计算属性 :如示例中的full_name,值由其他属性计算而来。
  2. 属性验证:在设置属性时检查值的合法性(如年龄范围)。
  3. 兼容旧接口:当需要将方法改为属性时,不破坏现有代码。
  4. 延迟计算:属性值在第一次访问时才计算,提高性能。

@property使属性访问既简洁又灵活,是Python面向对象编程中封装的重要工具。

54. 解释多继承中的MRO(方法解析顺序)。

MRO(Method Resolution Order,方法解析顺序) 是Python在多继承中确定方法调用顺序的规则,用于解决多个父类中存在同名方法时的调用冲突。

为什么需要MRO?

在多继承中,若多个父类有同名方法,MRO决定了子类调用该方法时的搜索顺序。

Python的MRO规则

Python 3使用"C3线性化"算法,遵循以下原则:

  1. 子类优先于父类:子类的方法优先于父类。
  2. 同一层级的父类按继承顺序搜索class C(A, B)中A优先于B。
  3. 保持父类的MRO顺序:确保父类的方法搜索顺序不变。

查看MRO的方式

  • 通过类的__mro__属性。
  • 通过cls.mro()方法。

示例

python 复制代码
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)

复杂多继承示例

python 复制代码
class X:
    def method(self):
        print("X.method")

class Y:
    def method(self):
        print("Y.method")

class A(X, Y):
    pass

class B(Y, X):
    pass

class C(A, B):
    pass

print(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实际类型(类对象),可用于类型比较。

示例

python 复制代码
class Animal:
    pass

class Dog(Animal):  # Dog是Animal的子类
    pass

dog = 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(),因为它支持多态,更符合面向对象思想。

    python 复制代码
    def feed(animal):
        if isinstance(animal, Animal):  # 接受所有Animal子类
            print("Feeding the animal")
  • 精确类型判断 :当需要严格区分子类和父类时,使用type()

    python 复制代码
    def get_type_name(obj):
        return type(obj).__name__  # 返回实际类型的名称

注意

  • 不要过度使用类型检查,Python更倾向于"鸭子类型"(关注对象行为而非类型)。

  • isinstance()的第二个参数可以是元组,检查对象是否是其中任一类型的实例:

    python 复制代码
    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)
相关推荐
小五1275 分钟前
数据科学与计算实例应用
开发语言·python
站大爷IP15 分钟前
Python类型注解:让代码“开口说话”的隐形助手
python
站大爷IP41 分钟前
Python多态实战:从基础到高阶的“魔法”应用指南
python
码界筑梦坊1 小时前
108-基于Python的中国古诗词数据可视化分析系统
python·信息可视化·数据分析·django·毕业设计·numpy
紫金修道1 小时前
python安装部署rknn-toolkit2(ModuleNotFoundError: No module named ‘rknn_toolkit2‘)
开发语言·python
何以问天涯3 小时前
K210人脸识别系统
人工智能·python·嵌入式硬件·ai编程
Juchecar3 小时前
TypeScript 中字符串与数值、日期时间的相互转换
javascript·python
Juchecar4 小时前
在TypeScript中如何实现Python中常用的dict类型及操作
javascript·python
Juchecar4 小时前
TypeScript 中字符串格式化及数值对齐的实现
javascript·python