恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Python类与面向对象深度解析:self、继承、抽象类与元类实践

  • 首页
  • 资讯中心
  • /
  • Python类与面向对象深度解析:self、继承、抽象类与元类实践

相关资讯

老系统迁移无文档?从代码逆向提取PRD的实战指南 2026/10/4 7:03:46
Spring Boot安全巡检系统毕设全解析:业务闭环到部署答辩 2026/10/4 7:03:46
GPT Image 2.5 中文图像生成实战:从提示词到 API 批量出图 2026/10/4 6:58:46

最新资讯

MR25H40CDF与PIC24FV16KA302:工业嵌入式MRAM存储方案
2026青岛外贸建站服务商技术实力排行与选型分析
想转 FDE(Forward Deployed Engineer)先别报班:一份 0 元的 30 天入门路线
长沙小吃培训口碑怎么判断:长沙曾食坊小吃培训走访
C++算法(二)
基于MRAM的工业存储方案:MR25H40CDF与TM4C123的SPI驱动实战

今日推荐

MR25H40CDF + PIC18F65K40:工业记录仪高可靠存储实战
基于STM32的数控恒压恒流电源设计:从硬件到PID调参全解析
LT9211 MIPI重定时器原理与双路扇出实战指南

本周热门

MR25H40CDF + PIC18F65K40:工业记录仪高可靠存储实战
基于STM32的数控恒压恒流电源设计:从硬件到PID调参全解析
LT9211 MIPI重定时器原理与双路扇出实战指南

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

Python类与面向对象深度解析:self、继承、抽象类与元类实践

