11. 魔术方法#

Python定义了一些以双下划线开始和结束的方法,它们在特定的操作中被自动调用。这些方法允许开发者定义或修改内置操作的行为,称为魔术方法(magic method)。这些魔术方法是 Python 对象模型的核心,允许开发者定义或修改对象的行为,以适应不同的使用场景。

11.1. 常用的魔术方法及其示例#

下面是一些常用的魔术方法及其使用示例:

  1. __init__(self, ...):类的构造器,当一个实例被创建时调用。

class Greeter:
    def __init__(self, name):
        self.name = name
        print("__init__ call")

greeter = Greeter("World")
__init__ call
  1. __str__(self):返回对象的字符串表示,用于 print() 函数和 str()

class Greeter:
    def __init__(self, name):
        self.name = name
        print("__init__")
    def __str__(self):
        return f"Hello, {self.name}!"

greeter = Greeter("World")
print(greeter)  # 输出: Hello, World!
__init__
Hello, World!
  1. __repr__(self):返回对象的官方字符串表示,通常用于调试。

class Greeter:
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return f"Greeter('{self.name}')"
 
greeter = Greeter("World")
repr(greeter)  # 输出: Greeter('World')
"Greeter('World')"
  1. __len__(self):返回容器类型的长度。

class MyList:
    def __init__(self, elements):
        self.elements = elements

    def __len__(self):
        return len(self.elements)

my_list = MyList([1, 2, 3])
len(my_list)  # 输出: 3
3
  1. __getitem__(self, key):获取序列的元素。

class MyList:
    def __init__(self, elements):
        self.elements = elements

    def __getitem__(self, index):
        return self.elements[index]

my_list = MyList([1, 2, 3])
my_list[1]  # 输出: 2
2
  1. __setitem__(self, key, value):设置序列的元素。

class MyList:
    def __init__(self, elements):
        self.elements = elements

    def __setitem__(self, index, value):
           self.elements[index] = value

my_list = MyList([1, 2, 3])
my_list[1] = 5
my_list.elements  # 输出: [1, 5, 3]
[1, 5, 3]
  1. __iter__(self)__next__(self):返回迭代器对象。

class MyRange:
   def __init__(self, start, end):
       self.current = start
       self.end = end

   def __iter__(self):
       return self

   def __next__(self):
       if self.current < self.end:
           current = self.current
           self.current += 1
           return current
       else:
           raise StopIteration
           
for number in MyRange(0, 3):
    print(number)  # 输出: 0, 1, 2
0
1
2
  1. __eq__(self, other):比较两个对象是否相等。

class Point:
   def __init__(self, x, y):
       self.x = x
       self.y = y
   def __eq__(self, other):
       return self.x == other.x and self.y == other.y

p1 = Point(1, 2)
p2 = Point(1, 2)
p1 == p2  # 输出: True
True

11.2. 知名库使用情况#

NumPy 是一个广泛使用的科学计算库,它大量使用了魔术方法来支持数组运算。例如,__add__ 方法使得两个 NumPy 数组可以直接相加:

import numpy as np

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c = a + b  # 使用了 ndarray 类的 __add__ 方法
print(c)  # 输出: [5 7 9]
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[9], line 1
----> 1 import numpy as np
      3 a = np.array([1, 2, 3])
      4 b = np.array([4, 5, 6])

ModuleNotFoundError: No module named 'numpy'

另一个例子是 Python 的内置 list 类型,它实现了 __getitem____setitem____len____iter____add__ 等魔术方法,使得列表支持索引、切片、长度获取、迭代和连接等操作。

my_list = [1, 2, 3]
my_list[1]  # 使用了 __getitem__,输出: 2
my_list[1] = 5  # 使用了 __setitem__
len(my_list)  # 使用了 __len__,输出: 3
for item in my_list:  # 使用了 __iter__
    print(item)  # 输出: 1, 5, 3
my_list + [4]  # 使用了 __add__,输出: [1, 5, 3, 4]
1
5
3
[1, 5, 3, 4]