Python
基础语法
01概念
02安装
03变量
04字符串
05数
06常量与注释
07列表
08元组
09if语句
10字典
11集合
12复合数据类型对比
13推导式
14用户输入
15while循环
16函数
17类
18面向对象编程
19文件操作
20异常处理
21日期和时间
22魔术方法
23内置函数
24线程
25并发&并行
26正则表达式
27迭代器
28装饰器
29生成器
30上下文管理器
31函数式编程
32闭包
33解包
34工具库
35连接关系型数据库
36虚拟环境
37异步编程
网络爬虫
01urllib库[了解]
02requests库
03数据交换格式
04解析库
05lxml
06Beautiful Soup
07Xpath语法
08动态网页的处理
-
+
首页
17类
在 Python 中,**类(Class)** 是面向对象编程(OOP)的核心概念,它是一种**用于创建对象的模板或蓝图**,封装了数据(属性)和操作数据的方法(函数),用于描述具有相同属性和行为的一类事物。通过类,可以实现代码的模块化、复用和抽象,更贴近现实世界的实体建模(如 “人”“汽车” 等概念均可抽象为类)。 ## 概念 **本质**:类是对 “一类事物” 的抽象描述。例如,“人类(Person)” 可以抽象为一个类,包含 “姓名、年龄” 等共性数据(属性),以及 “说话、走路” 等共性行为(方法)。 **对象(实例)**:类的具体实现。例如,“张三” 是 “人类” 类的一个对象(实例),他有具体的姓名 “张三”、年龄 “30”,并能执行 “说话” 的行为。 **核心作用**: 1. 封装(Encapsulation):将数据和操作数据的方法捆绑在一起,隐藏内部细节; 2. 继承(Inheritance):子类可复用父类的属性和方法,实现代码复用; 3. 多态(Polymorphism):不同类的对象可通过相同的接口(方法名)表现出不同行为。 **根据类来创建对象称为实例化,创建后的对象称为实例,可通过实例访问的变量称为属性,类中的函数称为方法。** ## 定义 用class关键字定义类,基本语法如下: ```python class 类名(父类列表): # 父类列表可选,用于继承 """类的文档字符串(描述类的功能)""" # 类属性(所有实例共享的变量) 类属性名 = 属性值 # 构造方法(初始化实例属性) def __init__(self, 参数列表): # 实例属性(每个实例独有的变量) self.实例属性名 = 参数值 # 实例方法(操作实例的方法) def 方法名(self, 参数列表): 方法体 # 类方法(操作类的方法) @classmethod def 类方法名(cls, 参数列表): 方法体 # 静态方法(与类和实例无关的工具方法) @staticmethod def 静态方法名(参数列表): 方法体 ``` 使用类几乎可以模拟任何东西,,例如可以创建一个简单的小狗类Dog。对于大部分的宠物狗来讲,都有名字和年龄,有些狗还可以让它坐下或打滚。 所以,根据Dog类创建的每个实例都应该有名字和年龄,还可以赋予它们坐下和打滚的能力。 **类名**:遵循 “驼峰命名法”(首字母大写,如Person、Student),见名知意。 ```python class Dog: """模拟小狗""" def __init__(self, name, age): """初始化属性name和age""" self.name = name self.age = age def site(self): """模拟小狗坐下的动作""" print(f"{self.name} is now sitting!") def roll_over(self): """模拟小狗打滚的动作""" print(f"{self.name} is now rolling over!") ``` 各部分说明: - class:定义类的关键词; - Dog:类名; - 文档字符串:三个引号包裹说明的文字,描述类的功能; - def:创建函数的关键词;(类中的函数被称为方法); - \__init__()方法:特殊方法,是类的构造方法也称为初始化方法,作用是在创建类的实例(对象)时自动调用,方法中包含了三个参数,具体讲解请看下一个目录; - site(self)方法:模拟小狗坐下的动作方法; - roll_over(self):模拟小狗打滚的动作方法。 ## \__init()__ 在 Python 类中,\__init__方法和self形参是初始化实例属性的核心,二者配合完成从 “类模板” 到 “具体对象” 的实例化过程。 \__init__方法的语法结构: ```python class 类名: def __init__(self, 参数1, 参数2, ...): # self是第一个必选参数 # 为当前实例绑定属性 self.属性1 = 参数1 # 将参数1的值赋给实例的属性1 self.属性2 = 参数2 # 将参数2的值赋给实例的属性2 # ... 其他属性初始化 ``` - **参数列表**:第一个参数必须是self(代表当前实例),后续参数是初始化实例所需的具体数据(如姓名、年龄)。 - **实例属性绑定**:通过self.属性名 = 参数的方式,将外部传入的参数值绑定到当前实例上,使每个实例拥有独有的属性值。 ```python class Person: # 定义__init__方法,初始化name和age属性 def __init__(self, name, age): self.name = name # 为当前实例绑定name属性 self.age = age # 为当前实例绑定age属性 # 创建实例时,自动调用__init__,传入name和age参数 person1 = Person("张三", 30) person2 = Person("李四", 25) # 每个实例的属性独立(由__init__初始化) print(person1.name) # 输出:张三(person1的name属性) print(person2.age) # 输出:25(person2的age属性) ``` self是\__init__(以及所有实例方法)的第一个必选参数,它代表**当前正在创建或操作的实例对象本身**,self的作用和特性: - **绑定实例属性**:在\__init__中,通过self.属性名的语法,将属性 “绑定” 到当前实例上,确保每个实例的属性独立(不与其他实例共享)。 - **访问实例属性和方法**:在类的实例方法中,通过self.属性名访问当前实例的属性,通过self.方法名()调用当前实例的其他方法。 - **区分实例属性与局部变量**:self.属性名明确表示 “实例的属性”,而不带self的变量是方法内部的局部变量(仅在方法内有效)。 - **自动传递**:调用实例方法(包括\__init__)时,self不需要手动传入,Python 会自动将当前实例作为self参数传递。 例如:person1 = Person("张三", 30)中,self会自动被替换为person1这个实例,无需写成Person(person1, "张三", 30)。 - **指向当前实例**:在不同实例中,self指向的对象不同。例如person1的self指向person1,person2的self指向person2,因此二者的属性相互独立。 ```python class Person: def __init__(self, name, age): self.name = name # self绑定实例属性 self.age = age # 实例方法:通过self访问实例属性 def introduce(self): # self.name和self.age即当前实例的属性 print(f"我叫{self.name},今年{self.age}岁") person1 = Person("张三", 30) person1.introduce() # 输出:我叫张三,今年30岁(self指向person1) person2 = Person("李四", 25) person2.introduce() # 输出:我叫李四,今年25岁(self指向person2) ``` **值得注意的是:\__init__的作用是初始化实例,必须返回None,也就是说该方法不能有返回值。** ## 创建 类是 “模板”,需通过**实例化**创建具体对象(实例),才能使用类中定义的属性和方法。 语法: ```python 对象名 = 类名(参数列表) # 参数列表对应__init__方法的参数(不含self) ``` 例如: ```python class Dog: """模拟小狗的尝试""" def __init__(self, name, age): """初始化属性name和age""" self.name = name self.age = age def site(self): """模拟小狗坐下的动作""" print(f"{self.name} is now sitting!") def roll_over(self): """模拟小狗打滚的动作""" print(f"{self.name} is now rolling over!") my_dog = Dog("布鲁斯", 10) your_dog = Dog("Tom", 20) ``` ## 访问 要访问实例的属性和方法,可以通过**实例名.属性名或方法名**进行访问。 ```python print(my_dog.name) print(your_dog.name) print(my_dog.site()) print(your_dog.roll_over()) ``` 输出结果: ```python 布鲁斯 Tom 布鲁斯 is now sitting! None Tom is now rolling over! None ``` 注意:为什么会出现None呢?因为所有的函数(方法)都有返回值,若方法有return 结果,则返回指定结果;若方法没有return语句(如site()和roll_over()),则默认返回None。 ## 指定默认值 有些属性无需通过形参来定义,可以在\__init__()方法中为其指定默认值。 例如在Dog类中加一个小狗的品种所属国的属性,默认为中国,再添加一个所属国的方法。 ```python class Dog: """模拟小狗的尝试""" def __init__(self, name, age): """初始化属性name和age""" self.name = name self.age = age self.country = "中国" def site(self): """模拟小狗坐下的动作""" return f"{self.name} is now sitting!" def roll_over(self): """模拟小狗打滚的动作""" return f"{self.name} is now rolling over!" def belong_to_country(self): """小狗来自于哪里""" return f"{self.name} comes from {self.country} " my_dog = Dog("布鲁斯",10) print(my_dog.country) print(my_dog.belong_to_country()) ``` 输出结果: ```python 中国 布鲁斯 comes from 中国 ``` ## 修改属性的值 一般情况下,可以通过两种方式修改属性的值:直接通过实例修改和通过方法设置修改。 **通过实例直接修改属性的值** ```python class Dog: """模拟小狗的尝试""" def __init__(self, name, age): """初始化属性name和age""" self.name = name self.age = age self.country = "中国" def site(self): """模拟小狗坐下的动作""" return f"{self.name} is now sitting!" def roll_over(self): """模拟小狗打滚的动作""" return f"{self.name} is now rolling over!" def belong_to_country(self): """小狗来自于哪里""" return f"{self.name} comes from {self.country} " my_dog = Dog("布鲁斯",10) print(my_dog.country) print(my_dog.belong_to_country()) my_dog.country = "China" print(my_dog.country) print(my_dog.belong_to_country()) ``` 输出结果: ```python 中国 布鲁斯 comes from 中国 China 布鲁斯 comes from China ``` **通过方法设置修改属性的值** 将belong_to_country()方法设置为可以接受参数。 ```python class Dog: """模拟小狗的尝试""" def __init__(self, name, age): """初始化属性name和age""" self.name = name self.age = age self.country = "中国" def site(self): """模拟小狗坐下的动作""" return f"{self.name} is now sitting!" def roll_over(self): """模拟小狗打滚的动作""" return f"{self.name} is now rolling over!" def belong_to_country(self, country): """小狗来自于哪里""" self.country = country return f"{self.name} comes from {self.country} " my_dog = Dog("布鲁斯",10) print(my_dog.country) my_dog.belong_to_country("CHINA") print(my_dog.country) ``` 输出结果: ```python 中国 CHINA ``` ## 封装 封装(Encapsulation)是指将数据(属性)和操作数据的方法捆绑在类中,并通过**访问控制**隐藏内部实现细节,只暴露必要的接口(方法)。 - **私有属性 / 方法**:在属性或方法名前加**双下划线__**,使其成为私有成员,只能在类内部访问(外部无法直接访问,通过 “名称修饰” 实现伪私有)。 - 目的:防止外部随意修改内部数据,保证数据安全性。 ```python class BankAccount: def __init__(self, balance): self.__balance = balance # 私有属性:余额(外部无法直接访问) # 公开方法:查询余额(提供接口) def get_balance(self): return self.__balance # 类内部可访问私有属性 # 公开方法:存款(提供接口) def deposit(self, amount): if amount > 0: self.__balance += amount # 私有方法:日志记录(仅内部使用) def __log(self, message): print(f"日志:{message}") account = BankAccount(1000) # 外部无法直接访问私有属性/方法 # print(account.__balance) # 报错:AttributeError # account.__log("测试") # 报错:AttributeError # 必须通过公开方法访问 account.deposit(500) print(account.get_balance()) # 输出:1500(正确访问) ``` 输出结果: ```python 1500 ``` ## 继承 在编写类时,并非总是要从头开始写,如果要编写的类是一个已经有的类的特殊版本,那么就可以使用继承(Inheritance)。 当一个类继承另一个类时,会自动获得后者的所有属性和方法,原有的类被称为父类,而新类被称为子类。 子类不仅可以继承父类的所有属性和方法,还可以定义自己的属性和方法,实现代码复用和扩展。 - **语法**:class 子类名(父类1, 父类2, ...):(支持多继承)。 - **super()函数**:在子类中调用父类的方法(尤其是\__init__方法)。 例如:**单继承(Student类继承Person类)** ```python class Person: """人类类,包含姓名、年龄属性和说话方法""" # 类属性(所有人类的物种都是"智人") species = "智人" # 构造方法:初始化实例属性name和age def __init__(self, name, age): self.name = name # 实例属性:姓名(每个实例独有) self.age = age # 实例属性:年龄(每个实例独有) # 实例方法:说话 def speak(self, content): print(f"{self.name}说:{content}") # 通过self访问实例属性name class Student(Person): # 继承自Person类 """学生类,继承自人类,新增学号属性和学习方法""" def __init__(self, name, age, student_id): # 调用父类的__init__方法初始化name和age super().__init__(name, age) self.student_id = student_id # 新增实例属性:学号 # 新增实例方法:学习 def study(self, course): print(f"{self.name}(学号:{self.student_id})正在学习{course}") # 覆盖父类的speak方法(重写) def speak(self, content): print(f"学生{self.name}说:{content}") # 自定义实现 # 实例化Student类 student = Student("王五", 20, "2023001") # 调用继承自父类的属性和方法 print(student.age) # 输出:20(继承自Person) student.speak("我是一名学生") # 输出:学生王五说:我是一名学生(覆盖后的方法) # 调用子类新增的属性和方法 print(student.student_id) # 输出:2023001 student.study("Python") # 输出:王五(学号:2023001)正在学习Python ``` 输出结果: ```python 20 学生王五说:我是一名学生 2023001 王五(学号:2023001)正在学习Python ``` **多继承(一个类继承多个父类)** ```python class A: def method_a(self): print("A类的方法") class B: def method_b(self): print("B类的方法") class C(A, B): # 同时继承A和B pass c = C() c.method_a() # 输出:A类的方法(继承自A) c.method_b() # 输出:B类的方法(继承自B) ``` 输出结果: ```python A类的方法 B类的方法 ``` **注意**:多继承可能导致 “菱形问题”(多个父类继承自同一祖先类),需注意方法调用顺序(遵循 MRO:方法解析顺序)。 ## 多态 多态指**不同类的对象**对**相同方法名**的调用,表现出不同的行为,即 “同一接口,不同实现”。 ```python class Cat: def sound(self): print("喵喵喵") class Dog: def sound(self): print("汪汪汪") class Duck: def sound(self): print("嘎嘎嘎") # 统一接口:接收任意实现了sound方法的对象 def make_sound(animal): animal.sound() # 调用相同方法名,表现不同行为 # 多态体现:不同对象调用相同方法,结果不同 cat = Cat() dog = Dog() duck = Duck() make_sound(cat) # 输出:喵喵喵 make_sound(dog) # 输出:汪汪汪 make_sound(duck) # 输出:嘎嘎嘎 ``` 输出结果: ```python 喵喵喵 汪汪汪 嘎嘎嘎 ``` **多态的核心是 “接口一致性”,无需关心对象具体类型,只需调用统一方法,提高代码灵活性。** ## 类方法 类方法(@classmethod)是**与类本身绑定的方法**,而非与实例绑定,主要用于操作 “类属性”(所有实例共享的数据)或实现与类相关的逻辑(如创建类的实例)。 用 @classmethod 装饰器定义,第一个参数必须是 cls(代表当前类本身,类似实例方法的self,但指向类),后续参数根据需求定义: ```python class 类名: @classmethod def 类方法名(cls, 参数1, 参数2, ...): # 方法体(可通过cls访问类属性或调用其他类方法) pass ``` - **cls的作用**:类似于实例方法的self,但cls指向 “类” 而非 “实例”,用于访问类属性、调用其他类方法,或创建类的实例。 - **调用方式**:可通过**类名**直接调用(推荐),也可通过**实例**调用(但不推荐,语义上不合理)。 在 Python 中,pass是一个**空语句**,本身不执行任何操作,仅作为**占位符**使用。在类方法(或任何函数、类、代码块)中使用pass,主要是为了**保持语法结构的完整性**,避免因 “没有具体代码” 而导致的语法错误。 例如:类方法操作类属性。 ```python class Dog: # 类属性:所有狗共享的物种信息 species = "哺乳动物" def __init__(self, name): self.name = name # 实例属性 # 类方法:修改类属性 @classmethod def update_species(cls, new_species): cls.species = new_species # 通过cls访问并修改类属性 # 类方法:获取类属性 @classmethod def get_species(cls): return f"物种:{cls.species}" # 1. 通过类名调用类方法(无需创建实例) print(Dog.get_species()) # 输出:物种:哺乳动物 # 2. 修改类属性 Dog.update_species("犬科动物") print(Dog.get_species()) # 输出:物种:犬科动物 # 3. 所有实例共享修改后的类属性 dog1 = Dog("布鲁斯") dog2 = Dog("Tom") print(dog1.species) # 输出:犬科动物(实例访问类属性) print(dog2.species) # 输出:犬科动物 ``` 输出结果: ```python 物种:哺乳动物 物种:犬科动物 犬科动物 犬科动物 ``` **类方法主要用于访问和修改 “类属性”(定义在类中、方法外的属性,所有实例共享),无需创建实例即可调用(通过类名直接调用)。** ## 静态方法 静态方法(@staticmethod)是**定义在类中的独立函数**,既不依赖于类(无cls参数),也不依赖于实例(无self参数),仅逻辑上属于该类(类似 “工具函数”)。 用 @staticmethod 装饰器定义,**没有默认参数**(既不用self也不用cls): ```python class 类名: @staticmethod def 静态方法名(参数1, 参数2, ...): # 方法体(不访问类属性或实例属性) pass ``` **调用方式**:可通过**类名**调用(推荐),也可通过**实例**调用,但均无法访问类或实例的属性。 例如: ```python class MathUtils: # 静态方法:计算两个数的最大公约数(与类/实例状态无关) @staticmethod def gcd(a, b): while b != 0: a, b = b, a % b return a # 静态方法:计算两个数的最小公倍数 @staticmethod def lcm(a, b): return a * b // MathUtils.gcd(a, b) # 调用同类中的其他静态方法 # 1. 通过类名调用静态方法(无需创建实例) print(MathUtils.gcd(12, 18)) # 输出:6 print(MathUtils.lcm(12, 18)) # 输出:36 # 2. 也可通过实例调用(但无必要,因为不依赖实例) mu = MathUtils() print(mu.gcd(8, 12)) # 输出:4 ``` 输出结果: ```python 6 36 4 ``` ## 实例方法 在 Python 类中,**实例方法(Instance Method)** 是最常用的方法类型,它是**与类的实例(对象)绑定的方法**,依赖于具体实例的状态(属性),主要用于实现实例的行为(如 “说话”“走路” 等操作)。 实例方法的本质是 “**属于具体对象的方法**”,它必须通过实例调用,且能直接访问和操作该实例的属性(每个实例的属性可能不同)。其核心特征包括: - 依赖实例:必须通过类的实例(而非类本身)调用; - 访问实例状态:通过特殊参数self访问当前实例的属性和其他实例方法; - 实现对象行为:描述实例能执行的操作(如 “小狗坐下”“用户登录” 等)。 实例方法通过def在类中定义,**第一个参数必须是self**(代表当前实例,类似其他语言的this),后续参数根据需求定义。语法结构如下: ```python class 类名: def 实例方法名(self, 参数1, 参数2, ...): # 方法体:可通过self访问实例属性或调用其他实例方法 # 例如:self.属性名(访问实例属性)、self.其他方法名()(调用其他实例方法) pass ``` **调用方式**:必须通过**实例**调用(如实例名.方法名(参数)),不能直接通过类名调用(除非手动传入实例作为self,但这不符合语法设计意图) 例如: ```python class Dog: # 构造方法:初始化实例属性name def __init__(self, name): self.name = name # 实例属性:每只狗的名字 # 实例方法:小狗坐下(依赖实例的name属性) def sit(self): print(f"{self.name} 坐下了!") # 通过self访问实例属性name # 实例方法:小狗打滚(调用其他实例方法) def roll_over(self): self.sit() # 调用当前实例的sit()方法 print(f"{self.name} 打滚了!") # 创建实例(对象) dog1 = Dog("布鲁斯") dog2 = Dog("Tom") # 通过实例调用实例方法 dog1.sit() # 输出:布鲁斯 坐下了!(self指向dog1) dog2.roll_over() # 输出:Tom 坐下了!\nTom 打滚了!(self指向dog2) ``` 输出结果: ```python 布鲁斯 坐下了! Tom 坐下了! Tom 打滚了! ``` | 维度 | 实例方法 | 类方法(@classmethod) | 静态方法(@staticmethod) | | ------------ | -------------------------- | ------------------------------ | -------------------------- | | 装饰器 | 无 | @classmethod | @staticmethod | | 第一个参数 | self(代表实例) | cls(代表类) | 无默认参数 | | 调用方式 | 必须通过实例调用 | 类名或实例调用(推荐类名) | 类名或实例调用(推荐类名) | | 访问属性能力 | 可访问实例属性和类属性 | 可访问类属性,不可访问实例属性 | 不可访问任何属性 | | 核心用途 | 操作实例状态、实现实例行为 | 操作类属性、创建实例 | 工具函数(与状态无关) | ## 构造方法[了解] 在面向对象编程(OOP)中,**构造方法(Constructor)** 是类中一种**特殊的方法**,其核心作用是:**在创建类的实例(对象)时自动调用,为实例初始化属性、分配资源或执行必要的初始化逻辑**,确保实例创建后能直接处于 “可用状态”(即拥有必要的属性和初始值)。 可以把构造方法理解为 “**实例的初始化工具**”: - 类是 “对象的模板”,而构造方法就是 “用模板造对象时,自动执行的初始化步骤”(比如给 “手机模板” 造具体手机时,自动设置品牌、型号等初始信息)。 - 没有构造方法时,实例创建后可能是 “空的”(无属性),需要手动添加属性;有了构造方法,实例创建时会自动绑定属性,无需手动操作。 在 Python 中,严格意义上的 “构造方法” 核心是负责**实例创建**和**初始化**的特殊方法。 “构造” 直接相关: ```txt __new__(实例创建)和__init__(实例初始化) ``` \__new__是 Python 中**唯一负责创建实例**的特殊方法(位于\_\_init\_\_之前执行),它为实例分配内存空间并返回新创建的实例。 - 属于类方法(第一个参数是cls,代表类本身); - 必须返回一个实例(通常是cls的实例,即return super().\__new__(cls)); - 极少手动定义,仅在需要自定义实例创建逻辑时使用(如单例模式、限制实例数量等)。 例如:用\__new__实现单例模式(确保类只有一个实例) ```python class Singleton: _instance = None # 存储唯一实例 def __new__(cls, *args, **kwargs): # 如果实例不存在,创建并保存;否则直接返回已有的实例 if not cls._instance: cls._instance = super().__new__(cls) # 调用父类的__new__创建实例 return cls._instance def __init__(self, name): self.name = name # 初始化实例(但仅第一次创建时有效) # 无论创建多少次,都指向同一个实例 s1 = Singleton("实例1") s2 = Singleton("实例2") print(s1 is s2) # 输出:True(s1和s2是同一个对象) print(s1.name) # 输出:实例2(第二次初始化覆盖了第一次的值) ``` 输出结果: ```python True 实例2 ``` 在 Python 中,构造方法的另一个特殊名称是\_\_init\_\_(双下划线__ + init + 双下划线__,全称 “initialize”,即 “初始化”)。 它是 Python 类中最常用的 “特殊方法” 之一,负责在\_\_new\_\_创建实例后初始化实例属性(为实例绑定数据)。 - 第一个参数是self(代表刚创建的实例); - 无返回值(必须返回None); - 实例创建时自动调用(在\_\_new\_\_之后执行)。 例如: ```python class Person: def __new__(cls, *args, **kwargs): print("__new__:创建实例") return super().__new__(cls) # 调用父类创建实例 def __init__(self, name): print("__init__:初始化实例") self.name = name # 绑定属性 p = Person("张三") ``` 输出结果: ```python __new__:创建实例 __init__:初始化实例 ``` 当通过 类名(参数) 创建实例时,Python 会**自动调用\_\_init\_\_方法**,无需手动调用。 ```python class Dog: # 构造方法:初始化name和age属性 def __init__(self, name, age): self.name = name # 为实例绑定name属性 self.age = age # 为实例绑定age属性 # 创建实例时,Python自动调用__init__(dog1, "布鲁斯", 10) dog1 = Dog("布鲁斯", 10) ``` 必须有self参数,\_\_init\_\_的第一个参数必须是 self(代表 “当前正在创建的实例”),用于将属性 “绑定” 到实例上。 - self是 Python 的约定俗成,不能省略(否则会报错,因为 Python 会强制传递实例作为第一个参数)。 - 通过 self.属性名 = 参数 的语法,将外部传入的参数转化为实例的 “独有属性”(每个实例的属性值独立)。 支持参数(包括默认参数),\_\_init\_\_可以定义除self外的其他参数(用于接收初始化实例所需的数据),也支持默认参数(简化实例创建)。 ```python class Dog: # 给age设置默认值1(创建实例时可省略age) def __init__(self, name, age=1): self.name = name self.age = age # 省略age,使用默认值1 dog1 = Dog("布鲁斯") print(dog1.age) # 输出:1 # 传入age,覆盖默认值 dog2 = Dog("Tom", 3) print(dog2.age) # 输出:3 ``` 输出结果: ```python 1 3 ``` ## 析构方法[了解] 在 Python 中,**析构方法(Destructor)** 是类中用于**对象销毁时自动执行资源清理**的特殊方法,其核心作用与构造方法(\_\_init\_\_)相反:构造方法负责对象创建时的初始化(如分配资源),而析构方法负责对象销毁时的收尾工作(如释放资源)。 Python 中析构方法的固定名称是\_\_del\_\_(双下划线包裹),其语法结构如下: ```python class 类名: def __del__(self): # 资源清理逻辑(如关闭文件、断开连接等) pass ``` - **self参数**:代表当前被销毁的实例,通过self可访问实例的属性(如需要清理的资源对象)。 - **无返回值**:\_\_del\_\_仅用于执行操作,不允许返回任何值。 析构方法的调用由 Python 的**垃圾回收机制**自动触发,具体时机取决于对象的 “引用计数”(即当前有多少变量指向该对象): 1. **当对象的引用计数变为 0**:即没有任何变量引用该对象时,Python 会销毁对象并调用\_\_del\_\_。 2. **程序结束时**:所有未被销毁的对象会被统一回收,此时它们的\_\_del\_\_会被调用。 例如: ```python class Demo: def __init__(self, name): self.name = name print(f"对象 {self.name} 被创建") def __del__(self): print(f"对象 {self.name} 被销毁(析构方法调用)") # 场景1:引用计数变为0 obj1 = Demo("A") obj1 = None # 解除引用,A的引用计数变为0 → 触发析构 # 场景2:程序结束时回收 obj2 = Demo("B") print("程序执行中...") # 程序结束时,obj2仍被引用 → 自动销毁并触发析构 ``` 输出结果: ```python 对象 A 被创建 对象 A 被销毁(析构方法调用) 对象 B 被创建 程序执行中... 对象 B 被销毁(析构方法调用) ``` 析构方法的主要价值是**自动清理对象生命周期中占用的外部资源**,避免 “资源泄漏”(资源被占用但无法释放,导致系统资源耗尽)。常见应用场景包括: - **关闭文件**:释放文件句柄(避免文件被长期锁定); - **断开连接**:释放数据库、网络服务器的连接(避免连接池耗尽); - **清理缓存**:释放对象创建的临时内存数据; - **记录日志**:记录对象销毁时间或状态(用于调试或审计)。 ## 特殊方法(魔术方法)[了解] Python 类中以双下划线\_\_开头和结尾的方法(如\_\_init\_\_)称为 “特殊方法” 或 “魔术方法”,用于自定义类的行为(如初始化、字符串表示、运算等)。 常见特殊方法: | 方法名 | 作用 | 示例 | | ------------ | ----------------------------------------- | ------------------------------------------------------------ | | \_\_init\_\_ | 初始化实例(构造方法) | def \_\_init\_\_(self, name): self.name = name | | \_\_str\_\_ | 定义对象的字符串表示(str(obj)调用) | def \_\_str\_\_(self): return f"Person({self.name})" | | \_\_repr\_\_ | 定义对象的官方字符串表示(repr(obj)调用) | def \_\_repr\_\_(self): return f"Person(name='{self.name}')" | | \_\_add\_\_ | 自定义加法运算(obj1 + obj2调用) | def \_\_add\_\_(self, other): return self.age + other.age | | \_\_len\_\_ | 自定义长度(len(obj)调用) | def \_\_len\_\_(self): return len(self.name) | 例如: ```python class Point: def __init__(self, x, y): self.x = x self.y = y # 自定义字符串表示 def __str__(self): return f"Point({self.x}, {self.y})" # 自定义加法(点的坐标相加) def __add__(self, other): return Point(self.x + other.x, self.y + other.y) p1 = Point(1, 2) p2 = Point(3, 4) print(p1) # 输出:Point(1, 2)(调用__str__) p3 = p1 + p2 # 调用__add__ print(p3) # 输出:Point(4, 6) ``` 输出结果: ```python Point(1, 2) Point(4, 6) ``` ## 类与对象的关系 - **类**是抽象的模板(如 “汽车设计图”),定义了属性和方法的结构; - **对象**是类的具体实例(如 “一辆具体的特斯拉汽车”),拥有类定义的属性和方法的具体值; - 一个类可以创建**多个对象**,对象之间的属性相互独立(实例属性不同),但共享类的方法和类属性。 ## 从模块中导入类 在 Python 中,**导入类**是实现代码复用和模块化的核心方式 —— 当类定义在其他模块(.py文件)中时,通过导入操作可以在当前文件中使用这些类,避免重复编写代码,同时让项目结构更清晰。 - **模块**:一个扩展名为.py的 Python 文件就是一个模块,可包含类、函数、变量等代码。 - **类的存放**:类通常定义在模块中(如dog.py中定义Dog类),通过导入模块中的类,可在其他文件中使用该类创建实例、调用方法。 例如:当前有一个模块animal.py,其中定义了两个类。 ```python # animal.py class Dog: def __init__(self, name): self.name = name def bark(self): print(f"{self.name} 在汪汪叫") class Cat: def __init__(self, name): self.name = name def meow(self): print(f"{self.name} 在喵喵叫") ``` **1.从模块导入单类** 语法:from 模块名 import 类名;适用场景:只需使用模块中的某个类。 ```python # main.py from animal import Dog # 从animal模块导入Dog类 # 使用导入的类创建实例 my_dog = Dog("旺财") my_dog.bark() # 输出:旺财 在汪汪叫 ``` **2.从模块导入多类** 语法:from 模块名 import 类名1, 类名2, ...;适用场景:需要使用模块中的多个类,且类名较少。 ```python # main.py from animal import Dog, Cat # 导入Dog和Cat两个类 my_dog = Dog("旺财") my_cat = Cat("汤姆") my_dog.bark() # 输出:旺财 在汪汪叫 my_cat.meow() # 输出:汤姆 在喵喵叫 ``` **3.导入整个模块,再使用类** 语法:import 模块名,使用时通过模块名.类名调用;适用场景:需要使用模块中的多个类,且希望明确类的来源(避免命名冲突)。 ```python # main.py import animal # 导入整个animal模块 # 通过“模块名.类名”使用类 my_dog = animal.Dog("旺财") my_cat = animal.Cat("汤姆") my_dog.bark() # 输出:旺财 在汪汪叫 my_cat.meow() # 输出:汤姆 在喵喵叫 ``` **4.导入类并使用别名** 语法:from 模块名 import 类名 as 别名;适用场景:当导入的类名与当前文件中的类名 / 变量名冲突时,可通过as指定别名。 ```python # main.py class Dog: # 当前文件中已有Dog类 def __init__(self, name): self.name = name # 导入animal模块的Dog类,并指定别名为AnimalDog from animal import Dog as AnimalDog my_dog1 = Dog("本地狗") # 使用当前文件的Dog类 my_dog2 = AnimalDog("模块狗") # 使用导入的Dog类(别名) my_dog2.bark() # 输出:模块狗 在汪汪叫 ``` **5.导入模块并指定别名** 语法:import 模块名 as 别名;适用场景:当模块名较长时,可通过as给模块指定别名,简化后续调用。 ```python # main.py import animal as ani # 导入animal模块,别名为ani my_dog = ani.Dog("旺财") # 通过别名调用类 my_dog.bark() # 输出:旺财 在汪汪叫 ``` **6.导入模块中所有类** 语法:from 模块名 import *(*表示 “所有”)。 ```python # main.py from animal import * # 导入animal模块中所有类 my_dog = Dog("旺财") my_cat = Cat("汤姆") # 功能可行,但不推荐在大型项目中使用 ``` ## 从包中导入类 当项目结构复杂时,多个模块会被组织成**包**(包含\_\_init\_\_.py文件的文件夹)。假设项目结构如下: ```txt my_project/ ├── pets/ # 包名 │ ├── __init__.py # 包标识文件(可空) │ ├── dog.py # 含Dog类 │ └── cat.py # 含Cat类 └── main.py ``` `dog.py`内容: ```python # pets/dog.py class Dog: def __init__(self, name): self.name = name def bark(self): print(f"{self.name} 汪汪叫") ``` **1.从包的子模块导入类** ```python # main.py from pets.dog import Dog # 从pets包的dog模块导入Dog类 my_dog = Dog("旺财") my_dog.bark() # 输出:旺财 汪汪叫 ``` **2.导入包的子模块,再使用类** ```python # main.py import pets.dog # 导入pets包的dog模块 my_dog = pets.dog.Dog("旺财") my_dog.bark() # 输出:旺财 汪汪叫 ``` **3.给包或者子模块指定别名** ```python # main.py from pets.dog import Dog as PetDog # 类别名 import pets.cat as cat_module # 模块别名 my_dog = PetDog("旺财") my_cat = cat_module.Cat("汤姆") # 假设cat.py中有Cat类 ```
毛林
2025年9月7日 11:45
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码