MST

星途 面试题库

面试题:Python类结构重构与性能提升

现有一个简单的Python类如下:```pythonclass Rectangle: def __init__(self, width, height): self.width = width self.height = height def calculate_area(self): return self.width * self.height def calculate_perimeter(self): return 2 * (self.width + self.height)```如果在实际应用中发现这个类的实例化非常频繁,对性能有一定影响。请从代码重构和性能优化策略方面,提出你的改进方案,包括但不限于优化类的结构、使用合适的数据结构等,并解释这样做的原因。
19.2万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

改进方案

  1. 使用 __slots__
    • 在类中定义 __slots__ 来限制实例能够拥有的属性。因为默认情况下,Python 实例使用字典来存储属性,这会占用较多内存。而 __slots__ 可以使用更紧凑的方式存储属性,从而减少内存占用,在频繁实例化时提升性能。
    • 重构后的代码如下:
class Rectangle:
    __slots__ = ('width', 'height')
    def __init__(self, width, height):
        self.width = width
        self.height = height
    def calculate_area(self):
        return self.width * self.height
    def calculate_perimeter(self):
        return 2 * (self.width + self.height)
  1. 缓存属性值(如果适用)
    • 如果 widthheight 的值在实例的生命周期内不会改变,并且 calculate_areacalculate_perimeter 方法会被频繁调用,可以在 __init__ 方法中预先计算并缓存面积和周长。这样在调用相应方法时,直接返回缓存的值,减少计算开销。
    • 重构后的代码如下:
class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        self._area = self.width * self.height
        self._perimeter = 2 * (self.width + self.height)
    def calculate_area(self):
        return self._area
    def calculate_perimeter(self):
        return self._perimeter
  1. 考虑使用 namedtuple(如果对象是不可变的)
    • 如果 Rectangle 对象的 widthheight 在创建后不需要改变,namedtuple 是一个很好的选择。namedtuple 是不可变的,并且比普通类更轻量级,占用内存更少,创建速度更快。
    • 代码如下:
from collections import namedtuple

Rectangle = namedtuple('Rectangle', ['width', 'height'])

def calculate_area(rect):
    return rect.width * rect.height

def calculate_perimeter(rect):
    return 2 * (rect.width + rect.height)

原因解释

  1. __slots__
    • 减少内存占用,因为每个实例不再需要一个字典来存储属性。这对于频繁实例化的类来说,可以显著减少内存开销,提高内存使用效率,进而提升性能。
  2. 缓存属性值
    • 对于频繁调用的计算方法,避免了重复计算,直接返回预先计算好的值,从而提高了方法的调用速度,提升整体性能。
  3. namedtuple
    • 由于其不可变性和轻量级特性,创建 namedtuple 实例比创建普通类实例更快,并且占用更少的内存。适用于对象状态不会改变的场景,进一步优化了频繁实例化的性能。