一、构造函数__init__()
1.1 构造函数基础
在Python中,__init__() 方法是一个特殊的方法,被称为类的构造函数(constructor)。它主要用于在创建类的新实例(对象)时初始化该对象的属性。每当通过类创建对象时,Python会自动调用这个方法
作用:通常用来做属性初始化或者赋值操作
注意:在类实例化对象的时候,会被自动调用
eg:
# 注意:在类实例化对象的时候,会被自动调用
class Test:def __init__(self): # self---一个实例方法print("这是__init__()函数")
# 实例化对象:对象名 = 类名()
te = Test()
# 输出结果:这是__init__()函数
以下是一些关于 __init__() 方法的要点:
命名:方法名必须是 __init__,并且前后各有两个下划线
参数:第一个参数通常是 self,它代表类的实例本身。在调用方法时,不需要显式传递 self 参数,Python会自动处理,其他参数用于初始化对象的属性
初始化属性:在 __init__ 方法内部,可以使用 self 来访问和设置对象的属性
没有返回值:构造函数不应该有返回值(实际上,如果尝试返回非 None 的值,会导致 TypeError)
1.2 构造函数举例
那么为什么我们要选择使用构造函数呢,举一个小小的例子说明一下:
class Person: # 人类def __init__(self):self.name = "junjun" # 实例属性 姓名self.age = 18 # 年龄self.height = 163 # 身高def play(self):print(f'{self.name}在打王者荣耀')def introduce(self):print(f"{self.name}的年龄是{self.age},身高是{self.height}cm")
# 实例化对象
pe = Person()
pe.play()
pe.introduce()
# 实例化第二个对象
pe2 = Person()
pe2.play()
pe2.introduce()
# 输出结果:
# junjun在打王者荣耀
# junjun的年龄是18,身高是163cm
# junjun在打王者荣耀
# junjun的年龄是18,身高是163cm
在这个例子中,如果想要更改输出结果必须要在实例属性位置一 一修改,很麻烦,这时就需要用到我们的构造函数了
class Person: def __init__(self, name, age): self.name = name # 初始化属性 name self.age = age # 初始化属性 age # 创建 Person 类的实例
person1 = Person("Alice", 30)
person2 = Person("Bob", 25) # 访问对象的属性
print(person1.name) # 输出: Alice
print(person1.age) # 输出: 30
print(person2.name) # 输出: Bob
print(person2.age) # 输出: 25
在这个例子中,Person 类有一个构造函数 __init__(),它接受三个参数:self、name 和 age
在创建 Person 类的实例时,传递的 name 和 age 参数被用来初始化对象的 name 和 age 属性
你也可以在 __init__() 方法中执行其他初始化操作,比如设置默认值、进行输入验证等
eg:带有默认值的构造函数
class Person: def __init__(self, name, age=None): self.name = name self.age = age if age is not None else 0 # 如果未提供 age,则默认设置为 0 # 创建 Person 类的实例
person1 = Person("Alice")
person2 = Person("Bob", 25) # 访问对象的属性
print(person1.name) # 输出: Alice
print(person1.age) # 输出: 0
print(person2.name) # 输出: Bob
print(person2.age) # 输出: 25
在这个例子中,age 参数有一个默认值 None,如果创建对象时没有提供 age 参数,则将其设置为 0
二、析构函数 __del__()
删除对象的时候,解释器会默认调用__del__() 方法
2.1 析构函数基础
在 Python 中,析构函数(也称为析构器)是一个特殊的方法,用于在对象被销毁或垃圾回收之前执行清理操作
析构函数的名称是 __del__()(注意双下划线)
当 Python 的垃圾回收机制确定对象不再被引用时,它会调用这个方法来释放对象所占用的资源,比如关闭文件、释放网络连接等
2.2 __del__() 方法的一些关键点
调用时机:__del__() 方法是在对象生命周期结束时调用的,这通常发生在对象不再被任何变量引用时。然而,确切的调用时机是由垃圾回收机制决定的,因此它是不可预测的
手动删除:即使对象仍被引用,如果显式地调用 del 语句来删除对象的引用,Python 也不会立即调用 __del__() 方法,而是等到对象实际上被垃圾回收时才调用
异常处理:如果在 __del__() 方法中抛出了异常,这个异常通常会被忽略,并且不会传播到调用者。这意味着在析构函数中处理异常时需要格外小心
循环引用:在涉及循环引用的复杂对象中,垃圾回收可能会变得复杂。在这种情况下,__del__() 方法可能永远不会被调用
资源管理:虽然 __del__() 方法可以用于资源管理,但更好的做法是使用上下文管理器(通过实现 __enter__() 和 __exit__() 方法)和 with 语句。这种方式可以确保资源在块结束时被正确释放,即使发生异常也是如此
继承:如果子类没有定义自己的 __del__() 方法,它会继承父类的 __del__() 方法。如果子类定义了 __del__() 方法,并且还想调用父类的 __del__() 方法,那么需要显式地调用 super().__del__()
2.3 __del__() 举例
1、正常运行时,不会调用__del__(),对象执行结束之后,系统会自动调用__del__()
eg:
class Person:def __init__(self):print("我是__init__()")def __del__(self):print("被销毁了")
p = Person()
print("这是倒数第二行代码")
print("这是最后一行代码")
# 输出结果:
# 我是__init__()
# 这是倒数第二行代码
# 这是最后一行代码
# 被销毁了
2、删除对象的时候,解释器会默认调用_del()方法
在 Python 中,当对象不再被任何变量引用,并且垃圾回收器决定回收该对象的内存时,解释器会调用该对象的 __del__() 方法(如果定义了的话)
然而,需要注意的是,__del__() 方法的调用并不是由 del 语句直接触发的,而是由垃圾回收机制在对象生命周期结束时进行的。
del 语句的作用是删除对对象的引用,使对象成为垃圾回收的目标。但是,实际的内存回收和 __del__() 方法的调用是由 Python 的垃圾回收器在后台管理的,并且这个过程是异步的,不可预测的。
eg:
class MyClass: def __init__(self, name): self.name = name print(f"Object {self.name} created.") def __del__(self): print(f"Object {self.name} destroyed (__del__ called).") # 创建一个对象并赋值给变量 obj
obj = MyClass("ExampleObject") # 此时,obj 引用了一个 MyClass 对象 # 使用 del 语句删除对对象的引用
del obj # 此时,MyClass 对象不再被 obj 引用
# 但是,__del__() 方法可能还没有被调用
# 因为垃圾回收器还没有决定回收这个对象的内存 # 为了演示目的,我们可以强制进行垃圾回收(通常不推荐这样做)
import gc
gc.collect() # 尝试立即回收垃圾 # 如果垃圾回收器决定回收该对象的内存,
# 它会在此时调用对象的 __del__() 方法
# 输出应该是:Object ExampleObject destroyed (__del__ called).
# 但是,请注意,由于垃圾回收的具体实现和时机,
# 这个输出可能不会在 del 语句之后立即出现。
在这个例子中,del obj 语句删除了对 MyClass 对象的引用,但是 __del__() 方法的调用取决于垃圾回收器的行为
我们通过调用 gc.collect() 来尝试强制垃圾回收,以便观察 __del__() 方法的调用
然而,即使这样,__del__() 方法的调用也不是确定的,因为垃圾回收器可能会决定稍后再回收内存
重要的是要理解,__del__() 方法通常不是进行资源管理的最佳方式
更好的做法是使用上下文管理器(通过实现 __enter__() 和 __exit__() 方法)和 with 语句,这样可以确保资源在块结束时被正确释放,即使发生异常也是如此
__del__() 方法应该仅用于需要在对象销毁时执行特定清理操作的极少数情况
今天的分享就到这里了,糊涂君-Q希望能够帮助到大家,大家有什么疑问欢迎在评论区互相交流,文中有什么错误同样也欢迎大家批评指正,期待和大家共同进步~