目录
1、__getattr__(self, name): 它允许一个对象在尝试访问一个不存在的属性时动态地创建和返回这个属性。
2、__setattr__(self, name, value): 主要负责控制类属性的设置。当尝试给对象的实例或类变量赋值时,Python解释器会自动调用这个方法。
4、__delattr__(self, name): 当尝试删除属性时调用。当尝试删除一个对象的属性时,Python 解释器会自动调用这个方法。
1、__str__(self): 主要用于提供对象的字符串表示形式。当需要将一个对象转换成字符串以便显示或者输出的时候,Python 的内置函数 str() 会调用这个方法。
1、__lt__(self, other): 又称-dunder 方法,定义小于运算符 <。
2、__le__(self, other): 定义小于等于运算符 <=。
3、__eq__(self, other): 定义等于运算符 ==。
4、__ne__(self, other): 定义不等于运算符 !=。
5、__gt__(self, other): 定义大于运算符 >。
6、__ge__(self, other): 定义大于等于运算符 >=。
1、__add__(self, other): 定义加法运算符 +。
2、__sub__(self, other): 定义减法运算符 -。
3、__mul__(self, other): 定义乘法运算符 *。
6、__pow__(self, other[, modulo]), 当对一个类的实例使用乘方运算符 ** 进行计算时,Python 解释器会自动调用这个方法。
Python 中的魔术方法(Magic Methods)是一系列以双下划线开头和结尾的方法,它们在特定场景下会被 Python 解释器自动调用。这些方法让开发者可以定制类的行为,模拟类似内置类型的特性。
一、初始化和清理:
1、构造方法 __init__(self, ...)
: 它是类中定义的一个构造方法,用于在创建类的实例时初始化对象的状态。每当通过 class_name()
创建一个新的类实例时,Python 会自动调用 __init__
方法。
class ClassName:
def __init__(self, parameter1, parameter2, ...):
# 初始化对象的属性或执行必要的设置
self.attribute1 = parameter1
self.attribute2 = parameter2
...
# 示例
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# 创建 Person 类的实例
john = Person("John Doe", 30)
# 访问实例的属性
print(john.name) # 输出: John Doe
print(john.age) # 输出: 30
2、__new__(cls, ...)
: 创建类实例时调用的第一个方法。它是类(class)级别的方法,主要负责创建并返回一个对象实例。当调用 cls()
创建类的新实例时,实际上首先调用的是 __new__
方法,而不是 __init__
方法。
__new__
方法的主要作用包括:
- 控制是否要创建一个新实例。
- 控制新实例的具体类型,即可以返回子类或者其他类型的实例。
- 对于不可变类型(如int、str等),可以通过重写
__new__
来实现自定义的创建行为。
class ClassName:
def __new__(cls, *args, **kwargs):
# 在这里创建并返回一个新的实例
instance = super().__new__(cls)
# 可以对 instance 进行一些初始化操作,但这部分不属于 __new__ 的主要职责,通常在 __init__ 方法中完成
return instance
其中,cls
是当前类,*args
和 **kwargs
则是可以传递给实例构造函数的任意位置参数和关键字参数。这个方法必须返回一个实例对象,如果不返回或者返回非实例对象,则后续的 __init__
方法将不会被调用。
再看一个重写 __new__
方法的例子,创建一个简单的计数器类 Counter,每次创建实例时自动增加一个全局计数,并且确保只创建一个实例,这实现了单例模式的一种形式:
class Counter:
_instance_count = 0
_instances = {}
def __new__(cls, name):
if name not in cls._instances:
cls._instance_count += 1
cls._instances[name] = super().__new__(cls)
cls._instances[name].name = name
cls._instances[name].count = cls._instance_count
return cls._instances[name]
# 使用示例
counter1 = Counter("Instance1")
print(counter1.count) # 输出: 1
counter2 = Counter("Instance2")
print(counter2.count) # 输出: 2
counter3 = Counter("Instance1")
print(counter3 is counter1) # 输出: True,因为"Instance1"只有一个实例
在这个例子中,Counter
类通过重写 __new__
方法来控制实例的创建过程,使得每个不同的名字(name)都只会对应唯一的一个实例,并且每次创建新的实例时,都会更新 _instance_count
属性。
3、__del__(self)
: Python 中的一个特殊方法,称为析构方法或解构方法。当一个对象即将从内存中被删除(垃圾回收)之前,Python 解释器会尝试调用该对象的 __del__
方法。它的主要用途是用于执行一些清理工作,例如关闭文件、网络连接,或者释放其他系统资源等。
然而,需要注意的是:
__del__
方法并不保证一定会被执行,特别是当程序正常退出时,或者引用了该对象的对象自身也在同一时刻被销毁时,可能会导致__del__
方法无法执行。- 不推荐在
__del__
方法中抛出异常,因为处理这种异常的机制并不明确,可能导致未知的行为。 - Python 的垃圾回收机制是基于引用计数和循环检测的,当一个对象的引用计数变为0时,才会触发垃圾回收进而可能执行
__del__
方法。
基本语法格式如下:
class MyClass:
def __init__(self):
# 初始化代码...
def __del__(self):
# 清理工作代码...
print("MyClass object is being deleted.")
# 示例:
obj = MyClass()
# ... 在其他地方使用 obj ...
# 当 obj 不再被任何变量引用,且垃圾回收器准备回收它时,将调用 obj 的 __del__ 方法
尽管 __del__
方法在某些情况下很有用,但建议尽量避免依赖它来进行关键资源的管理,而应尽可能利用上下文管理协议(with语句)或者 try-finally 结构来确保资源能够及时正确地释放。
二、属性访问:
1、__getattr__(self, name)
: 它允许一个对象在尝试访问一个不存在的属性时动态地创建和返回这个属性。
当对一个对象使用getattr
函数或者尝试访问对象中不存在的属性时,__getattr__
方法会被调用。这个方法可以用于实现一些高级的特性,比如懒加载属性或者动态创建属性。 下面是一个简单的例子来说明__getattr__
的用法:
class MyClass:
def __init__(self, name):
self.name = name
def __getattr__(self, item):
return f'属性 "{item}" 在 MyClass 中不存在,但是我会告诉你这个对象叫做 "{self.name}"'
obj = MyClass('我的对象')
print(obj.attr) # 输出: 属性 "attr" 在 MyClass 中不存在,但是我会告诉你这个对象叫做 "我的对象"
在这个例子中,我们定义了一个MyClass
类,它有一个__getattr__
方法。当我们尝试访问obj.attr
时,attr
属性在MyClass
中并不存在,所以__getattr__
方法被调用,并返回了一个字符串,告诉我们这个对象的名字。 需要注意的是,__getattr__
方法应该返回一个值,否则会抛出AttributeError
异常。此外,__getattr__
方法不应该用于替代正常的属性访问,它应该只在尝试访问不存在的属性时使用。
2、__setattr__(self, name, value)
: 主要负责控制类属性的设置。当尝试给对象的实例或类变量赋值时,Python解释器会自动调用这个方法。
在类中定义__setattr__(self, name, value)
方法后,每次尝试给该类的实例属性赋值时,都会执行这个方法,其中:
self
:表示调用该方法的对象实例;name
:要设置的属性名,是一个字符串;value
:要赋予的新值。
class MyClass:
def __setattr__(self, name, value):
if name == 'age':
if not isinstance(value, int):
raise ValueError("Age must be an integer.")
super().__setattr__(name, value)
# 示例
obj = MyClass()
obj.age = 25 # 此处将调用__setattr__方法
在这个例子中,重写了__setattr__
方法,对age
属性进行特殊处理,确保其只能被设置为整数类型。如果尝试设置非整数类型的age,将会抛出一个ValueError异常。
注意,在自定义__setattr__
方法时,通常需要通过super().__setattr__(name, value)
调用父类(在这里是object)的__setattr__
方法来完成实际的属性设置,否则可能会导致属性无法正确设置或者无限递归的情况。
3、__getattribute__(self, name)
: 每次访问属性时均调用(优先级高于 __getattr__
)。用来控制任何属性获取行为的核心方法。每当尝试访问对象的任何属性时,包括类属性和实例属性,Python解释器首先会调用__getattribute__
方法。
在类中定义__getattribute__(self, name)
方法后,每次尝试获取该类实例或类本身的任何属性时,无论该属性是否存在,都会先调用此方法。其中:
self
:表示调用该方法的对象实例;name
:要获取的属性名,是一个字符串。
class MyClass:
def __init__(self, attr_value):
self.attr = attr_value
def __getattribute__(self, name):
if name == 'attr':
return f"The value of '{name}' is {super().__getattribute__(name)}"
else:
return super().__getattribute__(name)
# 使用示例
obj = MyClass(42)
print(obj.attr) # 这里将调用__getattribute__方法
在这个例子中,重写了__getattribute__
方法,对attr
属性的获取进行了定制,返回了一个包含属性名及其值的字符串。对于其他属性,我们仍然使用父类的默认行为(即直接返回属性值)。
需要注意的是,由于__getattribute__
方法对所有属性访问都起作用,所以在实现时要特别小心,避免造成循环引用或者其他意料之外的结果。如果不希望覆盖所有属性的获取方式,而是只针对某些特定属性操作,可以考虑使用@property
装饰器以及相关的方法如__getattr__
。同时,为了正常处理继承链上的属性查找,通常会在自定义逻辑之后调用super().__getattribute__(name)
来继续正常的查找流程。
4、__delattr__(self, name)
: 当尝试删除属性时调用。当尝试删除一个对象的属性时,Python 解释器会自动调用这个方法。
self
: 对象实例自身,这是面向对象编程中实例方法的第一个参数,代表调用该方法的对象。name
: 要删除的属性名,这是一个字符串,表示你想