python 魔术方法
一、什么是魔术方法
1、魔术方法是一组具有特殊命名和行为的特殊方法,它们允许您自定义类的行为。这些方法使用双下划线(__)作为前缀和后缀,因此也被称为双下划线方法或特殊方法。
2、需要掌握每个方法什么时候触发或者执行
二、常见的魔术方法
1、__init__方法
初始化方法,当一个类被调用产生实例对象,自动触发,它可以用来初始化对象的属性和执行其他必要的设置。
2、__str__和__repr__方法
class Student():
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def __str__(self):
print('str')
return '%s %s' % (self.name, self.age)
def __repr__(self):
print('repr')
return '%s' % self.name
stu = Student('kevin', 18, 'male')
print(stu)
# str
# kevin 18
注:
__str__和__repr__差不多,同时使用时,__str__会被优先执行,__repr__不执行
当打印或者输出对象的时候,会自动触发__str__(self)的执行
__str__(self): 只能返回字符串,它被print()函数和str()函数调用,可以用来自定义对象的打印输出。
__repr__的补充:
__repr__(self): 返回对象的可打印表示。它被repr()函数调用,通常用于调试目的。
-
__repr__就是帮对象“自我介绍”的方法。 -
没有它,Python 只告诉你对象的类型和内存地址。
-
有了它,对象可以直接输出所有关键信息,非常方便调试和阅读。
class User:
def __init__(self, name, age, vip=False):
self.name = name
self.age = age
self.vip = vip
def __repr__(self):
return f'User(name={self.name!r}, age={self.age}, vip={self.vip})'
u = User('Alice', 20, True)
print(u)
有__repr__(self)的时候:
User(name='Alice', age=20, vip=True)
没有的时候
<__main__.User object at 0x7f8e3d5a0>
3、_len__(self): 返回对象的长度。
它被len()函数调用,用于获取对象的元素个数。
4、__del__方法
用于定义对象被销毁(垃圾回收)时的行为。它在对象的引用计数达到零时自动被调用。
class Student():
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
self.f = open("a.txt", "w", encoding="utf8")
# 我执行了:
# 1. 当删除对象的时候,会自动触发函数的执行
# 2. 当程序结束的时候,也会自动触发执行
def __del__(self):
print("我执行了")
"""可以做一些清理垃圾的操作"""
self.f.close()
stu = Student("kevin", 19, 'male')
# del stu # 有删除对象的操作,会立即触发__del__(self)
print("1")
print("12")
print("123")
# 1
# 12
# 123
# 我执行了
注:
当对象被销毁会触发执行__del__(self)
没有对象被销毁操作时,程序代码执行完也会触发执行__del__(self)
5、 isinstance(obj,cls) 和 issubclass(sub,super)
isinstance(obj,cls) 函数判断对象是不是由某个类实例化的,返回布尔值
issubclass(sub,super) 函数也可以用于检查一个类是否是多个类中的任何一个类的子类
print(issubclass(Dog, (Animal, Mammal)))
6、__doc__
document:可以查看出类内部的详细信息,其实就是注释里面的内容
这个特性不能够继承到父类
class MyClass:
"""This is a docstring for MyClass."""
pass
print(MyClass.__doc__) # 输出 "This is a docstring for MyClass."
7、__enter__和__exit__
是用于实现上下文管理器的两个特殊方法
__enter__(self): __enter__() 方法在进入上下文管理器(遇到with)时被调用,并返回一个对象。通常,它被用来执行一些准备工作,例如初始化资源、设置环境等。返回的对象(如果有)会被赋值给与 with 语句关联的目标变量 as 后的 f 变量。
__exit__(self, exc_type, exc_value, traceback):
__exit__() 方法在离开上下文管理器时被调用。它接受三个参数,用于处理异常情况。如果代码块正常执行完毕,这些参数都为 None。如果发生异常,这些参数将包含异常的类型、值和回溯信息。__exit__() 方法负责清理资源、处理异常或执行其他必要的操作。
class open:
def __init__(self, name):
self.name = name
def __enter__(self):
# 执行进入上下文前的准备工作
print("Entering the context")
return self # 可选,返回一个对象
def __exit__(self, exc_type, exc_value, traceback):
# 执行离开上下文时的清理工作
print("Exiting the context")
if exc_type is not None:
# 处理异常
print(f"Exception occurred: {exc_type}, {exc_value}")
# 使用上下文管理器
with open('a.txt') as f:
# 执行一些操作
print("Inside the context")
# Entering the context # 遇到with先执行__enter__方法
# Inside the context # 再执行with 下的代码
# Exiting the context # 最后执行__exit__方法
补充:对上下文管理器的with的理解
当使用 with 语句时,Python 会自动管理上下文管理器的获取和释放,以确保资源的正确获取和释放,即使在出现异常的情况下也能正常工作。这是通过遵循上下文管理协议来实现的。
上下文管理协议要求上下文管理器对象必须定义 __enter__() 和 __exit__() 两个方法。它们分别用于进入上下文和离开上下文时的操作。
具体来说,with 语句的工作流程如下:
-
with语句获取上下文管理器对象:- 调用上下文管理器的
__enter__()方法,该方法可能返回一个对象,并将其绑定到as子句中指定的变量上。如果没有指定as子句,则返回的对象被丢弃。
- 调用上下文管理器的
-
执行
with语句块:- 执行
with语句块中的代码,执行相关的操作。
- 执行
-
离开上下文:
- 无论
with语句块是否发生异常,都会调用上下文管理器的__exit__()方法进行资源的释放和清理。 - 如果
with语句块正常执行完毕,或者没有发生异常,__exit__()方法的参数都为None。 - 如果
with语句块发生异常,异常的类型、值和回溯信息将传递给__exit__()方法的参数,可以在该方法内部处理异常。
- 无论
上下文管理协议的优点是它提供了一种统一、可靠的方式来管理资源,无论是否发生异常,都能保证资源的释放。这样可以避免资源泄露和其他潜在的问题。通过使用 with 语句,可以提高代码的可读性,并使资源管理更加简洁和安全。
8、__call__
对象后面加括号,触发执行。
本质上就是类里面定义了一个函数,类实例化后的对象➕括号调用该函数
class CallableClass:
def __call__(self, *args, **kwargs):
print("Calling the object")
# 创建一个对象
obj = CallableClass()
# 调用对象
obj() # 输出:"Calling the object"
____________
class CallableClass:
def __call__(self, *args, **kwargs):
print("Calling the object with arguments:")
print("Positional arguments:", args)
print("Keyword arguments:", kwargs)
# 创建一个对象
obj = CallableClass()
# 调用对象并传递参数
obj(1, 2, foo='bar')
9、访问、设置、删除对象提供自定义行为
__setattr__, __delattr__, __getattr__ 使用(.)句点法 object.key = value进行赋值操作
__setitem__, __delitem__, __getitem__ 使用使用 object[key] = value进行赋值操作
用于在访问、设置和删除对象的属性时提供自定义行为
-
__setattr__(self, name, value):- 当给对象的属性赋值时被调用。
- 它可以被用来在属性赋值前执行一些额外的逻辑或进行验证。
- 参数
name是要设置的属性名,value是要赋给属性的值。 - 在
__setattr__方法内部,通常应该使用self.__dict__[name] = value来设置属性值,以避免无限递归调用。
-
__delattr__(self, name):- 当删除对象的属性时被调用。
- 它可以用来在属性删除前执行一些清理操作或进行验证。
- 参数
name是要删除的属性名。
-
__getattr__(self, name):- 当访问对象的属性失败时被调用。
- 它可以用来处理对不存在属性的访问,或者实现属性的延迟加载。
- 参数
name是要访问的属性名。 __getattr__方法应该返回属性的值或引发AttributeError异常。
class MyClass:
def __setattr__(self, name, value): # attribute 属性
print(f"Setting attribute: {name} = {value}")
self.__dict__[name] = value
def __delattr__(self, name):
print(f"Deleting attribute: {name}")
del self.__dict__[name]
def __getattr__(self, name):
print(f"Getting attribute: {name}")
raise AttributeError(f"Attribute '{name}' not found")
# 创建对象
obj = MyClass()
# 设置属性
obj.attr1 = "Value 1" # 调用 __setattr__()
# 获取属性
print(obj.attr1) # 直接访问,不会调用 __getattr__()
# Setting attribute: attr1 = Value 1
# Value 1
# 访问不存在的属性
print(obj.attr2) # 调用 __getattr__()
# 删除属性
del obj.attr1 # 调用 __delattr__()
10、__new__
Python 中的一个特殊方法(special method),用于在创建一个新的实例(对象)时被调用。
它是在对象实例化的过程中执行的第一个方法,负责创建并返回一个新的实例。__new__ 方法的主要作用是控制对象的创建过程,它在 __init__ 方法之前调用。
__new__ 方法接收的参数与普通方法一样,但与普通方法不同的是,第一个参数不是 self,而是类本身(通常被命名为 cls)。
__new__ 方法必须返回一个新的实例,通常是通过调用父类的 __new__ 方法来实现的。
一般情况下,我们很少直接重写 __new__ 方法,因为大部分情况下使用默认的 object.__new__ 就足够了。但在某些特殊情况下,比如定制不可变对象,或者在创建对象时需要做一些额外的处理,重写 __new__ 方法可能是有用的。
class MyClass:
def __new__(cls, *args, **kwargs):
# 调用父类的 __new__ 方法来创建新实例
instance = super().__new__(cls)
# 可以在这里对实例进行额外的初始化或处理
return instance
def __init__(self, arg1, arg2):
# 在 __new__ 方法之后,由 __init__ 方法完成实例的初始化
self.arg1 = arg1
self.arg2 = arg2
# 创建实例时会调用 __new__ 方法,并将实例传递给 __init__ 方法
obj = MyClass("Hello", "World")
11、__eq__ 方法
默认比较的是实例对象内存地址,而__eq__ 方法重写了比较,在这里名字和年龄相同就是同一个对象
class User:
def __init__(self, name, age, vip=False):
self.name = name
self.age = age
self.vip = vip
def __eq__(self, other):
return isinstance(other, User) and (self.name, self.age, self.vip) == (other.name, other.age, other.vip)
u1 = User("Alice", 25)
u2 = User("Alice", 25)
print(u1 == u2) # 如果没有 __eq__,结果是 False(即使内容一样)
好处
- 更符合直觉:我们通常认为,两个用户如果名字、年龄、VIP状态都一样,就是“同一个人”或“等价用户”,即使它们是不同的对象。
- 支持集合操作:比如把
User对象放入set或作为dict的 key(前提是也实现__hash__),需要正确的相等判断。 - 便于测试和比较:在单元测试中经常需要判断两个对象是否具有相同的数据。

浙公网安备 33010602011771号