Python中的类

📅 2026/7/8 13:09:06
Python中的类
用一个比喻——汽车的设计蓝图与生产——来系统性地讲解Python的类定义与实例化。每一个专业术语我都会用但我会把概念拆到最细确保每一步都像放电影一样在你脑子里清晰可见。1. 蓝图与汽车类和对象的基本概念假设你是一家汽车公司的总设计师。你画好了一份图纸上面详细标明了这辆车应该有哪些数据特征颜色、发动机型号、座椅数量。这辆车能执行哪些行为启动引擎、鸣喇叭、显示仪表盘。在Python里这张图纸就是类Class。你写classCar:pass这就画了一张空图纸。用更严谨的话说类是一个用户自定义的复合数据类型它定义了一组属性和方法用来描述一类对象的结构和行为。类本身是一张抽象的蓝图不是一辆具体的车。当你想要一辆实实在在的车时你按照图纸生产一辆my_carCar()这个my_car就是实例Instance它是根据Car蓝图制造出来的一个具体对象。把蓝图变成具体对象的过程叫作实例化Instantiation。2. 类定义到底做了什么当你写下class Car:开头的代码块时Python并不会只是把它当成一段说明看看就完它会立即执行类体内的代码来制造出一个“蓝图对象”。具体步骤创建一个全新的命名空间内部是一个字典。在这个命名空间里逐条执行类体中的语句。如果在类中写了wheels 4那么键值对wheels: 4就会被放进这个命名空间如果定义了函数def drive(self): …那么函数对象也会被放进去。执行完之后Python把类名、继承的父类稍后讲以及这个装满内容的命名空间一起交给元类默认是type去调用最终返回一个类对象并绑定到类名上。关键点类本身也是一个对象蓝图也是用纸做的实物。这个类对象可以被赋值、被传递甚至可以动态修改。它存储在内存中拥有自己的属性。3. 类的核心成员属性和方法在类的命名空间里我们主要放两类东西属性变量和方法函数。3.1 类属性 vs 实例属性类属性定义在类体内、任何方法之外的变量。它属于类对象本身被所有该类的实例共享。就像是印在蓝图上的通用规格——所有按这张蓝图造出的车都共用这一个规格值。classCar:wheels4# 类属性所有车默认有4个轮子material钢实例属性在__init__方法或其他实例方法内部通过self.属性名绑定的变量。它只属于每一个单独的实例。就像是每辆具体的车出厂时在车身上喷上的独一无二的VIN码和颜色。classCar:def__init__(self,color,vin):self.colorcolor# 实例属性self.vinvin# 实例属性__init__方法称为构造器Constructor或者更精确地说是初始化方法。它在每辆车生产出来实例化的一瞬间被自动调用用来为这辆新车设置最初的实例属性。3.2 方法的三种形态方法是定义在类里的函数根据其第一个参数和装饰器分为三种方法类型装饰器第一个参数作用比喻实例方法无self操作实例自身的数据司机踩下这辆车的油门my_car.accelerate()类方法classmethodcls操作类本身的数据或提供替代构造器工厂调阅蓝图修改通用规格Car.update_specs()静态方法staticmethod无强制参数一个与类逻辑相关但不依赖实例或类的普通工具函数放在蓝图文件夹里的单位换算表代码示例classCar:total_produced0# 类属性统计总产量def__init__(self,color):self.colorcolor Car.total_produced1# 操作类属性# 实例方法defhonk(self):print(f这辆{self.color}的车嘀嘀)# 类方法classmethoddeffrom_color_only(cls,color):# 替代构造器可以直接 Car.from_color_only(红) 来造车returncls(color)# 静态方法staticmethoddefkm_to_miles(km):returnkm*0.621371注意self和cls不是关键字只是极强烈推荐的命名约定。self指向调用方法的那个特定实例cls指向类对象本身。3.3 特殊方法魔法方法Python内置了一整套双下划线的方法能让你自定义的类表现得和内置类型一样自然。__init__(self)已讲初始化。__str__(self)定义print(对象)或str(对象)的“通俗易懂版”输出。__repr__(self)定义直接敲对象名或在调试器里的“精确描述版”输出通常应能让eval重建对象。__len__(self)响应len()。__eq__(self, other)响应。__add__(self, other)响应。__getitem__(self, key)响应索引操作obj[key]。这些方法由Python解释器在特定语法下自动调用你一般不需要直接写my_car.__str__()。4. 实例化的完整过程从蓝图到新车当你执行my_car Car(红色)时可不仅仅是调用__init__那么简单。背后有一条精密的生产线触发__call__Car(红色)想“调用”类对象。这种调用能力来自类的元类type里定义的__call__方法。分配内存__new__type.__call__首先调用Car.__new__(Car)。这是一个静态方法负责真正分配内存、创建并返回一个空白的实例对象。绝大多数情况下你不需要重写它除非你继承不可变类型如str,tuple或实现单例模式。初始化__init__刚刚返回的空白实例作为self被自动传给Car.__init__(self, 红色)完成实例属性的设置。返回实例__init__结束它绝不能返回None以外的值最终type.__call__将初始化好的实例对象返回由变量my_car接住。链条__call__→__new__→__init__。这就是实例化的完整内核。5. 属性查找与方法绑定当你访问my_car.color或调用my_car.honk()时Python按照严格的顺序去查找首先查找实例自身的__dict__实例属性字典。找到就返回。如果找不到去类对象的__dict__里找。方法就存在这里函数对象。如果还找不到按照**MRO方法解析顺序**往所有父类的字典里依次找。如果完全找不到则尝试调用__getattr__方法如果定义了否则抛出AttributeError。这就是为什么所有实例能共享方法方法作为函数对象存在类里实例调用它时Python会自动把实例本身作为第一个参数self塞进去这个过程叫绑定binding。所以my_car.honk()底层相当于Car.honk(my_car)。6. 继承基于旧蓝图造新车继承是面向对象的核心机制之一。你可以在一个已有类的基础上进行扩展得到一个新的类。classElectricCar(Car):# ElectricCar 继承自 Cardef__init__(self,color,battery_kwh):super().__init__(color)# 调用父类 __init__ 初始化 colorself.battery_kwhbattery_kwh# 新增实例属性# 可以覆盖Override父类方法defhonk(self):print(静音的滴滴声...)ElectricCar是子类SubclassCar是**父类Superclass**或基类。super()返回一个代理对象让你能调用父类的方法避免硬编码父类名字这在多重继承下尤其重要。子类可以**重写Override**父类的方法实现多态同一方法名不同类的实例表现出不同行为。这是面向对象编程的精髓之一。MRO 是方法查找的线性顺序表。对于单继承就是子类→父类→祖父类对于多重钻石继承Python使用C3 线性化算法计算出单调一致的顺序。可以通过类名.__mro__或类名.mro()查看。7. 更精细的控制property 与名称改写7.1 property 装饰器把方法伪装成属性有时候你希望像访问属性一样来获取或设置一个值但背后需要执行检查或计算逻辑。classCar:def__init__(self,speed):self._speedspeedpropertydefspeed(self):获取速度returnself._speedspeed.setterdefspeed(self,value):ifvalue0:raiseValueError(速度不能为负)self._speedvalue然后你就可以写my_car.speed 60和print(my_car.speed)自然地触发getter和setter方法。注意底层我们通常用一个“内部”属性如_speed来真正存储数据避免方法名和属性名冲突导致递归。7.2 名称改写 (Name Mangling)Python没有真正的私有成员但双下划线开头的属性会触发名称改写__var在类内部会被解释器自动重命名为_ClassName__var。这是用来防止子类意外覆盖父类属性的机制而非安全措施。classA:def__init__(self):self.__secret1# 实际变成 _A__secret社区更通用的“私有”约定是单下划线_var表示“内部实现细节不建议外部直接访问”。8. 元类制造蓝图的蓝图可选深度还记得“类也是对象”吗那么类是由什么制造出来的呢答案就是元类Metaclass。默认的元类是type。你可以通过__metaclass__关键字或继承时指定来定制类的创建过程框架开发者常用它实现自动注册、接口检查等魔法。当你执行class Car:实际上是调用了type(Car, (object,), class_dict)。元类是高级话题但理解了它你就明白了Python中一切皆对象的真谛类不过是元类的实例。9. 完整术语速查表用蓝图/汽车比喻专业术语直白解释类 (Class)汽车的设计蓝图。定义数据和行为的模板。类对象 (Class Object)蓝图本身也是一个实实在在的对象。实例 (Instance)根据蓝图生产出来的一辆能开上路的汽车。实例化 (Instantiation)根据蓝图把车造出来的动作Car(红)。实例属性喷在这辆特定车身上的颜色、VIN号self.color。类属性写在蓝图上的通用规格所有车共享如wheels4。实例方法司机操作这辆车的行为第一个参数是self。类方法修改蓝图通用参数的操作classmethod第一个参数cls。静态方法放在蓝图文件夹里的工具函数staticmethod。构造器__init__初始化方法每辆车下线时给车上漆、打码。__new__真正的生产模具分配车壳的内置方法极少改动。self“这辆车自己”实例方法中指向当前操作的汽车。cls“这张蓝图自己”类方法中指向当前类对象。继承基于旧蓝图设计新蓝图自动获得旧蓝图的全部特征。super()获取父类蓝图的代理安全调用父类功能。方法重写 (Override)新蓝图对旧蓝图的某个功能进行重新设计。多态不同蓝图的车对“按喇叭”有不同实现但调用方式一样。MRO方法搜索的路线图决定了多重继承时找方法的顺序。property让方法像直接读取车上的速度表一样自然背后可加逻辑。名称改写__name会自动变成_类名__name避免子类无意覆盖。元类制造蓝图的蓝图type就是默认的蓝图生产机器。至此我用汽车蓝图与生产的比喻从头到尾把Python的类定义与实例化完整穿了一遍。你可以拿着这张表对着代码例子去验证直到这些抽象术语在你脑中像实物一样清晰。费曼的方法就是如果你不能用一个简单的比方把它讲透就是你还没真懂。现在你应该可以了。