今天我们来聊聊魔术方法使用的精髓,叫做emulation。我们知道python中的类型系统叫做duck type。
简单的说,就是他不去检查具体的这个对象是什么类型,而是检查这个对象有没有相应的功能。
而python中有大量的魔术方法,就是给某一个对象加上相应的功能,接下来聊一聊emulating numeric types,也就是让你的类型实现一些数的功能。
__add__
魔术方法
__add__
是一种在Python中定义对象之间加法操作的魔术方法。当使用“+”运算符对两个对象执行加法操作时,Python将会查找并调用每个对象中定义的__add__
方法。
以下是一个简单的例子,其中我们定义了一个名为MyNumber
的类,并定义了__add__
方法来允许在对象之间执行加法操作:
class MyNumber:
def __init__(self, value):
self.value = value
def __add__(self, other):
if isinstance(other, MyNumber):
return MyNumber(self.value + other.value)
elif isinstance(other, (int, float)):
return MyNumber(self.value + other)
else:
return NotImplemented
def __repr__(self):
return f"MyNumber({self.value})"
n1 = MyNumber(1)
n2 = MyNumber(2)
print(n1 + n2)
print(n1 + 5)
print(n2 + "3")
输出结果为:
Traceback (most recent call last):
File "/mnt/f/lianhaifeng_codes/djangoProject/djangoProject/sss.py", line 21, in <module>
print(n2 + "3")
TypeError: unsupported operand type(s) for +: 'MyNumber' and 'str'
MyNumber(3)
MyNumber(6)
__iadd__魔术方法
__iadd__
是Python中的一个魔术方法,用于在类中定义就地加法的实现,即将两个对象相加,并将结果存储在第一个对象中。在Python中,就地加法使用+=
运算符进行实现,如果类中没有实现__iadd__
,则Python解释器会尝试使用__add__
方法代替__iadd__
方法,这样会创建一个新的对象并返回结果。
以下是一个使用__iadd__
方法的示例:
class MyList:
def __init__(self, items):
self.items = items
def __iadd__(self, other):
if isinstance(other, MyList):
self.items.extend(other.items)
else:
self.items.append(other)
return self
def __repr__(self):
return f'MyList({self.items})'
l1 = MyList([1, 2, 3])
l2 = MyList([4, 5, 6])
l1 += l2 # 就地加法
print(l1) # 输出 MyList([1, 2, 3, 4, 5, 6])
在上面的示例中,MyList
类实现了__iadd__
方法,用于将两个MyList
对象进行就地加法。当执行l1 += l2
时,l1
对象的__iadd__
方法被调用,将l2
对象的内容添加到l1
中,最终结果存储在l1
中。
需要注意的是,__iadd__
方法需要返回self
对象,以便在就地加法完成后继续使用当前对象。
__sub__魔术方法
__sub__
是一个魔术方法,用于定义两个对象相减的行为。当对象使用 -
运算符进行相减操作时,会自动调用 __sub__
方法。
下面是一个例子,展示了如何定义一个自定义对象的 __sub__
方法:
class MyNumber:
def __init__(self, value):
self.value = value
def __sub__(self, other):
return MyNumber(self.value - other.value)
def __repr__(self):
return f"MyNumber({self.value})"
a = MyNumber(10)
b = MyNumber(5)
c = a - b
print(c) # 输出 MyNumber(5)
__mul__魔术方法
__mul__
是Python中的一个魔术方法,用于在两个对象相乘时调用。它接受两个参数:self
和other
,其中self
是调用方法的对象,而other
是传递给方法的参数。
下面是一个简单的例子,展示了如何使用__mul__
方法重载乘法运算符:
class MyClass:
def __init__(self, value):
self.value = value
def __mul__(self, other):
return MyClass(self.value * other)
x = MyClass(10)
y = x * 2
print(y.value) # 输出 20
__rmul__魔术方法
__rmul__
魔术方法是指右侧乘法运算的魔术方法。当一个对象被用于乘法运算并且它是另一个对象的右侧操作数时,Python会尝试调用它的__rmul__
方法来进行运算。
例如,在下面的代码中,我们创建了一个自定义的类MyInt
,它包含一个整数值,并实现了__rmul__
方法:
class MyInt:
def __init__(self, value):
self.value = value
def __rmul__(self, other):
return MyInt(self.value * other)
x = MyInt(10)
result = 5 * x
print(result.value) # 输出 50
在上面的例子中,Python首先将5作为参数传递给__rmul__
方法,因此other
参数的值为5。__rmul__
方法将MyInt
对象的值与other
参数相乘,并返回一个新的MyInt
对象,其值为乘积。最后,结果被赋给result
变量,并打印出来。
需要注意的是,在__rmul__
方法中,我们必须返回一个新的对象,而不能修改原始对象的值。这是因为Python的乘法运算符是不可变的,所以我们不能直接在原始对象上修改它的值。
__matmul__魔术方法
__matmul__
是一个魔术方法,用于定义对象的“@”运算符。当我们使用“@”运算符时,Python 会自动调用该对象的__matmul__
方法。
例如,我们可以定义一个Matrix
类,并在其中实现__matmul__
方法来定义矩阵相乘的操作。以下是一个简单的示例:
class Matrix:
def __init__(self, data):
self.data = data
def __matmul__(self, other):
if not isinstance(other, Matrix):
raise TypeError('Operand must be a matrix')
if len(self.data[0]) != len(other.data):
raise ValueError('Matrix dimensions do not match')
result = [[0] * len(other.data[0]) for _ in range(len(self.data))]
for i in range(len(self.data)):
for j in range(len(other.data[0])):
for k in range(len(other.data)):
result[i][j] += self.data[i][k] * other.data[k][j]
return Matrix(result)
m1 = Matrix([[1, 2], [3, 4]])
m2 = Matrix([[5, 6], [7, 8]])
result = m1 @ m2
print(result.data) # 输出 [[19, 22], [43, 50]]
在这个例子中,Matrix
类具有一个属性data
,它是一个二维列表,代表矩阵中的数据。__matmul__
方法接受另一个Matrix
对象作为参数,并计算它们的矩阵乘积。
在这个例子中,我们首先创建了两个矩阵m1
和m2
,然后使用@
运算符将它们相乘,并将结果存储在变量result
中。最后,我们打印了结果矩阵的数据。
__truediv__魔术方法
__truediv__
是Python中的一个魔术方法,用于实现对象除法运算。当使用“/”符号时,会自动调用该方法。需要注意的是ÿ