Python 魔术或邓德方法
Python 中的魔法方法是以双下划线开始和结束的特殊方法。它们也被称为邓德方法。魔法方法并不意味着由您直接调用,而是在某个动作上从类内部进行调用。例如,当您使用 +
运算符将两个数字相加时,在内部将调用 __add__()
方法。
Python 中的内置类定义了许多神奇的方法。使用 dir()
函数查看一个类继承的魔法方法数量。例如,下面列出了在 int
类中定义的所有属性和方法。
>>> dir(int)
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
正如您在上面看到的,int
类包含了各种由双下划线包围的神奇方法。例如,__add__
方法是一种神奇的方法,当我们使用 +
运算符将两个数字相加时,它就会被调用。考虑以下示例。
>>> num = 10
>>> num + 5
15
>>> num.__add__(5)
15
可以看到,当你做 num + 10
时,+
运算符调用 __add__(10)
方法。也可以直接打 num.__add__(5)
会给出同样的结果。然而,如前所述,魔法方法并不意味着被直接调用,而是在内部,通过一些其他的方法或动作。
在 Python 中,魔术方法最常用于定义预定义运算符的重载行为。例如,默认情况下,算术运算符对数字操作数进行运算。这意味着数值对象必须与 +
、-
、*
、/
等运算符一起使用。+
运算符也被定义为字符串、列表和元组类中的串联运算符。我们可以说 +
运算符是重载的。
为了使重载行为在您自己的自定义类中可用,应该重写相应的 magic 方法。例如,为了将 +
运算符用于用户定义类的对象,它应该包括 __add__()
方法。
让我们看看如何实现和使用一些重要的魔术方法。
__new__()
方法
Java 和 C# 等语言使用新的运算符来创建类的新实例。在 Python 中,__new__()
魔法方法在 __init__()
方法之前被隐式调用。__new__()
方法返回一个新的对象,然后由 __init__()
初始化。
class Employee:
def __new__(cls):
print ("__new__ magic method is called")
inst = object.__new__(cls)
return inst
def __init__(self):
print ("__init__ magic method is called")
self.name='Satya'
当您创建 Employee
类的实例时,上面的示例将产生以下输出。
>>> emp = Employee()
__new__ magic method is called
__init__ magic method is called
因此,在 __init__()
方法之前调用 __new__()
方法。
__str__()
方法
另一个有用的魔法方法是 __str__()
。它被重写以返回任何用户定义类的可打印字符串表示形式。我们已经看到 str()
内置函数从对象参数返回一个字符串。例如,str(12)
返回 '12'
。当被调用时,它调用 int
类中的 __str__()
方法。
>>> num = 12
>>> str(num)
'12'
>>> # This is equivalent to
>>> int.__str__(num)
'12'
现在让我们重写 Employee
类中的 __str__()
方法,以返回其对象的字符串表示。
class Employee:
def __init__(self):
self.name = 'Swati'
self.salary = 10000
def __str__(self):
return 'name=' + self.name + ' salary=$' + str(self.salary)
查看 str()
函数如何在内部调用员工类中定义的 __str__()
方法。这就是为什么它被称为神奇的方法!
>>> e1 = Employee()
>>> print(e1)
name=Swati salary=$10000
__add__()
方法
在下面的示例中,一个名为 distance
的类定义了两个实例属性 - ft
和 inch
。这两个距离对象的添加需要使用重载 +
运算符来执行。
为了实现这一点,神奇的方法 __add__()
被覆盖,它执行两个对象的英尺和英寸属性的添加。方法返回对象的字符串表示。
class distance:
def __init__(self, x=None, y=None):
self.ft = x
self.inch = y
def __add__(self, x):
temp = distance()
temp.ft = self.ft + x.ft
temp.inch = self.inch + x.inch
if temp.inch >= 12:
temp.ft += 1
temp.inch -= 12
return temp
def __str__(self):
return 'ft:' + str(self.ft) + ' in: ' + str(self.inch)
运行上面的 Python 脚本来验证 +
运算符的重载操作。
>>> d1 = distance(3, 10)
>>> d2 = distance(4, 4)
>>> print("d1= {} d2={}".format(d1, d2))
d1= ft:3 in: 10 d2=ft:4 in: 4
>>> d3 = d1 + d2
>>> print(d3)
ft:8 in: 2
__ge__()
方法
在距离类中增加以下方法来重载 >=
运算符。
class distance:
def __init__(self, x=None, y=None):
self.ft = x
self.inch = y
def __ge__(self, x):
val1 = self.ft * 12 + self.inch
val2 = x.ft * 12 + x.inch
if val1 >= val2:
return True
else:
return False
当使用 >=
运算符并返回真或假时,调用该方法。相应地,可以显示适当的信息。
>>> d1 = distance(2, 1)
>>> d2 = distance(4, 10)
>>> d1 >= d2
False
重要的魔术方法
下表列出了 Python 3 中的重要魔术方法。
初始化和构造
方法名 | 描述 |
---|---|
__new__(cls, other) |
在对象的实例化中被调用。 |
__init__(self, other) |
被 new 方法调用。 |
__del__(self) |
析构函数方法。 |
一元运算符和函数
方法名 | 描述 |
---|---|
__pos__(self) |
被要求一元正,例如 +someobject 。 |
__neg__(self) |
为一元负数被调用,例如 -someobject 。 |
__abs__(self) |
被内置的 abs() 函数调用。 |
__invert__(self) |
使用 ~ 运算符进行反演。 |
__round__(self, n) |
被内置 round() 函数调用。 |
__floor__(self) |
被内置的 math.floor() 函数调用。 |
__ceil__(self) |
被内置的 math.ceil() 函数调用。 |
__trunc__(self) |
被内置的 math.trunc() 函数调用。 |
扩充赋值
方法名 | 描述 |
---|---|
__iadd__(self, other) |
通过赋值来调用加法,例如 a += b 。 |
__isub__(self, other) |
在带赋值的减法运算中被调用,例如 a -= b 。 |
__imul__(self, other) |
被要求进行乘法运算,例如 a *= b 。 |
__ifloordiv__(self, other) |
通过赋值调用整数除法,例如 a //= b 。 |
__idiv__(self, other) |
被叫去分配任务,例如 a /= b 。 |
__itruediv__(self, other) |
被叫去真正的部门分配任务。 |
__imod__(self, other) |
通过赋值进行模调用,例如 a %= b 。 |
__ipow__(self, other) |
在有赋值的指数上被调用,例如 a **= b 。 |
__ilshift__(self, other) |
通过赋值(如 a << =b )在按位左移时被调用。 |
__irshift__(self, other) |
通过赋值进行右位移位调用,例如 a >> =b 。 |
__iand__(self, other) |
通过赋值按位“与”调用,例如 a &= b 。 |
__ior__(self, other) |
通过赋值按位“或”调用,例如 `a |
__ixor__(self, other) |
通过赋值进行按位异或调用,例如 ^=b 。 |
类型转换魔术方法
方法名 | 描述 |
---|---|
__int__(self) |
由内置 int() 方法调用,将类型转换为 int 。 |
__float__(self) |
由内置的 float() 方法调用,将类型转换为浮点。 |
__complex__(self) |
由内置的 complex() 方法调用,将类型转换为复杂类型。 |
__oct__(self) |
由内置的 oct() 方法调用,将类型转换为八进制。 |
__hex__(self) |
由内置的 hex() 方法调用,将类型转换为十六进制。 |
__index__(self) |
当对象在切片表达式中使用时,在类型转换为 int 时被调用。 |
__trunc__(self) |
从 math.trunc() 方法调用。 |
字符串魔术方法
方法名 | 描述 |
---|---|
__str__(self) |
方法调用以返回类型的字符串表示形式。 |
__repr__(self) |
由内置的 repr() 方法调用以返回类型的机器可读表示形式。 |
__unicode__(self) |
由内置的 unicode() 方法调用以返回类型的 Unicode 字符串。 |
__format__(self, formatstr) |
由内置的 string.format() 方法调用以返回新的字符串样式。 |
__hash__(self) |
由内置 hash() 方法调用以返回一个整数。 |
__nonzero__(self) |
由内置 bool() 方法调用以返回真或假。 |
__dir__(self) |
由内置的 dir() 方法调用以返回类的属性列表。 |
__sizeof__(self) |
由内置的 sys.getsizeof() 方法调用以返回对象的大小。 |
属性魔法方法
方法名 | 描述 |
---|---|
__getattr__(self, name) |
当访问不存在的类的属性时调用。 |
__setattr__(self, name, value) |
为类的属性赋值时调用。 |
__delattr__(self, name) |
在删除类的属性时调用。 |
运算符魔术方法
方法名 | 描述 |
---|---|
__add__(self, other) |
使用 + 运算符在添加操作时被调用。 |
__sub__(self, other) |
使用 - 运算符在减法运算时被调用。 |
__mul__(self, other) |
使用 * 运算符调用乘法运算。 |
__floordiv__(self, other) |
使用 // 运算符调用地板除法操作。 |
__truediv__(self, other) |
使用 / 运算符调用除法运算。 |
__mod__(self, other) |
使用 % 运算符进行模运算时调用。 |
__pow__(self, other[, mod]) |
使用 ** 运算符计算功率时被调用。 |
__lt__(self, other) |
使用 < 运算符进行比较时调用。 |
__le__(self, other) |
使用 <= 运算符进行比较时调用。 |
__eq__(self, other) |
使用 == 运算符进行比较时调用。 |
__ne__(self, other) |
使用 != 运算符进行比较时调用。 |
__ge__(self, other) |
使用 >= 运算符进行比较时调用。 |
因此,您可以使用适当的魔法方法在自定义类中添加各种功能。 | |
Further Reading: https://rszalski.github.io/magicmethods |