python常用魔术方法

发布时间 2023-10-31 16:16:46作者: liuyang9643

__new__

__new__ 方法是在Python中用于创建对象实例的特殊方法。它通常用于自定义对象的创建和初始化过程。__new__ 方法在对象创建之前被调用,而 __init__ 方法则在对象创建之后进行初始化。

在以下示例中,我们定义了一个名为 Demo 的类,它是一个单例类,即只能创建一个实例。我们使用 __new__ 方法来实现单例模式,确保只创建一个实例。__new__ 方法中的逻辑检查了类的 _singleton 属性,如果没有实例存在,就创建一个新的实例,如果存在实例,则直接返回已存在的实例。

class Demo(object):
    _singleton = None

    def __new__(cls, *args, **kwargs):
        """创建新对象的方法,在类实例化时调用。通常用于定制类的创建方式。"""
        if cls._singleton is None:
            print("第一次实例化,进行实例化操作")
            cls._singleton = super(Demo, cls).__new__(cls)
            cls._singleton.initialized = False
        else:
            print("非第一次实例化,不做操作")
        return cls._singleton


if __name__ == '__main__':
    d1 = Demo()
    d2 = Demo()

输出结果如下:

第一次实例化,进行实例化操作
非第一次实例化,不做操作

__init__

使用__init__方法来初始化类的属性。

在以下示例中,当我们创建Demo类的实例d时,__init__方法会自动调用,并为实例设置相关属性。之后,我们可以访问这些属性来获取实例的信息。

class Demo(object):

    def __init__(self, name, age, *args, **kwargs):
        """构造函数,在对象创建时调用。用于初始化对象的属性。"""
        self.name = name
        self.age = age
        self.args = args
        self.kwargs = kwargs


if __name__ == '__main__':
    d = Demo("ly", 18, 1, 2, 3, a=1, b=2, c=3)
    print(d.name)
    print(d.age)
    print(d.args)
    print(d.kwargs)

输出结果如下:

ly
18
(1, 2, 3)
{'a': 1, 'b': 2, 'c': 3}

__del__

__del__ 是Python中的特殊方法,也称为析构方法。它在对象即将被销毁时自动调用,用于执行对象的清理和资源释放操作。当Python解释器退出但对象仍然存活的时候, __del__ 并不会 执行。 所以养成一个手工清理的好习惯是很重要的,比如及时关闭连接。

__del__ 方法和 del 关键字不是等价的,虽然它们都可以用于销毁对象,但它们的作用和调用时机有重要的不同:

  1. __del__ 方法:

    • __del__ 方法是一个特殊方法,当对象被销毁时(垃圾回收),它会自动调用。
    • __del__ 方法允许您在对象被销毁之前执行一些清理操作,例如释放资源或记录日志。
    • 它通常不应该显式调用,而是由Python的垃圾回收机制自动触发。
  2. del 关键字:

    • del 是一个Python关键字,用于删除对象引用或从容器(例如列表或字典)中删除元素。
    • 它的主要作用是释放变量名与对象之间的关联。当没有引用指向一个对象时,垃圾回收机制可能会在某个时刻销毁该对象。
    • del 通常用于删除引用,而不是直接销毁对象。对象销毁是由垃圾回收机制负责的,通常在引用计数下降到零时触发。
class Demo(object):

    def __init__(self, name, age, *args, **kwargs):
        """构造函数,在对象创建时调用。用于初始化对象的属性。"""
        self.name = name
        self.age = age
        self.args = args
        self.kwargs = kwargs


if __name__ == '__main__':
    d = Demo("ly", 18, 1, 2, 3, a=1, b=2, c=3)
    print(d.name)
    print(d.age)
    print(d.args)
    print(d.kwargs)

输出结果如下:

ly
18
(1, 2, 3)
{'a': 1, 'b': 2, 'c': 3}

__str__ 和 __repr__

__str____repr__ 方法都用于定义类的字符串表示,但它们在用途和返回值上有一些重要的区别:

  1. 用途:

    • __str__: 用于返回对象的可读性较好的字符串表示,通常用于用户友好的输出。它应该包含对象的关键信息,以便人类能够理解。

    • __repr__: 用于返回对象的"官方"字符串表示,通常用于开发和调试目的。它应该包含足够的信息来唯一标识对象,并且通常是一个可以用于创建相同对象的表达式。

  2. 返回值:

    • __str__: 返回一个字符串,通常是对象的可读性较好的描述。这个描述应该是用户友好的,适合直接显示给终端用户。

    • __repr__: 返回一个字符串,通常是一个表达式,可以用来创建相同对象。这个字符串应该足够详细,以便能够精确重新创建对象。

  3. 调用时机:

    • __str__: 当使用 str(obj)print(obj) 函数时,会调用 __str__ 方法。

    • __repr__: 当使用 repr(obj) 函数、在交互式环境中输入对象名并回车时,或者在调试工具中查看对象时,会调用 __repr__ 方法。

  4. 默认实现:

    • 如果您不定义 __str__ 方法,Python会默认使用 __repr__ 方法的结果作为字符串表示。

    • 如果您不定义 __repr__ 方法,Python会默认提供一个通用的实现,通常返回对象的类名和内存地址。

class Demo(object):

    def __init__(self, name, age, *args, **kwargs):
        """构造函数,在对象创建时调用。用于初始化对象的属性。"""
        self.name = name
        self.age = age
        self.args = args
        self.kwargs = kwargs

    def __str__(self):
        """返回对象的字符串表示。通常用于 print(obj) 或 str(obj)。当你需要可读性较好的对象表示时,可以重写它。"""
        return f"Demo(name: {self.name}, age: {self.age})"

    def __repr__(self):
        """返回对象的“官方”字符串表示,通常是可以用于创建对象的表达式。在交互式环境中输入对象名并回车时,会调用该方法。"""
        return f"Demo('{self.name}', {self.age})"


if __name__ == '__main__':
    d = Demo("ly", 18, 1, 2, 3, a=1, b=2, c=3)
    print(str(d))  # 调用__str__方法
    print(repr(d))  # 调用__repr__方法

输出结果如下:

Demo(name: ly, age: 18)
Demo('ly', 18)

__len__

__len__ 方法用于自定义类的长度,通常在实现容器类或可迭代对象时使用。

当我们创建Demo类的实例并使用len()函数来获取它的长度时,实际上是调用了__len__方法。这使得我们可以使用len()函数来获取自定义类的长度,就像对待内置的列表、元组等容器一样。

class Demo(object):

    def __init__(self, name, age, *args, **kwargs):
        """构造函数,在对象创建时调用。用于初始化对象的属性。"""
        self.name = name
        self.age = age
        self.args = args
        self.kwargs = kwargs

    def __len__(self):
        """返回对象的长度,通常在容器类中实现,如列表、字典等。可通过内置函数 len(obj) 获取对象的长度。"""
        print("使用了len()函数,返回args和kwargs总长度")
        return len(self.args) + len(self.kwargs)


if __name__ == '__main__':
    d = Demo("ly", 18, 1, 2, 3, a=1, b=2, c=3)
    print(len(d))

输出结果如下:

使用了len()函数,返回args和kwargs总长度
6

__getitem__、__setitem__、__delitem__

__getitem__, __setitem__, 和 __delitem__ 是Python中用于实现索引操作的特殊方法,通常用于自定义类的行为,以使其支持索引访问和操作。

我们创建Demo类包含了__getitem__, __setitem__, 和 __delitem__ 方法,以支持索引访问、赋值和删除操作。这三个方法使Demo对象可以像列表一样被操作。

  • __getitem__ 方法用于获取索引位置的元素。在示例中,d1[2] 调用了__getitem__方法来获取索引为2的元素。
  • __setitem__ 方法用于设置索引位置的元素。在示例中,d1[1] = 10 调用了__setitem__方法来将索引为1的元素设置为10。
  • __delitem__ 方法用于删除索引位置的元素。在示例中,del d1[3] 调用了__delitem__方法来删除索引为3的元素。

这些方法允许自定义类的行为,以支持索引操作,从而使自定义类更像内置的序列类型。需要注意的是,这些方法应该正确处理索引越界的情况,并引发适当的异常,以确保代码的健壮性。

class Demo(object):
    def __init__(self, data):
        self.data = data

    def __getitem__(self, index):
        if 0 <= index < len(self.data):
            return self.data[index]
        else:
            raise IndexError("Index out of range")

    def __setitem__(self, index, value):
        if 0 <= index < len(self.data):
            self.data[index] = value
        else:
            raise IndexError("Index out of range")

    def __delitem__(self, index):
        if 0 <= index < len(self.data):
            del self.data[index]
        else:
            raise IndexError("Index out of range")