发布时间:2026/10/4 7:03:46
Python类与面向对象深度解析:self、继承、抽象类与元类实践 写Python写了两三年之后你会发现一个规律只要项目稍微复杂一点类和对象就是绕不过去的坎。不管你是刚开始学class关键字的新手还是写了几年脚本但一直靠函数硬撑的老哥只要你涉及设备管理、订单系统、配置中心、策略封装这类要维护多份独立状态的场景只靠函数和字典堆逻辑代码很快就会变成一团乱麻。这篇文章就专门讲Python的类——从最基础的__init__和self原理到类属性与实例属性的差别再到继承、抽象类、嵌套类、类加载和元类最后用一个“设备信息类”把整个流程完整跑一遍。内容覆盖了入门和进阶两个层次适合刚学完基础语法想系统理解面向对象的人也适合写了好几年Python但某些机制始终没吃透的朋友。1. 从函数到类先搞清楚类到底解决了什么问题1.1 函数式写法的瓶颈在哪里很多初学者会有个疑问我写函数也能传参数、能返回结果为什么非要引入类这么个看起来更复杂的东西我举个特别常见的例子。假设你做一个设备管理程序每台设备有硬件型号、MAC地址、系统类型、系统版本、分辨率、网络状态这些信息。用函数写法你大概率会这么做def create_device(device_type, mac_addr, os_name, os_version, resolution, online): return { device_type: device_type, mac_addr: mac_addr, os_name: os_name, os_version: os_version, resolution: resolution, online: online, } def device_to_string(device): return f{device[device_type]} | {device[mac_addr]} | {device[os_name]} {device[os_version]} | {device[resolution]} | {在线 if device[online] else 离线}看起来挺清晰的对吧但注意这种写法靠的是“字典键名约定”。你传参的时候一旦拼错一个字符串键比如把mac_addr写成macaddr程序不会立刻报错而是等到运行时某个函数读取不到数据才爆炸。而且这种数据结构和操作它的函数是完全分离的随着逻辑增加你可能需要维护一堆device_to_string、device_to_json、device_save这样的独立函数它们都依赖于同一个字典结构却没有一个统一的约束出口。真正到了多人协作的项目里这种“约定大于规范”的写法是最容易出问题的。1.2 类本质上是把数据和操作绑在一起类解决的核心问题就是把数据结构和能作用在数据上的操作封装成一个整体。用类来写同一个设备模型你会得到这样一段代码class DeviceInfo: def __init__(self, device_type, mac_addr, os_name, os_version, resolution, online): self.device_type device_type self.mac_addr mac_addr self.os_name os_name self.os_version os_version self.resolution resolution self.online online def to_string(self): return f{self.device_type} | {self.mac_addr} | {self.os_name} {self.os_version} | {self.resolution} | {在线 if self.online else 离线}你在创建对象的时候__init__方法强制要求这些字段必须传进来少一个参数直接报TypeError这在很大程度上把“错误暴露时间”提前到了创建对象的那一刻。同时to_string作为方法绑定在对象上你不需要去记忆哪个函数操作哪种数据结构。这就是面向对象里说的“高内聚”——数据和操作待在同一个地方。用生活化的类比来说函数式写法就像你把食材、菜谱、炒菜工具全部分开堆放每次做菜都要自己把对应关系理一遍类则像把食材和专属菜谱装进一个料理盒你拿起来就知道这个盒子里装的是什么、能做什么。这只是最表层的好处更深层的威力在继承和多态里后面我会展开讲。2. 核心语法与对象本质self、__init__和属性边界2.1__init__方法到底是什么self又为什么必不可少几乎所有Python入门教程都会让你写def __init__(self, ...)但很多人写了半年都没搞明白self是什么。self就是当前实例对象本身。当你调用device.to_string()的时候Python解释器会自动把device这个对象作为第一个参数传给to_string方法所以self并不神秘它只是“这个对象自己”的约定叫法。至于__init__严格来说它并不是构造函数。真正创建对象的是__new__方法它负责分配一块内存空间然后__init__负责在空间分配好之后往里面填数据。你可以把__new__理解成“预订了房间”把__init__理解成“住进房间后把行李摆好”。常规开发中你基本不需要重写__new__只要知道这个流程就够了。这里有一个很多教程不会细讲的点__init__必须有返回值吗答案是不能有。如果你在__init__里写了return一个非None的值解释器会直接抛出TypeError。原因很简单__init__的职责是“初始化”不是“创建”创建的结果已经由__new__返回了。2.2 类属性与实例属性“同一个变量两种命运”这是Python类设计里最容易踩坑的地方之一。先看这段代码class Counter: count 0 # 这是类属性属于类本身 def __init__(self): self.value 0 # 这是实例属性属于每个对象 def increase(self): self.value 1 Counter.count 1Counter.count是定义在类体里的变量它是“类级别的属性”所有实例共享同一个值。而self.value是“实例级别的属性”每个Counter对象都有自己的value。如果你试着通过实例来修改类属性比如执行obj.count 1Python并不会直接修改类属性而是先查一下实例上有没有count这个属性发现没有就去类上找到了count的值然后创建了一个新的实例属性count把obj.count指向这个新值。这就是所谓的“属性遮蔽”。我实测下来最稳妥的做法是类属性用类名访问实例属性用self访问不要跨着用。在类内部想修改类属性就用类名.属性名的方式想修改实例属性就用self.属性名。否则很容易出现“看起来改了实际上别的实例根本没受影响”的诡异现象。2.3 方法家族实例方法、类方法、静态方法怎么选Python类里可以定义三种方法区别体现在第一个参数上。实例方法接收self类方法用classmethod装饰、接收cls静态方法用staticmethod装饰、不接收任何特殊参数。实例方法最常见它的特点是必须通过实例调用能访问实例状态。类方法的典型应用是“备选的创建入口”。比如设备类里你可以提供一个从JSON字典创建对象的方法class DeviceInfo: def __init__(self, device_type, mac_addr, os_name, os_version, resolution, online): self.device_type device_type self.mac_addr mac_addr self.os_name os_name self.os_version os_version self.resolution resolution self.online online classmethod def from_dict(cls, data): return cls( device_typedata[device_type], mac_addrdata[mac_addr], os_namedata[os_name], os_versiondata[os_version], resolutiondata[resolution], onlinedata[online], )这里cls是什么它是类本身。当你调用DeviceInfo.from_dict(some_dict)时cls就是DeviceInfo。这样一来即使你之后继承了这个类子类调用from_dict时cls会自动变成子类避免了把类名写死导致的继承问题。静态方法则适合那些和类有关但不需要类和实例状态的工具函数比如单位换算、格式校验staticmethod def validate_mac(mac_addr): return len(mac_addr) 17 and mac_addr.count(:) 5很多初学者把静态方法和模块级函数搞混其实它们最大的区别只是调用方式上多了类名.前缀同时给别人阅读代码时“这个函数属于这个类”的意图更明确。我的建议是如果函数会被外部代码直接用到而且逻辑上属于类的相关工具就写成静态方法如果只在这个类内部用那模块级函数也完全可以。3. 继承、抽象类与组合设计类与类之间怎么协作3.1 继承与super()的协作方式继承解决的是一类“相似但有差异”的对象建模问题。比如设备信息类可以按照设备类型继续细分路由器、摄像头、工控机它们都有device_type、mac_addr、os_name这些基本信息但各自又有额外字段和行为。如果你不做继承每新增一种设备类型就复制粘贴一份代码后续改公共字段会让你痛不欲生。class RouterDevice(DeviceInfo): def __init__(self, mac_addr, os_version, firmware_version, wifi_band): super().__init__( device_typerouter, mac_addrmac_addr, os_nameRouterOS, os_versionos_version, resolutionN/A, onlineTrue, ) self.firmware_version firmware_version self.wifi_band wifi_band注意super().__init__(...)这行的作用它主动调用父类的__init__让父类把公共字段初始化好然后子类再初始化自己的私有字段。很多新手在子类里重新初始化父类字段比如直接写self.device_type router这样也能跑但破坏了父类里可能存在的默认逻辑公共字段的初始化就散落到各个子类里了。正确的顺序是先让父类初始化公共部分再补自己的特色部分。3.2 抽象类与普通类的本质区别“抽象类和普通类的区别”这个热搜词出现频率极高说明很多人对这个概念的理解是模糊的。抽象类用abc模块实现它的核心特征是不能直接实例化只能被继承。它存在的意义是定义一种“模板”或“契约”。举个例子你可能同时有RouterDevice、CameraDevice、IpcDevice三种设备它们都应该有“启动自检”这个动作但自检逻辑完全不同。你可以在父类里定义一个普通的start_self_test方法并随便写个占位实现但这有个隐患——子类很可能忘记重写它然后调用到父类的占位逻辑而不自知。抽象方法就是来堵这个漏洞的from abc import ABC, abstractmethod class BaseDevice(ABC): abstractmethod def start_self_test(self): 所有子类必须实现自检逻辑 pass当start_self_test被abstractmethod装饰后任何继承了BaseDevice的子类只要没有实现这个方法的完整逻辑创建对象时就会直接报TypeError。这比“父类写个占位实现等子类重写”要严格得多占位实现属于“靠自觉”抽象方法则是“强制要求”。那普通类和抽象类的区别到底怎么理解我的经验是用一句话概括普通类的重点在于复用代码抽象类的重点在于定义接口规范。前者是“我帮你把活干了”后者是“你必须给我干这个活但我不限定你怎么干”。实际项目里抽象类非常适合做策略模式父类定义流程骨架比如预处理、执行、后处理子类只需要实现各自不同的那一步。3.3 嵌套类内部类与类图设计思路嵌套类也叫内部类指的是定义在类内部的类。这个特性在Python里不如Java里常用但合理使用能让代码结构更清晰。比如设备信息类里你可以定义一个NetworkState嵌套类来组织网络状态相关的字段class DeviceInfo: class NetworkState: def __init__(self, ip, connected, signal_strength): self.ip ip self.connected connected self.signal_strength signal_strength def __init__(self, device_type, mac_addr): self.device_type device_type self.mac_addr mac_addr self.network self.NetworkState(ip0.0.0.0, connectedFalse, signal_strength0)嵌套类的主要作用是表达“这个类是强依赖所属类的离开所属类就没有独立存在的意义”。不过我也要提醒一句嵌套类会让代码的可读性有所下降文件结构变复杂。遇到“不知道应不应该用嵌套类”的犹豫时我的默认选择是先拆成平级类除非这个类真的只为所属类服务。讲到类与类之间的关系就绕不开类图。UML类图里几种箭头的关系我一直是这么记忆的空心三角加实线是继承空心三角加虚线是实现接口对应Python里就是继承抽象类并实现抽象方法实心菱形加实线是组合表示“整体消失部分跟着消失”比如订单包含订单项订单删了订单项就没意义空心菱形加实线是聚合表示“整体消失部分还能独立存在”比如班级和学生虚线箭头是依赖表示某个类的方法参数或局部变量里用到了另一个类。画类图不一定非要用StarUML之类的高级工具我的建议是先用纸笔画清楚关系再动手写代码尤其当你的类超过五个的时候这个习惯能帮你省掉大量重构时间。4. 类的底层机制类本质上是对象类加载与元类4.1 类本身也是一个对象Python和C/Java最大的区别之一就是在Python里“类”本身也是一个对象。当你写下一行class DeviceInfo:的时候Python解释器会执行这段定义代码创建一个名为DeviceInfo的类对象这个对象是type类的实例。也就是说类也是一种数据你可以把它赋值给变量、放进列表、作为参数传递def create_device(device_class, mac_addr): return device_class(mac_addr) new_device create_device(DeviceInfo, AA:BB:CC:DD:EE:FF)这种特性在写工厂模式、注册表模式时非常有用。比如你有一个设备类型注册表可以直接把类对象存进字典里按需实例化DEVICE_REGISTRY { router: RouterDevice, camera: CameraDevice, ipc: IpcDevice, } def build_device(device_type, config): cls DEVICE_REGISTRY.get(device_type) if cls is None: raise ValueError(f未知设备类型: {device_type}) return cls(**config)这就是“类加载”和“类对象”这两个热搜词在实践中的意义。理解“类是对象”之后很多Python特技装饰器、元类、动态创建类都会变得顺理成章。而且这个特性也让Python的多态比静态语言灵活很多——你不必非得通过继承来共享接口只要对象有同名方法就能被统一调用。4.2__new__、类定义执行顺序与元类浅析类定义虽然是一段代码但它的执行顺序是很多人忽略的。当解释器执行class语句时会先按顺序执行类体里的所有代码包括类属性赋值、普通函数定义然后把这些名字收集进类的命名空间最后用type(类名, 父类元组, 命名空间)创建类对象。这意味着类体里你甚至可以放print语句和if判断它们都会在“定义类的时候”执行一次而不是在实例化的时候执行。这个机制和__new__加__init__的创建流程合在一起就是完整的一条线定义类时先执行类体代码type创建类对象实例化时先__new__分配内存再__init__填数据。__new__在什么场景下会用到最常见的是实现单例模式——让一个类始终只能有一个实例class SingletonDeviceManager: _instance None def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance super().__new__(cls) return cls._instance这里super().__new__(cls)才是真正的内存分配动作__init__会在__new__返回实例后被自动调用。如果你发现单例模式的__init__被重复执行了那就需要给__init__加个判断因为__new__只会分配一次但__init__每次实例化都会执行。元类metaclass是比__new__更底层的机制它决定“创建类的类”。默认是type你可以自定义一个元类来批量修改所有继承某个基类的子类。但我必须直说元类在实际项目里的使用频率极低90%的开发者一辈子不写元类也完全没问题。如果你遇到有人炫耀元类写法保持敬意就好不要盲目模仿能用装饰器或类装饰器解决的问题都不要上升到元类。5. 完整实操从需求到实现一个“设备信息类”5.1 需求分析与类的骨架设计说了这么多理论我用一个实际可用的案例把所有知识点串起来。假设有这样的需求程序需要管理一批设备的信息设备字段包括硬件型号、MAC地址、系统类型、系统版本、分辨率、网络状态不同的设备有不同的自检方式输出时支持格式化为字符串或JSON。这个需求直接对应了开头那段热搜词里“设备信息包括硬件型号、MAC地址、系统类型、系统版本、分辨率、网络状态类”的场景。结合前面讲的内容我的设计思路是这样的先做一个抽象基类BaseDevice强制子类实现start_self_test然后做一个通用实现DeviceInfo覆盖基本信息模型和通用方法再分别派生出RouterDevice和CameraDevice来展示继承最后在DeviceInfo里加一个嵌套类NetworkState来组织网络状态。类的骨架设计如下from abc import ABC, abstractmethod import json class BaseDevice(ABC): abstractmethod def start_self_test(self): pass class DeviceInfo(BaseDevice): class NetworkState: def __init__(self, ip, connected, signal_strength): self.ip ip self.connected connected self.signal_strength signal_strength def __init__(self, device_type, mac_addr, os_name, os_version, resolution, onlineTrue): self.device_type device_type self.mac_addr mac_addr self.os_name os_name self.os_version os_version self.resolution resolution self.network self.NetworkState(0.0.0.0, False, 0) def start_self_test(self): return f{self.device_type} 基础自检通过 def to_string(self): state 在线 if self.network.connected else 离线 return f{self.device_type} | {self.mac_addr} | {self.os_name} {self.os_version} | {self.resolution} | {state} def to_dict(self): return { device_type: self.device_type, mac_addr: self.mac_addr, os_name: self.os_name, os_version: self.os_version, resolution: self.resolution, online: self.network.connected, } def to_json(self): return json.dumps(self.to_dict(), ensure_asciiFalse, indent2)这里我特意让BaseDevice作为抽象基类要求所有子类必须实现start_self_test。DeviceInfo继承它并提供了通用实现后续更具体的设备类只需要继承DeviceInfo并重写自检逻辑。5.2 逐步实现与验证继承和重写的完整过程接下来写两个具体子类。路由器有固件版本和无线频段字段自检时要检查固件版本号摄像头有像素和夜视能力字段自检时要额外模拟传感器状态检测class RouterDevice(DeviceInfo): def __init__(self, mac_addr, os_version, firmware_version, wifi_band): super().__init__( device_typerouter, mac_addrmac_addr, os_nameRouterOS, os_versionos_version, resolutionN/A, onlineTrue, ) self.firmware_version firmware_version self.wifi_band wifi_band def start_self_test(self): if self.firmware_version 2.0: return f路由器 {self.mac_addr} 固件过旧请升级 return f路由器 {self.mac_addr} 固件版本 {self.firmware_version}自检通过 class CameraDevice(DeviceInfo): def __init__(self, mac_addr, os_version, resolution, pixel, night_vision): super().__init__( device_typecamera, mac_addrmac_addr, os_nameCameraOS, os_versionos_version, resolutionresolution, onlineTrue, ) self.pixel pixel self.night_vision night_vision def start_self_test(self): if not self.night_vision: return f摄像头 {self.mac_addr} 夜视功能异常 return f摄像头 {self.mac_addr} 传感器检测通过像素 {self.pixel}验证一下router RouterDevice(AA:BB:CC:DD:EE:01, 4.5.6, 2.1.0, 5GHz) camera CameraDevice(AA:BB:CC:DD:EE:02, 3.2.1, 1920x1080, 400万, True) print(router.to_string()) print(router.start_self_test()) print(camera.to_string()) print(camera.start_self_test())运行结果为router | AA:BB:CC:DD:EE:01 | RouterOS 4.5.6 | N/A | 在线 路由器 AA:BB:CC:DD:EE:01 固件版本 2.1.0自检通过 camera | AA:BB:CC:DD:EE:02 | CameraOS 3.2.1 | 1920x1080 | 在线 摄像头 AA:BB:CC:DD:EE:02 传感器检测通过像素 400万这个例子里你能清晰看到继承的复用效果子类完全没有重写to_string和to_dict它们直接继承了父类的公共逻辑同时通过super().__init__()把公共字段初始化交给父类自己只负责差异部分。这就是继承的核心意义。5.3 扩展批量实例化、注册表模式与类方法最后一个扩展场景假设设备配置是存在一个JSON文件里的你需要加载并批量创建设备对象。这时候就能用上前面讲的类方法和注册表模式DEVICE_REGISTRY { router: RouterDevice, camera: CameraDevice, } def load_devices_from_config(config_list): devices [] for item in config_list: device_type item[device_type] cls DEVICE_REGISTRY[device_type] item.pop(device_type) devices.append(cls(**item)) return devices有一点需要注意RouterDevice和CameraDevice的构造参数并不相同一个需要firmware_version和wifi_band另一个需要pixel和night_vision。所以严格来说最好为每个子类单独提供from_config类方法而不是在统一的注册表里盲目地cls(**item)。这也是实战中常见的分叉点——继承让公共部分得到复用但子类各自的差异化参数必须在子类层面负责。你可以这样优化class RouterDevice(DeviceInfo): classmethod def from_config(cls, config): return cls( mac_addrconfig[mac_addr], os_versionconfig[os_version], firmware_versionconfig[firmware_version], wifi_bandconfig[wifi_band], )这样load_devices_from_config就可以统一调用cls.from_config(item)实现“接口统一、实现各异”的多态效果。如果你对设计模式有了解会发现这就是工厂模式加策略模式的雏形。6. 常见问题与排查经验速查6.1 高频报错与对策速查表代码写得多了报错是必然的。我把实际工程里最常见的类相关报错整理成一张速查表方便你遇到问题直接对照。报错信息常见原因解决方案TypeError: __init__() missing 1 required positional argument创建对象时少传了参数检查构造方法的参数列表确认所有必填参数都传了NameError: name self is not defined在类体里直接调用了方法而不是通过实例在方法内部使用self.xxx()调用其他方法类体里的顶层代码无法访问实例方法TypeError: start_self_test() takes 1 positional argument but 2 were given方法没有被正确装饰子类重写后忘了传self或装饰器用错检查方法定义是否少了self参数或者子类重写时是否保留selfAttributeError: DeviceInfo object has no attribute xxx访问了实例上不存在的属性确认该属性确实在__init__中赋值过且没有拼写错误TypeError: Cant instantiate abstract class ... with abstract method ...子类没有实现所有抽象方法实现父类中所有被abstractmethod装饰的方法属性改了但没有生效修改的是实例属性而不是类属性产生了属性遮蔽用类名DeviceInfo.count 1来修改类属性类方法里报NameError类方法内部直接引用了函数名而不是cls.方法名类方法里调用其他类方法要用cls.method()TypeError: __init__() should return None在__init__里写了return返回值删除__init__中的return语句“表达式必须包含类类型”这个报错在C#和Java里经常出现意思是某个变量不是预期的类类型就开始访问成员了。Python里对应的场景也常见你拿到一个字典或者列表却想直接点.访问属性就会报AttributeError。本质是一样的——先确认你的对象到底是什么类型再用对应的访问方式。6.2 可变默认参数与共享引用的坑这是Python类设计里最经典的一个坑。如果你在__init__里写了这种代码class DeviceGroup: def __init__(self, devices[]): self.devices devices那么所有没传devices参数的对象会共享同一个默认列表。第一批设备被加进去之后第二批新建的对象里也会出现。原因在于默认参数是在函数定义时创建并缓存的同一个默认列表每次都用同一份引用。这个坑在我刚写Python的时候坑了我整整一个下午后来就养成了铁律可变类型列表、字典、集合永远不要作为默认参数值。正确写法是class DeviceGroup: def __init__(self, devicesNone): self.devices devices if devices is not None else []类似的问题也出现在实例属性共享上。如果__init__里你写了self.network self.default_network而这个default_network是一个类属性且是可变的那么所有实例都会共享同一个网络状态对象。一个设备改状态所有设备都跟着变。这个问题的排查思路是凡是定义在类体里且是可变对象的属性都默认被所有实例共享。6.3 类设计的一些个人心得写类写了这么多年我总结出几条简单粗暴但实用的设计原则最后分享给你。第一能用组合就不用继承。继承适合“is-a”是一种的关系比如路由器是一种设备组合适合“has-a”有一个的关系比如网络状态是设备拥有的一个部分。如果你不确定是不是“is-a”优先用组合把另一个类的实例作为自己的属性挂进去这样耦合度低改起来不伤筋动骨。第二类不要太大。一个类如果超过三四个字段且方法超过十个基本就说明它承担了过多的职责。这时候我会考虑拆分把网络状态拆成NetworkState类把自检逻辑拆成SelfTestMixin让每个类都保持一个明确的小职责。拆分以后你会觉得代码好改很多因为改动的影响面变小了。第三类属性、类方法、静态方法的装饰器是给未来的你看的。每当你犹豫要不要写staticmethod时默认可以写因为它在调用方式上明确告诉你这个函数不依赖实例状态只是类的工具。读代码的人一眼就能分辨方法的行为这个信号价值在半年后重新翻代码的时候尤其值钱。最后再补充一个实用技巧给类加上__repr__方法会让调试过程舒服很多。比如def __repr__(self): return fDeviceInfo(device_type{self.device_type!r}, mac_addr{self.mac_addr!r})这样你在IDE里或者命令行里直接输入对象名看到的就不是一行__main__.DeviceInfo object at 0x...这种毫无信息的地址而是清晰的属性和值。我后来把这招用在了所有自定义类上调试效率提升非常明显。Python的类机制其实并不复杂核心就一句话类是把状态和方法绑在一起的模具实例是模具造出来的具体对象。把这句话吃透再往里面一点点加继承、抽象、嵌套这些细节你会发现写Python的整体思路都会通顺很多。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号