

深入理解 python 虚拟机:魔术方法之数学计算 - 一无是处的研究僧
source link: https://www.cnblogs.com/Chang-LeHung/p/17418541.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

深入理解 python 虚拟机:魔术方法之数学计算
在本篇文章当中主要给大家介绍在 python 当中一些常见的魔术方法,本篇文章主要是关于与数学计算相关的一些魔术方法,在很多科学计算的包当中都使用到了这些魔术方法。
当我们在Python中定义自己的类时,可以通过重写一些特殊方法来改变对象的比较行为。这些特殊方法包括__lt__
、__le__
、__eq__
、__ne__
、__gt__
和__ge__
,它们分别对应于小于、小于等于、等于、不等于、大于和大于等于的比较运算符。这些方法允许我们自定义对象之间的比较规则。
下面是对每个方法的详细介绍:
object.__lt__(self, other)
这个方法用于定义小于(<)运算符的行为。当我们使用小于运算符比较两个对象时,会调用该方法。如果self
对象小于other
对象,则返回True
,否则返回False
。object.__le__(self, other)
这个方法用于定义小于等于(<=)运算符的行为。当我们使用小于等于运算符比较两个对象时,会调用该方法。如果self
对象小于等于other
对象,则返回True
,否则返回False
。object.__eq__(self, other)
这个方法用于定义等于(==)运算符的行为。当我们使用等于运算符比较两个对象时,会调用该方法。如果self
对象等于other
对象,则返回True
,否则返回False
。object.__ne__(self, other)
这个方法用于定义不等于(!=)运算符的行为。当我们使用不等于运算符比较两个对象时,会调用该方法。如果self
对象不等于other
对象,则返回True
,否则返回False
。object.__gt__(self, other)
这个方法用于定义大于(>)运算符的行为。当我们使用大于运算符比较两个对象时,会调用该方法。如果self
对象大于other
对象,则返回True
,否则返回False
。object.__ge__(self, other)
这个方法用于定义大于等于(>=)运算符的行为。当我们使用大于等于运算符比较两个对象时,会调用该方法。如果self
对象大于等于other
对象,则返回True
,否则返回False
。
这些比较方法允许我们根据自己的需求自定义对象的比较规则。当我们使用比较运算符对对象进行比较时,Python会自动调用这些方法,并返回相应的结果。
下面是一个简单的示例,展示如何在自定义类中使用这些比较方法:
class Point: def __init__(self, x, y): self.x = x self.y = y def __lt__(self, other): return self.x < other.x and self.y return self.y < other.y def __le__(self, other): return self.x <= other.x and self.y <= other.y def __eq__(self, other): return self.x == other.x and self.y == other.y def __ne__(self, other): return not self.__eq__(other) def __gt__(self, other): return self.x > other.x and self.y > other.y def __ge__(self, other): return self.x >= other.x and self.y >= other.y p1 = Point(1, 2)p2 = Point(3, 4) print(p1 < p2) print(p1 <= p2)print(p1 == p2)print(p1 != p2)print(p1 > p2)print(p1 >= p2)
上面的代码输出结果如下所示:
2TrueFalseTrueFalseFalse
在上面的示例中,我们定义了一个名为Point
的类,它表示一个二维平面上的点。我们重写了__lt__
、__le__
、__eq__
、__ne__
、__gt__
和__ge__
方法来定义点之间的比较规则。根据我们的定义,如果一个点的x
坐标和y
坐标都小于另一个点的相应坐标,则我们认为前一个点小于后一个点。
通过创建两个Point
对象并使用比较运算符进行比较,我们可以看到根据我们的定义,比较运算符返回了预期的结果。
模拟设计一个数学类型
当我们在Python中定义自己的类时,可以通过重写一些特殊方法来改变对象的算术运算行为。这些特殊方法包括__add__
、__sub__
、__mul__
、__matmul__
、__truediv__
、__floordiv__
、__mod__
、__divmod__
、__pow__
、__lshift__
、__rshift__
、__and__
、__xor__
和__or__
,它们分别对应于加法、减法、乘法、矩阵乘法、真除法、整除法、取模运算、divmod函数、幂运算、左移位、右移位、按位与、按位异或和按位或的运算符。这些方法允许我们自定义对象之间的算术运算规则。
object.__add__(self, other)
这个方法用于定义加法(+)运算符的行为。当我们使用加法运算符对两个对象进行相加时,会调用该方法。它返回两个对象相加的结果。object.__sub__(self, other)
这个方法用于定义减法(-)运算符的行为。当我们使用减法运算符对两个对象进行相减时,会调用该方法。它返回两个对象相减的结果。object.__mul__(self, other)
这个方法用于定义乘法(*)运算符的行为。当我们使用乘法运算符对两个对象进行相乘时,会调用该方法。它返回两个对象相乘的结果。object.__matmul__(self, other)
这个方法用于定义矩阵乘法(@)运算符的行为。当我们使用矩阵乘法运算符对两个对象进行矩阵乘法时,会调用该方法。它返回两个对象的矩阵乘法结果。object.__truediv__(self, other)
这个方法用于定义真除法(/)运算符的行为。当我们使用真除法运算符对两个对象进行相除时,会调用该方法。它返回两个对象相除的结果。object.__floordiv__(self, other)
这个方法用于定义整除法(//)运算符的行为。当我们使用整除法运算符对两个对象进行相除并取整时,会调用该方法。它返回两个对象相除取整的结果。object.__mod__(self, other)
这个方法用于定义取模(%)运算符的行为。当我们使用取模运算符对两个对象进行取模运算时,会调用该方法。它返回两个对象取模运算的结果。object.__divmod__(self, other)
这个方法用于定义divmod函数的行为。divmod函数接受两个参数,并返回一个包含商和余数的元组。当我们对两个对象使用divmod函数时,会调用该方法。它返回一个包含两个对象的商和余数的元组。object.__pow__(self, other[, modulo])
这个方法用于定义幂运算(**)运算符的行为。当我们使用幂运算符对两个对象进行幂运算时,会调用该方法。它返回两个对象的幂运算结果。可选的modulo
参数用于指定取模运算的模数。object.__lshift__(self, other)
这个方法用于定义左移位(<<)运算符的行为。当我们对一个对象使用左移位运算符时,会调用该方法。它返回对象左移指定位数后的结果。object.__rshift__(self, other)
这个方法用于定义右移位(>>)运算符的行为。当我们对一个对象使用右移位运算符时,会调用该方法。它返回对象右移指定位数后的结果。object.__and__(self, other)
这个方法用于定义按位与(&)运算符的行为。当我们对两个对象使用按位与运算符时,会调用该方法。它返回两个对象按位与的结果。object.__xor__(self, other)
这个方法用于定义按位异或(^)运算符的行为。当我们对两个对象使用按位异或运算符时,会调用该方法。它返回两个对象按位异或的结果。object.__or__(self, other)
这个方法用于定义按位或(|)运算符的行为。当我们对两个对象使用按位或运算符时,会调用该方法。它返回两个对象按位或的结果。
通过重写这些方法,我们可以在自定义类中定义对象之间的算术运算规则。当我们使用相应的算术运算符或函数对对象进行操作时,Python会自动调用这些方法,并返回相应的结果。
下面是一个简单的示例,展示如何在自定义类中使用这些算术方法:
class Vector: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): return Vector(self.x + other.x, self.y + other.y) def __sub__(self, other): return Vector(self.x - other.x, self.y - other.y) def __mul__(self, scalar): return Vector(self.x * scalar, self.y * scalar) def __truediv__(self, scalar): return Vector(self.x / scalar, self.y / scalar) def __repr__(self): return f"Vector[{self.x}, {self.y}]" # 创建两个 Vector 对象v1 = Vector(1, 2)v2 = Vector(3, 4) # 使用算术运算符进行操作v3 = v1 + v2v4 = v1 - v2 v5 = v1 * 2v6 = v2 / 3 print(f"{v1 = }")print(f"{v2 = }")print(f"{v3 = }")print(f"{v4 = }")print(f"{v5 = }")print(f"{v6 = }")
上面的代码输出结果如下所示:
v1 = Vector[1, 2]v2 = Vector[3, 4]v3 = Vector[4, 6]v4 = Vector[-2, -2]v5 = Vector[2, 4]v6 = Vector[1.0, 1.3333333333333333]
在上面的示例中,我们定义了一个名为Vector
的类,它表示二维向量。我们重写了__add__
、__sub__
、__mul__
和__truediv__
方法来定义向量之间的加法、减法、乘法和真除法的规则。根据我们的定义,向量的加法是将对应的分量相加,向量的减法是将对应的分量相减,向量的乘法是将每个分量与标量相乘,向量的真除法是将每个分量除以标量。通过创建两个Vector
对象并使用算术运算符进行操作,我们可以看到根据我们的定义,算术运算符返回了预期的结果。
当我们在Python中定义自己的类时,除了重写一些魔术方法来改变对象的算术运算行为之外,还可以重写对应的反向魔术方法来处理反向运算。这些反向魔术方法以__r
开头,后面跟着对应的运算符,例如__radd__
、__rsub__
、__rmul__
等。它们用于在无法直接对另一个对象调用相应的魔术方法时,尝试使用当前对象的魔术方法来处理反向运算。主要有下面的方法:
object.__radd__(self, other)object.__rsub__(self, other)object.__rmul__(self, other)object.__rmatmul__(self, other)object.__rtruediv__(self, other)object.__rfloordiv__(self, other)object.__rmod__(self, other)object.__rdivmod__(self, other)object.__rpow__(self, other[, modulo])object.__rlshift__(self, other)object.__rrshift__(self, other)object.__rand__(self, other)object.__rxor__(self, other)object.__ror__(self, other)
比如 a + b,当 a 当中没有定义 __add__
的时候,就会调用 b 的 __radd__
。比如下面这个例子:
class A: def __init__(self, x): self.x = x class B: def __init__(self, x): self.x = x def __radd__(self, other): print("In B __radd__") return self.x + other.x if __name__ == '__main__': a = A(1) b = B(1) print(a + b)
上面的代码输出结果如下所示:
In B __radd__2
除了上面关于数据的魔术方法之外,还有一些其他的魔术方法,具体如下所示:
object.__neg__(self)object.__pos__(self)object.__abs__(self)object.__invert__(self)object.__complex__(self)object.__int__(self)object.__float__(self)object.__index__(self)object.__round__(self[, ndigits])object.__trunc__(self)object.__floor__(self)object.__ceil__(self)
object.__neg__(self)
这个方法用于定义负号(-)运算符的行为。当应用负号运算符到一个对象时,会调用该对象的__neg__
方法。它返回一个表示当前对象相反数的新对象。object.__pos__(self)
这个方法用于定义正号(+)运算符的行为。当应用正号运算符到一个对象时,会调用该对象的__pos__
方法。它返回当前对象的副本。object.__abs__(self)
这个方法用于定义绝对值(abs())函数的行为。当应用abs()
函数到一个对象时,会调用该对象的__abs__
方法。它返回当前对象的绝对值。object.__invert__(self)
这个方法用于定义按位取反(~)运算符的行为。当应用按位取反运算符到一个对象时,会调用该对象的__invert__
方法。它返回当前对象按位取反后的结果。object.__complex__(self)
这个方法用于定义complex()
函数的行为,用于将对象转换为复数形式。当应用complex()
函数到一个对象时,会调用该对象的__complex__
方法。它返回一个复数对象,表示当前对象。object.__int__(self)
这个方法用于定义int()
函数的行为,用于将对象转换为整数形式。当应用int()
函数到一个对象时,会调用该对象的__int__
方法。它返回一个整数对象,表示当前对象。object.__float__(self)
这个方法用于定义float()
函数的行为,用于将对象转换为浮点数形式。当应用float()
函数到一个对象时,会调用该对象的__float__
方法。它返回一个浮点数对象,表示当前对象。object.__index__(self)
这个方法用于定义operator.index()
函数的行为,用于将对象转换为整数索引。当应用operator.index()
函数到一个对象时,会调用该对象的__index__
方法。它返回一个整数对象,表示当前对象可以用作索引。object.__round__(self[, ndigits])
这个方法用于定义round()
函数的行为,用于对对象进行四舍五入。当应用round()
函数到一个对象时,会调用该对象的__round__
方法。可选的ndigits
参数指定小数位数,默认为None。它返回一个新的对象,表示当前对象四舍五入后的结果。object.__trunc__(self)
这个方法用于定义math.trunc()
函数的行为,用于将对象截断为整数。当应用math.trunc()
函数到一个对象时,会调用该对象的__trunc__
方法。
本篇文章介绍了在Python中使用魔术方法来改变对象的比较和算术运算行为。对于比较运算符,可以通过重写__lt__
、__le__
、__eq__
、__ne__
、__gt__
和__ge__
方法来定义自定义对象之间的比较规则。对于算术运算符,可以通过重写__add__
、__sub__
、__mul__
、__matmul__
、__truediv__
、__floordiv__
、__mod__
、__divmod__
、__pow__
、__lshift__
、__rshift__
、__and__
、__xor__
和__or__
方法来定义对象之间的算术运算规则。这些方法允许自定义类的对象具有与内置类型相似的行为。
本篇文章还提到了反向魔术方法,即以__r
开头的方法,用于处理反向运算。例如,__radd__
、__rsub__
、__rmul__
等方法可以定义对象在反向运算中的行为。
通过示例代码,文章演示了如何在自定义类中重写这些魔术方法,以实现自定义的比较和算术运算规则。最后,展示了在自定义类中使用这些方法时得到的预期结果。
总而言之,通过理解和使用这些魔术方法,我们可以在Python中更好地控制自定义类对象的比较和算术运算行为,使其更符合特定需求。
本篇文章是深入理解 python 虚拟机系列文章之一,文章地址:https://github.com/Chang-LeHung/dive-into-cpython
更多精彩内容合集可访问项目:https://github.com/Chang-LeHung/CSCore
关注公众号:一无是处的研究僧,了解更多计算机(Java、Python、计算机系统基础、算法与数据结构)知识。
Recommend
-
4
深入理解 Python 虚拟机:元组(tuple)的实现原理及源码剖析 在本篇文章当中主要给大家介绍 cpython 虚拟机当中针对列表的实现,在 Python 中,tuple 是一种非常常用的数据类型,在本篇文章当中...
-
9
深入理解 Python 虚拟机:浮点数(float)的实现原理及源码剖析 在本篇文章当中主要分析在 cpython 虚拟机当中 float 类型的实现原理以及与他相关的一些源代码。 ...
-
6
深入理解 Python 虚拟机:整型(int)的实现原理及源码剖析 在本篇文章当中主要给大家介绍在 cpython 内部是如何实现整型数据 int 的,主要是分析 int 类型的表示方式,分析 int 类型的巧妙设计。
-
8
深入理解 Python 虚拟机:复数(complex)的实现原理及源码剖析 在本篇文章当中主要给大家介绍在 cpython 虚拟机当中是如何实现 复数 complex 这个数据类型的,这个数据类型在 cpython 当中一...
-
6
深入理解 Python 虚拟机:集合(set)的实现原理及源码剖析 在本篇文章当中主要给大家介绍在 cpython 虚拟机当中的集合 set 的实现原理(哈希表)以及对应的源代码分析。
-
6
深入理解 Python 虚拟机:字典(dict)的实现原理及源码剖析 在本篇文章当中主要给大家深入介绍一下在 cpython 当中字典的实现原理,在本篇文章当中主要介绍在早期 python3 当中的版本字典的实现...
-
13
深入理解 Python 虚拟机:字节(bytes)的实现原理及源码剖析 在本篇文章当中主要给大家介绍在 cpython 内部,bytes 的实现原理、内存布局以及与 bytes 相关的一个比较重要的优化点—— bytes 的拼...
-
5
深入理解 Python 虚拟机:字典(dict)的优化 在前面的文章当中我们讨论的是 python3 当中早期的内嵌数据结构字典的实现,在本篇文章当中主要介绍在后续对于字典的内存优化。 在前面的文章当中我们介绍...
-
9
深入理解 python 虚拟机:pyc 文件结构 在本篇文章当中主要给大家介绍一下 .py 文件在被编译之后对应的 pyc 文件结构,pyc 文件当中的一个核心内容就是 python 字节码。 pyc 文件 p...
-
2
深入理解 python 虚拟机:花里胡哨的魔术方法 在本篇文章当中主要给大家介绍在 cpython 当中一些比较花里胡哨的魔术方法,以帮助我们自己实现比较花哨的功能,当然这其中也包含一些也非常实用的魔术方法。
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK