Python中类的特殊方法(双下划线方法)汇总

      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 ======")

      执行结果如下图所示:

      GitHubhttps://github.com/fengbingchun/Python_Test

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值