第69篇 Python面向对象:面试官问“Python的类和C++有什么区别”,这些差异你得说清楚

📅 2026/8/19 14:23:01
第69篇 Python面向对象:面试官问“Python的类和C++有什么区别”,这些差异你得说清楚
上篇聊了Python的四个内置数据结构的选型。今天说Python的面向对象编程重点是从C的视角来看两者的差异。面试的时候Python的类和C有什么区别是一个常见的对比题。如果你只能说出Python不用声明类型这种表面差异说明理解还不够深。先说个事。我之前带一个实习生C写得不错转到Python之后写出来的类完全是C风格每个属性都配getter/setter构造函数里初始化所有成员变量到处写private。我看了之后跟他说Python不是这么玩的。他很委屈C里不就是这样吗这就是问题所在。Python的面向对象和C有很多设计哲学上的差异。理解了这些差异你才能写出地道的Python代码而不是C味的Python。差异一没有真正的访问控制C有public、private、protected三个访问修饰符编译器会强制执行。Python没有这些——所有属性和方法在技术上都是可访问的。Python的私有靠命名约定class Sensor: def __init__(self): self.name lidar # 公开 self._status idle # 约定为私有但实际可访问 self.__serial ABC123 # 名称改写name mangling单下划线_status是一种君子协定——告诉其他开发者这是内部实现别直接用。但Python不会阻止你访问它。双下划线__serial会触发名称改写变成_Sensor__serial增加了访问难度但依然不是真正的私有。面试的时候如果被追问为什么Python不强制私有可以引用Python社区的一句话We are all consenting adults here.Python的设计哲学是信任开发者而不是用编译器限制你。差异二属性直接访问不需要getter/setterC里好的实践是把属性设为private通过getter/setter访问。Python里直接暴露属性是正常做法# C风格不推荐 class Sensor: def get_range(self): return self._range def set_range(self, value): if value 0: self._range value # Python风格推荐 class Sensor: def __init__(self): self.range 30.0 # 直接访问如果以后需要在赋值时加逻辑Python提供了property装饰器可以在不改变外部接口的前提下加入验证逻辑class Sensor: property def range(self): return self._range range.setter def range(self, value): if value 0: raise ValueError(Range must be positive) self._range value s Sensor() s.range 50.0 # 调用setter print(s.range) # 调用getter这个设计非常优雅——一开始用简单属性需要加逻辑时改成property外部代码完全不用改。差异三构造函数和析构函数C有构造函数和析构函数负责资源的获取和释放。Python也有__init__和__del__但使用方式很不一样。Python有垃圾回收不需要手动释放内存。所以__del__很少用主要用于关闭文件句柄、网络连接这类非内存资源。而且__del__的调用时机不确定——你不应该依赖它做关键操作。Python管理资源的标准做法是用with语句class LidarConnection: def __init__(self, port): self.port port def __enter__(self): self.conn connect(self.port) return self def __exit__(self, *args): self.conn.close() with LidarConnection(/dev/ttyUSB0) as lidar: data lidar.scan() # 离开with块时自动关闭连接这就是Python版的RAII。差异四没有虚函数但有鸭子类型C的多态靠虚函数表vtable基类声明virtual方法子类override。Python不需要这套机制——Python天然支持多态因为它是动态类型的。class Lidar: def scan(self): return [1.0, 2.0, 3.0] class Camera: def scan(self): return [[0, 0, 0], [255, 255, 255]] def process(sensor): data sensor.scan() # 不关心sensor是什么类型 return dataprocess函数不关心传入的sensor是什么类型只要它有scan()方法就行。这就是鸭子类型——如果它走起来像鸭子、叫起来像鸭子那它就是鸭子。面试的时候面试官可能会问鸭子类型和C的多态有什么区别。核心区别在于C的多态是编译时绑定的通过虚函数表在运行时查找具体实现但要求继承关系Python的多态是运行时动态绑定的不要求任何继承关系只要有对应的方法就行。差异五多继承C支持多继承但容易出菱形继承问题需要用虚继承来解决。Python也支持多继承用MROC3线性化算法自动处理方法解析顺序。class BaseSensor: def calibrate(self): print(Base calibrate) class LidarMixin: def calibrate(self): print(Lidar calibrate) super().calibrate() # 按MRO调用下一个 class SmartLidar(LidarMixin, BaseSensor): pass SmartLidar().calibrate() # 输出Lidar calibrate → Base calibratePython中多继承更常见的用法是Mixin模式——把可复用的功能拆成独立的类按需组合。这比C的多继承安全得多。另外值得一提的是Python 3.7引入的dataclass和typing模块。dataclass可以自动生成__init__、__repr__等方法减少样板代码。typing模块支持类型注解比如def scan(self) - list[float]虽然运行时不强制检查但配合mypy静态检查工具可以在编译前发现类型错误。在大型机器人项目中类型注解能显著提高代码的可维护性。还有一个和性能相关的技巧__slots__。默认情况下Python对象的属性存在一个__dict__字典里每个对象都要额外分配字典的内存。如果你的项目需要创建大量对象比如点云中的每个点用__slots__可以告诉Python不要用字典而是用固定大小的数组来存属性内存占用能减少40%-50%。在机器人视觉处理中一帧点云可能有几十万个点这个优化的效果非常明显。给正在准备面试的你Python的面向对象面试重点不在于你能不能写出一个类而在于你能不能讲清楚Python和C在对象模型上的差异。访问控制、property、鸭子类型、MRO这几个概念要能讲清楚。下篇聊Python文件与数据处理——CSV/JSON/YAML的读写。机器人开发中经常要和配置文件、日志文件、实验数据打交道这几个格式的读写是基本功。如果这篇文章对你有帮助欢迎点赞、在看、转发三连。 你的支持是我持续更新的最大动力。「机器人软件开发面试·从入门到精通」连载系列上一篇第68篇 Python数据结构——list/dict/tuple/set的选型思维下一篇预告第70篇 Python文件与数据处理——CSV/JSON/YAML的读写有任何问题欢迎评论区留言我会尽量回复。