推荐参考视频实在搞不懂时去看ROS 实战部分B站搜索“鱼香ROS机器人”该 UP 主的 ROS2 系列课程讲解细致本文档是看这个视频的时候记录的Python 类的基础语法B站林粒粒呀的《三小时入门 Python》对类这个概念讲得通俗易懂适合零基础快速理解面向对象编程本文档作为上述视频的文字配套笔记建议先看视频本文档查阅具体语法细节作为辅助。目录什么是类为什么需要类定义类的基本语法__init__— 构造函数self— 对象自身实例变量 vs 类变量实例方法封装继承super().__init__()— 调用父类初始化实例化什么时候需要__init__什么时候不需要在 ROS2 中的固定套路与导入模块的关系术语速查表1. 什么是类为什么需要类类是一种组织代码的方式把数据属性和操作数据的方法函数打包在一起形成一个整体。这个整体就叫类。为什么要用类如果不使用类数据和行为是分散的# 不用类数据归数据函数归函数name法外狂徒张三age18defeat(person_name,person_age,food):print(f我叫{person_name},今年{person_age}岁吃{food})eat(name,age,鱼香肉丝)每次调用eat都要把name和age重新传一遍。数据和操作数据的行为是分离的。使用类之后classPerson:def__init__(self,name,age):self.namename self.ageagedefeat(self,food):print(f我叫{self.name},今年{self.age}岁吃{food})pPerson(法外狂徒张三,18)p.eat(鱼香肉丝)# 不需要再传 name 和 age对象自己记得数据name、age和行为eat绑定在一起。调用eat时对象知道自己的名字和年龄。2. 定义类的基本语法class类名:# 类体属性、方法示例classDownload:defdownload(self,url,callback):...部分含义规则classPython 关键字必须写类名你自己取的名字使用大驼峰命名法每个单词首字母大写如Download、PersonNode:冒号表示类体开始下面必须缩进类名命名约定classPersonNode# ✅ 大驼峰每个单词首字母大写classperson_node# ❌ 不推荐小写加下划线是变量/函数的命名方式classpersonNode# ❌ 不推荐小驼峰不是 Python 类的规范3.__init__— 构造函数是什么__init__是一个特殊方法双下划线开头和结尾。当你创建对象时Python 会自动调用它。作用在对象诞生时做初始化工作——把初始数据存到对象上。语法def__init__(self,参数1,参数2,...):self.某个属性参数1self.另一个属性参数2示例classPerson:def__init__(self,name,age):self.namename# 把传来的 name 存为这个对象的 name 属性self.ageage# 把传来的 age 存为这个对象的 age 属性当你写p Person(张三, 18)时Python 内部流程1. 创建一个空的 Person 对象 2. 自动调用 Person.__init__(这个空对象, 张三, 18) 3. __init__ 里 - self.name 张三 → 对象有了 name 属性 - self.age 18 → 对象有了 age 属性 4. 返回这个对象赋给变量 p什么时候写什么时候不写情况需要__init__创建对象时需要存储数据后面方法中需要用到self.xxx✅ 需要每次干活需要的数据都从参数直接传入不需要提前存储❌ 不需要不写__init__的例子classDownload:defdownload(self,url,callback):# url 和 callback 每次调用时直接从参数传入不需要存...4.self— 对象自身self是什么self代表调用这个方法的那个对象本身。为什么每个方法都要写selfPython 规定实例方法的第一个参数必须是self虽然你可以给它取别的名字但全世界都用self。调用时不需要手动传selfclassDog:defbark(self):print(f{self.name}在叫)# self 就是调用时的那个对象dog1Dog()dog1.bark()# 你写了 dog1.bark()Python 自动把 dog1 传给 selfself的用途访问对象的属性和方法classPerson:def__init__(self,name):self.namename# 把 name 存为 self 的属性defgreet(self):print(f我是{self.name})# 通过 self 访问这个对象的 name 属性5. 实例变量 vs 类变量实例变量属于每个对象自己每个对象的值可以不同。在__init__里用self.xxx定义。classDog:def__init__(self,name):self.namename# 实例变量每只狗的名字不同dog1Dog(旺财)dog2Dog(来福)print(dog1.name)# 旺财print(dog2.name)# 来福类变量属于整个类所有对象共享同一份数据。在类体里、方法外面定义。classDog:species犬科# 类变量所有狗都是犬科def__init__(self,name):self.namename# 实例变量dog1Dog(旺财)dog2Dog(来福)print(dog1.species)# 犬科print(dog2.species)# 犬科实例变量类变量属于谁每个对象自己整个类所有对象共享定义位置__init__里用self.xxx类体里、方法外访问方式self.xxx类名.xxx或self.xxx每个对象值相同吗❌ 可以不同✅ 所有对象一样6. 实例方法定义在类里面的函数叫方法。第一个参数必须是self。classPerson:defeat(self,food_name):# self 其他参数print(f吃{food_name})defsleep(self,hours):# 可以有多个自定义方法print(f睡{hours}小时)调用方式pPerson()p.eat(鱼香肉丝)# 对象.方法名(参数)不需要传 self7. 封装封装的意思是把数据和操作数据的方法捆绑在一起隐藏内部细节对外只暴露简单的接口。classDownload:defdownload(self,url,callback):# 内部怎么发 HTTP 请求、怎么处理编码...responserequests.get(url)response.encodingutf-8callback(url,response.text)defstart_download(self,url,callback):# 内部怎么开线程...threadthreading.Thread(targetself.download,args(url,callback))thread.start()外部使用时dDownload()d.start_download(http://...,my_callback)使用者只需要知道调用start_download并传网址和回调函数不需要知道内部是怎么开线程、怎么发 HTTP 请求的。8. 继承语法class子类名(父类名):...含义子类自动获得父类的所有属性和方法不用重新写一遍。子类还可以添加自己的新功能。代码示例# 父类classPersonNode(Node):def__init__(self,node_name,name,age):super().__init__(node_name)self.namename self.ageagedefeat(self,food_name):self.get_logger().info(f我叫{self.name},吃{food_name})# 子类继承 PersonNodeclassWriterNode(PersonNode):def__init__(self,name,age,book):super().__init__(name,age)# 调用父类的 __init__self.bookbook# 新增自己的属性继承链和能力叠加Node ← ROS2 提供get_logger()、create_publisher() 等 └── PersonNode ← 加了name、age、eat() └── WriterNode ← 加了bookWriterNode的对象同时拥有这三层的全部能力。为什么用继承不用重复造轮子WriterNode不需要重写eat()直接继承就能用层次清晰每一层只管自己的新增部分容易扩展需要新类型时再继承一层即可9.super().__init__()— 调用父类初始化含义super()返回当前类的父类。super().__init__(...)就是调用父类的__init__让父类先完成它的初始化工作。为什么要调用它父类可能有自己的初始化逻辑比如把节点名注册到 ROS2 系统。如果不调用父类的初始化就没执行后续功能可能失效。在 ROS2 节点中必须写classPersonNode(Node):def__init__(self,node_name,name,age):super().__init__(node_name)# 必须把节点名登记到 ROS2 系统...如果删掉这行ROS2 不知道这个节点存在get_logger()、发布、订阅统统失效。多层继承中的super()Node.__init__ ← 最底层向 ROS2 登记 ↑ 被调用 PersonNode.__init__ ← 中间层存 name、age ↑ 被调用 WriterNode.__init__ ← 最上层存 book每一层的super().__init__()往上调用最终整条链都执行。10. 实例化语法对象变量类名(参数1,参数2,...)含义用类这个模板造出一个具体的对象。示例# 不需要 __init__ 的类dDownload()# 空括号# 需要 __init__ 的类nodePersonNode(person_node,法外狂徒张三,18)# 传参数实例化时 Python 做了什么nodePersonNode(person_node,法外狂徒张三,18)内部流程1. 分配内存 → 创建一个空的 PersonNode 对象 2. 自动调用 PersonNode.__init__(空对象, person_node, 法外狂徒张三, 18) 3. __init__ 内部执行 → super().__init__(person_node) 向 ROS2 登记 → self.age 18 存年龄 → self.name 法外狂徒张三 存名字 4. 返回创建好的对象赋给变量 node11. 什么时候需要__init__什么时候不需要需要__init__对象有自己的记忆——方法里要用到self.xxxclassPersonNode(Node):def__init__(self,node_name,name,age):super().__init__(node_name)self.ageage# 存起来self.namename# 存起来defeat(self,food_name):# 这里用到 self.name 和 self.age所以必须先在 __init__ 里存self.get_logger().info(f我叫{self.name},今年{self.age}岁吃{food_name})不需要__init__每次方法调用需要的所有东西都从参数直接传入不需要存classDownload:defdownload(self,url,callback):# url 和 callback 从参数直接来不需要 self.url...defstart_download(self,url,callback):# 同理...12. 在 ROS2 中的固定套路以后你写任何 ROS2 Python 节点都遵循这个骨架importrclpyfromrclpy.nodeimportNodeclass你的节点名(Node):# ① 继承 Nodedef__init__(self,...):# ② 构造函数super().__init__(节点名)# ③ 必须向 ROS2 登记self.xxx...# ④ 你自己的属性# ⑤ 在这里创建发布者、订阅者、定时器...def你的方法(self,...):# ⑥ 自定义方法...defmain(argsNone):rclpy.init(argsargs)node你的节点名(...)# ⑦ 实例化rclpy.spin(node)rclpy.shutdown()if__name____main__:main()13. 与导入模块的关系从系统库导入fromrclpy.nodeimportNode翻译去rclpy库的node.py文件里把Node类拿出来给我用。从你自己写的文件导入fromdemo_python_pkg.person_nodeimportPersonNode翻译去demo_python_pkg包的person_node.py文件里把PersonNode类拿出来。这样WriterNode就可以继承PersonNode不用把代码重写一遍。14. 术语速查表术语含义示例类Class一个模板定义对象的属性和行为class PersonNode:对象Object用类造出来的具体实例node PersonNode(...)实例化用类创建对象的过程d Download()__init__构造函数创建对象时自动调用def __init__(self, ...):self代表对象自身方法第一个参数self.name name实例变量属于每个对象自己的数据self.age类变量属于整个类、所有对象共享的数据species 犬科实例方法定义在类里的函数第一个参数是selfdef eat(self, food):封装隐藏内部细节对外暴露简单接口start_download内部开线程外部不用管继承子类自动获得父类的所有能力class WriterNode(PersonNode):super()指代父类super().__init__(...)父类 / 子类被继承的类叫父类继承的类叫子类Node是父类PersonNode是子类核心口诀类是把数据和行为打包的模板继承让你不用重复造轮子super().__init__()是 ROS2 节点的必写项self永远代表那个对象自己。实在搞不懂时回到开头的视频链接跟着林粒粒呀和鱼香ROS机器人再走一遍。