if __name__ == '__main__':
    # 创建Demo类的实例
    d1 = Demo([1, 2, 3, 4, 5])

    # 使用__getitem__来获取元素
    print("Element at index 2:", d1[2])

    # 使用__setitem__来设置元素
    d1[1] = 10
    print("Updated data:", d1.data)

    # 使用__delitem__来删除元素
    del d1[3]
    print("Data after deleting index 3:", d1.data)

输出结果如下:

Element at index 2: 3
Updated data: [1, 10, 3, 4, 5]
Data after deleting index 3: [1, 10, 3, 5]

__getattr__、__setattr__、__delattr__

``getattr, setattr, 和 delattr` 是Python中用于实现属性访问的特殊方法,通常用于自定义类的属性操作。

我们创建Demo类包含了__getattr__, __setattr__, 和 __delattr__ 方法,以支持自定义属性访问和操作。这三个方法使Demo对象可以像普通属性一样被访问、设置和删除。

  • __getattr__ 方法用于获取属性的值。在示例中,d1.attr1d1.attr2 调用了__getattr__方法来获取属性的值。
  • __setattr__ 方法用于设置属性的值。在示例中,d1.attr1 = "Value 1"d1.attr2 = "Value 2" 调用了__setattr__方法来设置属性的值。
  • __delattr__ 方法用于删除属性。在示例中,del d1.attr1 调用了__delattr__方法来删除属性。

这些方法允许自定义类的属性访问和操作。需要注意的是,当使用这些方法时,应该确保正确处理属性不存在和删除不存在的属性的情况,以提高代码的健壮性。在示例中,我们引发了AttributeError 异常以处理这些情况。

class Demo(object):
    _data = {}

    def __getattr__(self, name):
        if name in self._data:
            return self._data[name]
        else:
            raise AttributeError(f"'Demo' object has no attribute '{name}'")

    def __setattr__(self, name, value):
        self._data[name] = value

    def __delattr__(self, name):
        if name in self._data:
            del self._data[name]
        else:
            raise AttributeError(f"'Demo' object has no attribute '{name}'")


if __name__ == '__main__':
    d1 = Demo()

    # 使用__setattr__来设置属性
    d1.attr1 = "Value 1"
    d1.attr2 = "Value 2"

    # 使用__getattr__来获取属性
    print("attr1:", d1.attr1)
    print("attr2:", d1.attr2)

    # 使用__delattr__来删除属性
    del d1.attr1

    # 尝试获取已删除的属性会引发异常
    # print("attr1:", d1.attr1)

输出结果如下:

attr1: Value 1
attr2: Value 2

__iter__、__next__

__iter____next__ 是Python中用于创建可迭代对象和定义迭代行为的两个特殊方法。

  1. __iter__ 方法:

    • __iter__ 方法用于返回一个迭代器对象,通常是self(即当前对象本身)。
    • 在一个可迭代对象的类中,通常会定义一个 __iter__ 方法,该方法返回一个实现了 __next__ 方法的迭代器对象。
    • 迭代器对象是可迭代对象的一部分,它负责迭代操作的控制。__iter__ 方法应该返回一个迭代器对象。
  2. __next__ 方法:

    • __next__ 方法用于定义迭代操作的行为,它在每次迭代中返回下一个元素。
    • __next__ 方法通常包含一个迭代器内部的状态,以跟踪当前迭代的位置。
    • 当没有更多的元素可供迭代时,__next__ 方法应该引发 StopIteration 异常,以指示迭代结束。
    • 迭代器对象的 __next__ 方法应该返回迭代中的下一个元素,或引发 StopIteration 异常来终止迭代。
class Demo(object):
    def __init__(self, data):
        self.data = data
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index < len(self.data):
            result = self.data[self.index]
            self.index += 1
            return result
        else:
            raise StopIteration


d1 = Demo([1, 2, 3, 4, 5])

# 使用迭代器迭代访问元素
for item in d1:
    print(item)

输出结果如下:

1
2
3
4
5

__call__

__call__ 是Python中的一个特殊方法,它允许将对象像函数一样调用。在调用对象时,实际上是调用了 __call__ 方法。__call__ 方法可以接受任意数量的位置参数 args 和关键字参数 kwargs

class Demo(object):

    def __call__(self, *args, **kwargs):
        """使对象可调用,就像函数一样。可通过 obj() 进行调用。"""
        print("调用了__call__")


d1 = Demo()
d1()
# 等价于以下操作
Demo()()

输出结果如下:

调用了__call__
调用了__call_

__enter__、__exit__

__enter____exit__ 是Python中用于上下文管理的两个特殊方法,通常与 with 语句结合使用。它们用于创建和管理上下文,以确保资源的正确分配和释放。

  1. __enter__ 方法:

    • __enter__ 方法用于进入上下文,它在 with 语句块的开始处被调用。
    • 这个方法通常用于执行一些初始化或资源分配操作,并返回一个对象,它可以被 as 子句赋值给一个变量(如果在 with 语句中使用了 as)。
    • 任何返回的对象都可以在 with 语句块中使用,以便处理上下文中的一些操作。
  2. __exit__ 方法:

    • __exit__ 方法用于退出上下文,它在 with 语句块的结束处被调用。
    • 这个方法通常用于执行一些清理或资源释放操作。它接受三个参数:exc_typeexc_valuetraceback,用于处理异常。
    • 如果 with 语句块正常执行完毕,__exit__ 方法可以返回 True,以表示一切正常。如果有异常发生,它可以返回 False,以表示异常已被处理。

当使用 with 语句创建上下文时,__enter__ 方法被调用,允许进行一些初始化操作。__exit__ 方法在 with 语句块结束后被调用,允许进行一些清理操作。如果在 with 语句块中发生异常,__exit__ 方法会处理它并返回 False,表示异常未被处理。如果没有异常发生,__exit__ 方法可以返回 True,表示一切正常。这使得您可以确保资源的正确管理和异常处理。

class Demo(object):

    def __enter__(self):
        """用于上下文管理器的进入方法。用于设置资源。"""
        print("Entering the context")
        return self  # 返回一个对象,可以在with语句块中使用

    def __exit__(self, exc_type, exc_value, traceback):
        """用于上下文管理器的退出方法。用于释放资源。"""
        if exc_type is None:
            print("Exiting the context (no exceptions)")
        else:
            print(f"Exiting the context with an exception: {exc_type}, {exc_value}")
        return False  # 返回False表示异常未被处理


# 使用with语句创建上下文,并在with块内执行操作
with Demo() as d1:
    print("Inside the context")
    # Uncomment the following line to test exception handling
    # raise Exception("An error occurred")

# 当with块结束后,会调用__exit__方法

输出结果如下:

Entering the context
Inside the context
Exiting the context (no exceptions)

其他

class Demo(object):

    def __eq__(self, other):
        """等于运算符 == 的定义。用于比较对象是否相等。"""

    def __ne__(self, other):
        """不等于运算符 != 的定义。用于比较对象是否不相等。"""

    def __lt__(self, other):
        """小于运算符 < 的定义。用于比较对象大小。"""

    def __le__(self, other):
        """小于或等于运算符 <= 的定义。用于比较对象大小。"""

    def __gt__(self, other):
        """大于运算符 > 的定义。用于比较对象大小。"""

    def __ge__(self, other):
        """大于或等于运算符 >= 的定义。用于比较对象大小。"""

    def __add__(self, other):
        """加法运算符 + 的定义。用于支持对象的加法操作。"""

    def __sub__(self, other):
        """减法运算符 - 的定义。用于支持对象的减法操作。"""

    def __mul__(self, other):
        """乘法运算符 * 的定义。用于支持对象的乘法操作。"""

    def __truediv__(self, other):
        """真除法运算符 / 的定义。用于支持对象的真除法操作。"""

    def __floordiv__(self, other):
        """地板除法运算符 // 的定义。用于支持对象的地板除法操作。"""

    def __mod__(self, other):
        """取模运算符 % 的定义。用于支持对象的取模操作。"""

    def __pow__(self, other):
        """幂运算符 ** 的定义。用于支持对象的幂操作。"""

    def __contains__(self, item):
        """用于 in 运算符的定义。用于检查对象是否包含某个元素。"""