Magic or Dunder Methods in Python
2023-09-17 22:15:31
Python 中的魔术方法是以双下划线开头和结尾的特殊方法。
它们也称为 dunder 方法。magic 方法并不意味着由您直接调用,但调用发生在类内部的特定操作上。
例如,当您使用 + 运算符将两个数字相加时,将在内部调用 __add__()
方法。
Python 中的内置类定义了许多神奇的方法。
使用 dir()
函数查看类继承的魔术方法的数量。
例如,下面列出了 int
类中定义的所有属性和方法。
示例: Define Static Method
print(dir(int))
#output:
#['__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__
方法是一种魔术方法,当我们使用 + 运算符将两个数字相加时,就会调用它。
请考虑以下示例。
示例: Dunder Method
num=10
res = num.__add__(5)
print(res)
如您所见,当您执行num+10
时,+ 运算符调用 __add__(10)
方法。
您也可以直接调用num.__add__(5)
,这将给出相同的结果。
但是,如前所述,魔术方法并不意味着直接调用,而是在内部通过其他一些方法或操作调用。
魔术方法最常用于定义 Python 中预定义运算符的重载行为。例如,默认情况下,算术运算符对数字操作数进行操作。 这意味着数字对象必须与 +、-、*、/等运算符一起使用。+ 运算符也定义为字符串、列表和元组类中的串联运算符。我们可以说 + 运算符是重载的。
为了使重载行为在您自己的自定义类中可用,应重写相应的 magic 方法。例如,为了将 + 运算符用于用户定义类的对象,它应该包括 __add__()
方法。
让我们看看如何实现和使用一些重要的魔术方法。
__new__() 方法(__new__() method)
Java 和 C# 等语言使用 new 运算符来创建类的新实例。在 Python 中,__new__()
magic 方法在 __init__()
方法之前隐式调用。__new__()
方法返回一个新对象,然后由 __init__()
初始化。
示例: __new__()
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
类的实例时生成以下输出。
__new__()
方法在__init__()
方法之前调用。
__str__() 方法(__str__() method)
另一种有用的魔术方法是 __str__()
.它被重写以返回任何用户定义类的可打印字符串表示形式。
我们已经看到了str()
内置函数,它从对象参数返回一个字符串。例如,str(12)
返回"12"。调用时,它会调用 int 类中的 __str__()
方法。
示例: __str__()
num=12
val = int.__str__(num)
print(type(val))
现在让我们重写 employee
类中的 __str__()
方法以返回其对象的字符串表示形式。
示例: __str__()
class employee:
def __init__(self):
self.name='Swati'
self.salary=10000
def __str__(self):
return 'name='+self.name+', salary=$'+str(self.salary)
e1 = employee()
print(e1)
str()
函数在内部调用上述 employee
类中定义的 __str__()
方法。这就是为什么它被称为神奇的方法!
__add__() 方法(__add__() method)
在下面的示例中,名为 distance 的类是使用两个实例属性 - ft 和 ininch 定义的。这两个距离对象的相加需要使用重载 + 运算符执行。
为此,将覆盖魔术方法__add__()
,该方法执行两个对象的 ft 和 inch 属性的相加。
__str__()
方法返回对象的字符串表示形式。
示例: Override __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)
d1=distance(3,10)
d2=distance(4,4)
print("d1= {} d2={}".format(d1, d2))
d3=d1+d2
print(d3)
该示例重载了使用 + 运算符添加两个对象时将调用的 __add__()
方法。
__ge__() 方法(__ge__() method)
在距离类中添加以下方法以使>=
运算符重载。
示例: __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)
print(d1>=d2)
使用 >=
运算符时调用 __ge__()
方法并返回 True 或 False。因此,可以显示相应的消息。
重要的魔术方法(Important Magic Methods)
下表列出了 Python 3 中重要的魔术方法。
Initialization and Construction | 描述 |
---|---|
__new__(cls, other) | To get called in an object's instantiation. |
__init__(self, other) | To get called by the __new__ method. |
__del__(self) | Destructor method. |
Unary operators and functions | 描述 |
---|---|
__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() 函数调用。 |
Augmented Assignment | 描述 |
---|---|
__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) | 通过赋值在按位 AND 上调用,例如 a&=b。 |
__ior__(self, other) | 通过赋值在按位 OR 上调用,例如 a|=b。 |
__ixor__(self, other) | 在按位 XOR 上调用赋值,例如 a ^=b。 |
Type Conversion Magic Methods | 描述 |
---|---|
__int__(self) | 通过内置 int int() 方法调用以将类型转换为 int。 |
__float__(self) | 通过内置 float() 方法调用以将类型转换为浮点数。 |
__complex__(self) | 通过内置 complex() 方法调用以将类型转换为复杂类型。 |
__oct__(self) | 通过内置 oct() 方法调用以将类型转换为八进制。 |
__hex__(self) | 通过内置 inty() 方法调用以将类型转换为十六进制。 |
__index__(self) | 在切片表达式中使用对象时在类型转换为 int 时调用。 |
__trunc__(self) | 从 math.trunc() 方法调用。 |
String Magic Methods | 描述 |
---|---|
__str__(self) | 通过内置 str() 方法调用以返回类型的字符串表示形式。 |
__repr__(self) | 通过内置 int repr() 方法调用以返回类型的机器可读表示形式。 |
__unicode__(self) | 通过内置 unicode() 方法调用以返回某个类型的 unicode 字符串。 |
__format__(self, formatstr) | 通过内置 string.format() 方法调用以返回新样式的字符串。 |
__hash__(self) | 通过内置 hash() 方法调用以返回整数。 |
__nonzero__(self) | 通过内置 bool() 方法调用以返回 True 或 False。 |
__dir__(self) | 通过内置 dir() 方法调用以返回类的属性列表。 |
__sizeof__(self) | 通过内置 sys.getsizeof() 方法调用以返回对象的大小。 |
Attribute Magic Methods | 描述 |
---|---|
__getattr__(self, name) | 当不存在的类的访问属性时调用。 |
__setattr__(self, name, value) | 在为类的属性赋值时调用。 |
__delattr__(self, name) | 在删除类的属性时调用。 |
Operator Magic Methods | 描述 |
---|---|
__add__(self, other) | 使用 + 运算符调用添加操作 |
__sub__(self, other) | 使用 - 运算符调用减法运算。 |
__mul__(self, other) | 使用 * 运算符在乘法运算时调用。 |
__floordiv__(self, other) | 使用//运算符调用楼层划分操作。 |
__truediv__(self, other) | 使用/运算符在除法操作中调用。 |
__mod__(self, other) | 使用 % 运算符调用模运算。 |
__pow__(self, other[, modulo]) | 调用使用 ** 运算符计算功率。 |
__lt__(self, other) | 使用运算符在比较时调用<。 |
__le__(self, other) | 使用 <= 运算符在比较时调用。 |
__eq__(self, other) | 使用 == 运算符在比较时调用。 |
__ne__(self, other) | 使用 != 运算符在比较时调用。 |
__ge__(self, other) | 使用 >= 运算符在比较时调用。 |
因此,您可以使用适当的魔术方法在自定义类中添加各种功能。
注意:
本文内容总结: