Python中类的特殊方法(也称为双下划线方法或魔术方法)是那些以双下划线("__")开头和结尾的方法。这些方法具有特殊的意义,它们被Python解释器用于执行特定的操作,如对象初始化、属性访问、比较、迭代等。以下是一些常见特殊方法的简要汇总:
1.初始化与析构:
(1).__init__(self, ...):类的初始化方法,当创建类的新实例(新对象)时,Python会自动调用此方法。
(2).__del__(self):对象的析构方法,当对象被销毁时调用,用于执行清理操作,比如关闭文件、释放外部资源等,它并不是用来删除对象或释放内存。此方法的调用时机是由Python的垃圾回收机制决定的,并不是在对象被删除时立即调用。
(3).__new__(cls, ...):静态方法,用于创建类的实例,在__init__之前调用。通常不需要重写此方法,除非需要控制对象的创建过程。__new__是类级别的方法,而__init__是实例级别的方法。
(4).__init_subclass__(cls, **kwargs):在子类被创建时自动调用。允许你在子类被定义时执行一些初始化操作,而不需要在子类中显式调用父类的方法。此方法在子类的__new__方法之后和__init__方法之前被调用。
2.属性访问:
(1).__getattr__(self, name):当访问的属性(self.__dict__)不存在时调用。适用于动态属性访问,注意与__getattribute__的区别。
(2).__setattr__(self, name, value):用于设置或更新对象的属性。当你为对象的属性赋值时,Python会自动调用这个方法。
(3).__delattr__(self, name):删除属性时调用。当使用del语句或delattr函数删除对象的属性时,如果类中定义了__delattr__方法,Python会调用这个方法而不是直接删除属性。
(4).__getattribute__(self, name):访问任何属性时调用,拦截所有对对象属性的访问。谨慎重写,因为它可能导致无限递归。
(5).__dir__(self):获取对象的所有属性名和方法名列表,用于dir()函数。
3.容器方法:
(1).__len__(self):当你对一个对象调用len()函数时,Python会自动查找该对象的__len__ 方法,并调用它来获取长度。
(2).__getitem__(self, index):允许类的实例支持类似列表(或任何可迭代对象)的索引操作。这意味着你可以使用方括号[]来访问实例中的元素。当你对一个对象使用索引操作时,Python会自动查找该对象的__getitem__方法,并调用它来获取对应的值。
(3).__setitem__(self, index, value):允许类的实例支持通过索引或键来设置项的值。当你使用像obj[index] = value这样的语法来设置类的实例中某个索引或键对应的值时,Python会自动调用该实例的__setitem__方法。
(4).__delitem__(self, index):允许类的实例支持通过索引或键来删除项。当你使用像del obj[index]这样的语法来从类的实例中删除某个索引或键对应的项时,Python会自动调用该实例的__delitem__方法。
(5).__iter__(self):允许类的实例支持迭代操作。当你对一个对象使用迭代器(比如使用for循环)时,Python会检查该对象是否实现了__iter__方法。如果实现了,Python会调用该方法来获取一个迭代器对象,然后使用该迭代器对象来遍历容器中的元素。该迭代器对象实现了两个方法:__iter__()返回迭代器对象本身(这允许迭代器被用在嵌套的循环中),以及__next__()用于返回容器的下一个元素。
(6).__next__(self):用于迭代器类中,以返回迭代器的下一个项。当一个迭代器被用于循环(如for循环)中时,Python会反复调用迭代器的__next__方法来获取序列中的下一个元素,直到__next__方法抛出一个StopIteration异常,表示迭代已完成,循环将终止。
(7).__reversed__(self):用于实现一个类的反向迭代。当你在一个对象上使用内置的reversed()函数时,Python会查找并调用该对象的__reversed__方法。这个方法应该返回一个迭代器,该迭代器会按照与原始对象相反的顺序产生元素。
(8).__contains__(self, value):当你使用in关键字来检查某个值是否存在于某个对象中时,Python会自动调用该对象的__contains__方法。
4.数值方法:
(1).__add__(self, other):当你将两个类的实例相加时,Python会自动调用这两个实例中任一个的__add__方法。
(2).__sub__(self, other):当你将类的两个实例相减时,Python会自动调用这个类的__sub__方法。
(3).__mul__(self, other):当你将类的两个实例相乘时,Python会自动调用这个类的__mul__方法。
(4).__truediv__(self, other):当你使用/运算符来操作两个对象时,Python会检查左侧对象的__truediv__方法是否存在。如果存在,Python会调用这个方法,并将右侧对象作为参数传入。如果不存在,Python会检查右侧对象是否有一个__rtruediv__方法,并以相反的顺序调用它。
(5).__floordiv__(self, other):当你使用//运算符来操作两个对象时,Python会首先检查左侧对象的__floordiv__方法是否存在。如果存在,Python会调用这个方法,并将右侧对象作为参数传入。如果不存在,Python会查找右侧对象的__rfloordiv__方法,并以相反的顺序调用它。
(6).__pow__(self, other[, modulo]):当你将类的两个实例作幂运算(**)时,Python会自动调用这个类的__pow__方法。
(7).__abs__(self):当你对类的实例执行绝对值操作时,Python会自动调用这个类的__abs__方法。
(8).__neg__(self):当你对类的实例执行一元负号运算符操作时,Python会自动调用这个类的__neg__方法。
(9).__pos__(self):当你对类的实例执行一元正号运算符操作时,Python会自动调用这个类的__pos__方法。
(10).__invert__(self):当你对类的实例执行按位取反运算符(~)操作时,Python会自动调用这个类的__invert__方法。
(11).__float__(self):当你将类的实例作为浮点数使用时,Python会自动调用这个类的__float__方法。类似的用法还有:__complex__、__int__、__round__、__oct__、__hex__、__index__、__trunc__。
(12).__mod__(self, other):当你将一个对象与另一个数(或支持模除操作的对象)使用%运算符时,Python会自动调用该对象的__mod__方法。
(13).__divmod__(self, other):当你对一个对象调用divmod函数(同时返回除法运算的商和余数)时,Python会检查此对象的__divmod__方法是否存在。如果存在,Python会调用这个方法。
(14).__lshift__(self, other):当你将一个对象与另一个数(或支持左移操作的对象)使用<<运算符时,Python会自动调用该对象的__lshift__方法。
(15).__rshift__(self, other):当你将一个对象与另一个数(或支持左移操作的对象)使用>>运算符时,Python会自动调用该对象的__rshift__方法。
(16).__and__(self, other):当你将一个对象与另一个对象(或值)使用&运算符时,Python会自动查找并调用左侧对象的__and__方法。
(17).__xor__(self, other):当你将一个对象与另一个对象(或值)使用^运算符时,Python会自动查找并调用左侧对象的__xor__方法。
(18).__or__(self, other):当你将一个对象与另一个对象(或值)使用|运算符时,Python会自动查找并调用左侧对象的__or__方法。
(19).__radd__(self, other):当左侧操作数不支持与右侧操作数直接相加时。
(20).__rsub__(self, other):当左侧操作数不支持与右侧操作数直接相减时。类似的用法还有__rand__、__rxor__、__ror__、__rmul__、__rturediv__、__rfloordiv__、__rmod__、__rdivmod__、__rpow__、__rlshift__、__rrshift__,Python会查找右侧对象的对应方法,并以相反的顺序调用它。
(21).__iadd__(self, other):当你对一个对象使用+=运算符来添加一个值时,Python会自动查找并调用该对象的__iadd__方法。
(22).__isub__(self, other):当你对一个对象使用-=运算符来减去一个值时,Python会自动查找并调用该对象的__isub__方法。类似的用法还有__imul__、__itruediv__、__ifoordiv__、__imod__、__ipow__、__ilshift__、__irshift__、__iand__、__ixor__、__ior__。
5.字符串与序列表示:
(1).__str__(self):当你使用print()函数打印对象,或者使用str()函数将对象转换为字符串时,Python会自动调用该对象的__str__方法。
(2).__repr__(self):当你使用repr()函数或者在交互式Python解释器(如IDLE)中直接输入一个对象时,Python会自动调用该对象的__repr__方法。
(3).__format__(self, format_spec):允许对象定义自己的格式化行为。当你使用字符串的format()方法时,会调用该对象的__format__方法。
(4).__reduce__(self):当你使用pickle序列化一个对象时,如果对象定义了__reduce__方法,pickle会调用这个方法而不是使用默认的序列化逻辑。
(5).__bytes__(self):当使用内置的bytes()函数将一个对象转换为字节序列时,如果该对象定义了__bytes__方法,则Python会调用该方法来完成转换。
6.上下文管理:
(1).__enter__(self):与with语句一起使用,在进入with代码块前调用。当一个对象与with语句一起使用时,Python会寻找该对象的__enter__和__exit__方法,用于在代码块执行前后自动执行资源分配和释放操作。
(2).__exit__(self, exc_type, exc_val, exc_tb):与with语句一起使用,在退出with代码块时调用,用于执行清理操作。
7.比较操作符:
(1).__lt__(self, other):"<"比较操作。
(2).__le__(self, other):"<="比较操作。
(3).__eq__(self, other):"=="比较操作。
(4).__ne__(self, other):"!="比较操作。
(5).__gt__(self, other):">"比较操作。
(6).__ge__(self, other):">="比较操作。
(7).__bool__(self):当你将类的实例用在需要布尔值的场合时,Python会自动调用该实例的__bool__方法。
8.其它:
(1).__hash__(self):用于获取对象的哈希值。这个哈希值是一个整数,用于支持哈希表(如字典的键、集合的成员)的快速查找、插入和删除操作。当一个对象被用作字典的键、添加到集合(set)中或者作为另一个集合的元素时,Python会自动调用该对象的__hash__方法来获取其哈希值。
(2).__call__(self, *args, **kwargs):当你定义一个类并实现了__call__方法后,你可以像调用普通函数那样调用这个类的实例,而Python会自动调用 __call__方法,并将传递给实例的参数传递给__call__方法。
(3).__class__:内置属性,只读的,用于访问对象的类,非特殊方法,每个对象都有一个__class__属性,这个属性指向了创建该对象的类。
(4).__dict__:内置属性,是一个字典,存储类的属性(包括数据属性和方法)。这个字典主要包含了在类中直接定义的属性,而不包括从基类继承的属性。
(5).__doc__:内置属性,用于存储类或函数(包括方法)的文档字符串。
(6).__module__:内置属性,用于标识一个类、函数、方法或变量是在哪个模块中定义的。
(7).__name__:内置属性,如果模块是直接运行的,__name__的值会被设置为"__main__"。如果模块是被其他模块导入的,__name__的值则会被设置为该模块的名称。可以使用if __name__ == "__main__": 块来包含仅在模块作为主程序运行时才应执行的代码。
以下为测试代码:
import colorama
import pickle
def create_instance(cls, *args, **kwargs):
return cls(*args, **kwargs)
class SpecialMethods(object):
"""special methods of class"""
'''initialization and destruction'''
def __init__(self, data=[]):
print(colorama.Fore.YELLOW + "call __init__ method")
self.csdn = "https://blog.csdn.net/fengbingchun" # 这里会调用__setattr__
self.github = "https://github.com/fengbingchun"
self.data = data
self.current = 0
self.high = len(data)
def __del__(self):
print(colorama.Fore.YELLOW + "call __del__ method" + colorama.Style.RESET_ALL)
def __new__(cls, *args, **kwargs):
print(colorama.Fore.YELLOW + "call __new__ method")
return super(SpecialMethods, cls).__new__(cls)
def __init_subclass__(cls, **kwargs):
print(colorama.Fore.YELLOW + "call __init_subclass__ method")
super().__init_subclass__(**kwargs)
print(f"subclass {cls.__name__} created")
'''property access'''
def __setattr__(self, name, value):
print(colorama.Fore.YELLOW + "call __setattr__ method")
self.__dict__[name] = value # 使用__dict__来避免无限递归
def __getattr__(self, name):
print(colorama.Fore.YELLOW + "call __getattr__ method")
if name in self.__dict__:
return self.attributes[name]
else:
# raise ArithmeticError(f"'{type(self).__name__}' object has no attribute '{name}'")
print(colorama.Fore.RED + f"'{type(self).__name__}' object has no attribute '{name}'")
def __delattr__(self, name):
print(colorama.Fore.YELLOW + "call __delattr__ method")
if name in self.__dict__:
super().__delattr__(name)
else:
print(colorama.Fore.RED + f"'{type(self).__name__}' object has no attribute '{name}'")
# def __getattribute__(self, name):
# print(colorama.Fore.YELLOW + "call __getattribute__ method")
def __dir__(self):
print(colorama.Fore.YELLOW + "call __dir__ method")
default_dir = super().__dir__()
modified_dir = [attr for attr in default_dir if attr != "_protected_method" and attr != "__private_method" ]
return modified_dir
def _protected_method(self):
print("call _protected_method method")
def __private_method(self):
pass
'''container methods'''
def __len__(self):
print(colorama.Fore.YELLOW + "call __len__ method")
return len(self.__dict__)
def __getitem__(self, index):
print(colorama.Fore.YELLOW + "call __getitem__ method")
return self.data[index]
def __setitem__(self, index, value):
print(colorama.Fore.YELLOW + "call __setitem__ method")
self.data[index] = value
def __delitem__(self, index):
print(colorama.Fore.YELLOW + "call __delitem__ method")
del self.data[index]
self.high = len(self.data)
def __iter__(self):
print(colorama.Fore.YELLOW + "call __iter__ method")
return self
def __next__(self):
print(colorama.Fore.YELLOW + "call __next__ method")
if self.current >= self.high:
raise StopIteration
else:
self.current += 1
return self.data[self.current - 1]
def __reversed__(self):
print(colorama.Fore.YELLOW + "call __reversed__ method")
return reversed(self.data)
def __contains__(self, value):
print(colorama.Fore.YELLOW + "call __contains__ method")
return value in self.data
'''numerical methods'''
def __add__(self, other):
print(colorama.Fore.YELLOW + "call __add__ method")
if isinstance(other, SpecialMethods):
return list(map(lambda x, y: x + y, self.data, other.data))
elif isinstance(other, (int, float)):
return [x + other for x in self.data]
else:
return NotImplemented
def __radd__(self, other):
print(colorama.Fore.YELLOW + "call __radd__ method")
return self.__add__(other)
def __sub__(self, other):
print(colorama.Fore.YELLOW + "call __sub__ method")
if isinstance(other, SpecialMethods):
return list(map(lambda x, y: x - y, self.data, other.data))
elif isinstance(other, (int, float)):
return [x - other for x in self.data]
else:
return NotImplemented
def __rsub__(self, other):
print(colorama.Fore.YELLOW + "call __rsub__ method")
return self.__sub__(other)
def __mul__(self, other):
print(colorama.Fore.YELLOW + "call __mul__ method")
return list(map(lambda x, y: x * y, self.data, other.data))
def __truediv__(self, other):
print(colorama.Fore.YELLOW + "call __truediv__ method")
assert isinstance(other, (int, float))
return [x / other for x in self.data]
def __floordiv__(self, other):
print(colorama.Fore.YELLOW + "call __floordiv__ method")
assert isinstance(other, (int, float))
return [x // other for x in self.data]
def __pow__(self, other, modulo=None):
print(colorama.Fore.YELLOW + "call __pow__ method")
if modulo is not None:
return [pow(x, other, modulo) for x in self.data]
return [pow(x, other) for x in self.data]
def __abs__(self):
print(colorama.Fore.YELLOW + "call __abs__ method")
return [abs(x) for x in self.data]
def __neg__(self):
print(colorama.Fore.YELLOW + "call __neg__ method")
return [-x for x in self.data]
def __pos__(self):
print(colorama.Fore.YELLOW + "call __pos__ method")
return self.data
def __invert__(self):
print(colorama.Fore.YELLOW + "call __invert__ method")
return [~x for x in self.data]
def __float__(self):
print(colorama.Fore.YELLOW + "call __float__ method")
return float(self.data[0])
def __mod__(self, other):
print(colorama.Fore.YELLOW + "call __mod__ method")
return [x % other for x in self.data]
def __divmod__(self, other):
print(colorama.Fore.YELLOW + "call __divmod__ method")
assert isinstance(other, (int, float))
quotient, remainder = divmod(self.data[0], other)
return quotient, remainder
def __lshift__(self, other):
print(colorama.Fore.YELLOW + "call __lshift__ method")
return [x << other for x in self.data]
def __rshift__(self, other):
print(colorama.Fore.YELLOW + "call __rshift__ method")
return [x >> other for x in self.data]
def __and__(self, other):
print(colorama.Fore.YELLOW + "call __and__ method")
return [x & other for x in self.data]
def __xor__(self, other):
print(colorama.Fore.YELLOW + "call __xor__ method")
return [x ^ other for x in self.data]
def __or__(self, other):
print(colorama.Fore.YELLOW + "call __or__ method")
return [x | other for x in self.data]
def __iadd__(self, other):
print(colorama.Fore.YELLOW + "call __iadd__ method")
self.data = [ x + other for x in self.data]
return self
def __isub__(self, other):
print(colorama.Fore.YELLOW + "call __isub__ method")
self.data = [x - other for x in self.data]
return self
'''string and sequence representation'''
def __str__(self):
print(colorama.Fore.YELLOW + "call __str__ method")
return f"SpecialMethods class(csdn:{self.csdn}; github:{self.github})"
def __repr__(self):
print(colorama.Fore.YELLOW + "call __repr__ method")
return f"SpecialMethods class(data:{self.data})"
def __format__(self, format_spec):
print(colorama.Fore.YELLOW + "call __format__ method")
return format(str(self), format_spec)
def __reduce__(self):
print(colorama.Fore.YELLOW + "call __reduce__ method")
return (create_instance, (SpecialMethods, self.data))
def __bytes__(self):
print(colorama.Fore.YELLOW + "call __bytes__ method")
return str(self.data).encode("utf-8")
'''context management'''
def __enter__(self):
print(colorama.Fore.YELLOW + "call __enter__ method")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print(colorama.Fore.YELLOW + "call __exit__ method")
if exc_type is not None:
print(f"Execution: {exc_type}:{exc_val}")
'''comparison operators'''
def __lt__(self, other):
print(colorama.Fore.YELLOW + "call __lt__ method")
if not isinstance(other, SpecialMethods):
return NotImplemented
return self.data[0] < other.data[0]
def __le__(self, other):
print(colorama.Fore.YELLOW + "call __le__ method")
if not isinstance(other, SpecialMethods):
return NotImplemented
return self.data[0] <= other.data[0]
def __eq__(self, other):
print(colorama.Fore.YELLOW + "call __eq__ method")
if not isinstance(other, SpecialMethods):
return NotImplemented
return self.data[0] == other.data[0]
def __ne__(self, other):
print(colorama.Fore.YELLOW + "call __ne__ method")
return not self.__eq__(other)
def __gt__(self, other):
print(colorama.Fore.YELLOW + "call __gt__ method")
if not isinstance(other, SpecialMethods):
return NotImplemented
return self.data[0] > other.data[0]
def __ge__(self, other):
print(colorama.Fore.YELLOW + "call __ge__ method")
if not isinstance(other, SpecialMethods):
return NotImplemented
return self.data[0] >= other.data[0]
def __bool__(self):
print(colorama.Fore.YELLOW + "call __bool__ method")
return self.data[0] != 0
'''other'''
def __hash__(self):
print(colorama.Fore.YELLOW + "call __hash__ method")
return hash(self.data[0])
def __call__(self, *args, **kwargs):
print(colorama.Fore.YELLOW + "call __call__ method")
self._protected_method()
class SubClass(SpecialMethods):
pass
if __name__ == "__main__":
colorama.init(autoreset=True)
# initialization and destruction
methods1 = SpecialMethods()
print("methods.special_attribute:", methods1.special_attribute)
# property access
del methods1.addr
methods1.addr = "Tianjin"
print("methods.addr:", methods1.addr)
del methods1.addr
print("dir:", dir(methods1))
# container methods
print("len:", len(methods1))
methods2 = SpecialMethods([2, 4, 6, 8, 10])
print("index3:", methods2[3])
methods2[3] = -10
print("indx3:", methods2[3])
del methods2[3]
print("index3:", methods2[3])
for value in methods2:
print("value:", value)
for value in reversed(methods2):
print("value:", value)
print(5 in methods2)
print(10 in methods2)
# numerical methods
print(methods2 + methods2)
print(methods2 + 88)
print(88 + methods2)
print(methods2 - 88)
print(88 - methods2)
print(methods2 * methods2)
print(methods2 / 2)
print(methods2 // 2)
print(methods2 ** 2)
print(methods2 % 3)
print(divmod(methods2, 2))
print(methods2 << 2)
print(methods2 >> 2)
print(methods2 & 3)
print(methods2 ^ 3)
print(methods2 | 3)
methods2 += 3
print(methods2)
methods2 -= 3
print(methods2)
methods3 = SpecialMethods([-2, 4, -6, 8, -10])
print(abs(methods3))
print(-methods3)
print(+methods3)
print(~methods3)
print(float(methods3))
# string and sequence representation
print(str(methods3))
print(repr(methods3))
print(format(methods3))
serialized = pickle.dumps(methods3)
reconstructed = pickle.loads(serialized)
print(reconstructed.data)
print(bytes(methods2))
# context management
with methods3 as md3:
print(md3)
# comparison operators
print(methods2 < methods3)
print(methods2 <= methods3)
print(methods2 == methods3)
print(methods2 != methods3)
print(methods2 > methods3)
print(methods2 >= methods3)
if methods2:
print("methods2 is True")
# other
print(hash(methods2))
print(hash(methods3))
methods3()
print("__class__:", methods3.__class__)
print("__dict__:", methods3.__dict__)
print("__doc__:", methods3.__doc__)
print("__module__:", methods3.__module__)
print("__name__:", SpecialMethods.__name__)
print(colorama.Fore.GREEN + "====== test finish ======")
执行结果如下图所示: