Python-魔术方法

一、__new__方法

触发时机:实例化类生成对象的时候触发(触发时机在__init__之前)
功能:控制对象的创建过程
参数:至少一个cls接受当前的类,其他根据情况决定
返回值:通常返回对象或None

1.基本语法

class MyClass():
	a = 1

obj = MyClass()
print(obj)

class MyClass1(object):
	def __new__(cls):
		print(cls)
		# (1)借助父类object 类.方法(),返回本类自己的对象
		# obj = object.__new__(cls)
		# return obj
		# (2)返回其他类的对象
		# return obj
		# (3)不返回任何对象
		return None
		
obj = MyClass1()
print(obj)

2.new方法的触发时机要快于init

new 用来创建对象
init 用来初始化对象(前提的有对象)
先创建对象,再去初始化对象,所以new快于init

class Boat():
	def __init__(self):
		print(2)
		
	def __new__(cls):
		print(1)
		return object.__new__(cls)
obj = Boat()

3.new方法的参数要和init方法参数一一对应

# 一个参数
class Boat():
	def __new__(cls,name):
		return object.__new__(cls)
	
	def __init__(self,name):
		self.name = name
		
obj = Boat("泰坦尼克号")
print(obj.name)


# 多个参数
class Boat():
	def __new__(cls,*args,**kwargs):
		return object.__new__(cls)
	
	def __init__(self,name,a,b,c,d,e):
		self.name = name
		
obj = Boat("泰坦尼克号",2,3,4,5,6)
print(obj.name)

4.如果返回的不是本类的对象,不会触发__init__构造方法

print("<=====>")
class MyClass():
	a = 1
other_obj = MyClass()

class Boat():
	def __new__(cls):
		return other_obj
	
	def __init__(self):
		print("构造方法被触发~")

obj = Boat()

二、单例(态)模式

目的意义:
为了节省内存空间,仅仅是为了调用类中的成员,
不需要额外给该对象添加任何成员,这个场景,使用单态.
比如:操作数据库的增删改查这样的类,是不需要的.

1.基本语法

class Singleton():
	__obj = None
	def __new__(cls):
		if cls.__obj is None:
			cls.__obj = object.__new__(cls)
		return cls.__obj 

"""
<__main__.Singleton object at 0x000001FB3F207278>
有这个对象直接返回,没这个对象,就给你创建,保证只有一个
第一次实例化时,if cls.__obj is None 条件为真 , 创建一个对象放到cls.__obj , 最后返回
第二次实例化时,if cls.__obj is None 条件为假 , 直接返回
第三次实例化时,if cls.__obj is None 条件为假 , 直接返回
第三次实例化时,if cls.__obj is None 条件为假 , 直接返回
"""

obj1 = Singleton()
print(obj1)
obj2 = Singleton()
print(obj2)
obj3 = Singleton()
print(obj3)
obj4 = Singleton()
print(obj4)
# 打印结果为同一个对象

2.单态模式+构造方法 小练习

class Singleton():
	__obj = None
	def __new__(cls,*args,**kwargs):
		if cls.__obj is None:
			cls.__obj = object.__new__(cls)
		return cls.__obj 

	def __init__(self,name):
		self.name = name
		
obj1 = Singleton("aaa")
obj2 = Singleton("bbb")
# 求答案
print(obj1.name)
print(obj2.name)
# obj1 和 obj2 都是同时指向同一个对象,因为对象只创建了一个对象.name  是获取他后边bbb那个值,是同一个值打印了2次;

三、__del__析构方法

触发时机:当对象被内存回收的时候自动触发[1.页面执行完毕回收所有变量 2.所有对象被del的时候]
功能:对象使用完毕后资源回收
参数:一个self接受对象
返回值:无

1.基本方法

del只会触发一次,即如果先把所有的对象给删除了,那么在执行完所有代码之后不会再触发

class LangDog():
	food = "吃肉"
	def __init__(self,name):
		self.name = name
		
	def __del__(self):
		print("析构方法被触发..")
	
#(1) 页面执行完毕回收所有变量
obj = LangDog("刀疤")
print(obj.name)

#(2) 所有对象被del的时候
"""
当一个值,没有任何变量指向或者说引用,这个值才会被真正的释放
"""
other_obj = obj
print(other_obj is obj)
print("<==start==>")
del obj
del other_obj
print("<==end==>")

2.模拟文件操作练习

将文件操作也封装起来,这要其他同事在使用文件操作时候,只需要调用我们写的代码就可以了,减少了代码冗余

import os
class ReadFile():
	def __new__(cls,filename):
		# 判断文件是否存在
		if os.path.exists(filename):
			return object.__new__(cls)
		else:
			return print("该文件是不存在的")
		
	def __init__(self,filename):
		# 打开文件操作
		self.fp = open(filename,mode="r",encoding="utf-8")
		
	def readcontent(self):		
		# 读取文件操作
		content = self.fp.read()
		return content
		
	def __del__(self):
		self.fp.close()
		

		
obj = ReadFile("ceshi.txt")
res = obj.readcontent()
print(res)

四、__str__与__repr__方法

1.__str__

触发时机: 使用print(对象)或者str(对象)的时候触发
功能: 查看对象
参数: 一个self接受当前对象
返回值: 必须返回字符串类型

class Cat():
	gift = "传说中的小猫有九条命,喜欢卖萌和上树"
	
	def __init__(self,name):
		self.name = name
		
	def __str__(self):
		return self.cat_info()
		
	def cat_info(self):
		return "{}小猫有故事-{}".format(self.name,self.gift)

tom = Cat("汤姆")
# 触发方式一, print 打印该对象
print(tom)
# 触发方式二, str
res = str(tom)
print(res)

2.__repr__

触发时机: 使用repr(对象)的时候触发
功能: 查看对象,与魔术方法__str__相似
参数: 一个self接受当前对象
返回值: 必须返回字符串类型

class Mouse():
	gift = "打洞"
	
	def __init__(self,name):
		self.name = name
		
	def __repr__(self):
		return self.mouse_info()
		
	def mouse_info(self):
		return "{}老鼠天赋是{},龙生龙,凤生凤,老鼠的儿子会打洞".format(self.name,self.gift)
		
	# 在系统底层,如果定义了repr , 将会默认赋值给str方法.
	# __str__ = __repr__
		

# repr强转obj对象时触发		
obj = Mouse("杰瑞")
res = repr(obj)
print(res)

# 注意点 底层存在赋值调用给str的语法,所以能实现打印或者str强转对象的触发机制.
print(obj)
res = str(obj)
print(res)

五、__call__方法

触发时机:把对象当做函数调用时候自动触发
功能:模拟函数化操作

参数:参数不固定,至少一个self参数

返回值:看需求

1.基本用法

class MyClass():
	a = 1
	""""""
	def __call__(self):
		print("call魔术方法被触发..")	

obj = MyClass()
obj()

2.call魔术方法的应用

# 模拟洗衣服的过程
class Wash():

	# 用call魔术方法统一调用
	def __call__(self,something):
		self.step1(something)
		self.step2()
		self.step3()

	def step1(self,something):
		print("脱衣服,洗{}".format(something))
		
	def step2(self):
		print("放水里,扔点洗衣液,洗衣粉,蓝月亮")
		
	def step3(self):
		print("扭干净,穿上")

# 利用魔术方法我们只需要两步完成了洗衣服的过程,并且之后洗衣服只需要一个语句
obj = Wash()
obj("裤衩")
obj("衣服")
obj("袜子")
obj("毛巾")
# 如不使用魔术方法,我们每次洗衣服都需要调三个函数
obj.step1("裤衩")
obj.step2()
obj.step3()
obj.step1("衣服")
obj.step2()
obj.step3()
obj.step1("袜子")
obj.step2()
obj.step3()
obj.step1("毛巾")
obj.step2()
obj.step3()

3.模拟内置函数int

import math
class MyInt():

	def mycalc(self,num,sign=1):
		# 去掉左边多余的0
		strvar = num.lstrip("0")
		if strvar == "":
			return 0
		# 计算最终的结果
		return eval(strvar) * sign


	def __call__(self,num):
	
		# 判断是布尔类型
		if isinstance(num,bool):
			if num == True:
				return 1
			else:
				return 0
		# 判断是整型
		elif isinstance(num,int):
			return num
		# 判断是浮点型
		elif isinstance(num,float):
			# 方法一
			'''
			strvar = str(num)			
			return strvar.split(".")[0]
			'''
			# 方法二
			"""
			if num >= 0 :
				return math.floor(num)
			else:
				return math.ceil(num)
			"""
			return math.floor(num) if num >= 0 else math.ceil(num)
			
		elif isinstance(num,str):
			# 首字符是+或者-  后边的是纯数字字符串
			if (num[0] == "+"  or  num[0] == "-") and num[1:].isdecimal():
				if num[0] == "+":
					sign = 1
				else:
					sign = -1
				return self.mycalc(num[1:],sign)
				
			elif num.isdecimal():
				return self.mycalc(num)
				
			else:
				return "老铁,这个真不能转~"

六、__bool__方法

触发时机:使用bool(对象)的时候自动触发

功能:强转对象

参数:一个self接受当前对象

返回值:必须是布尔类型

类似的还有如下(了解):

__complex__(self)      # 被complex强转对象时调用
__int__(self)          # 被int强转对象时调用
__float__(self)        # 被float强转对象时调用

基本语法

class MyClass():
	def __bool__(self):
		return True
		
obj = MyClass()
res = bool(obj)
print(res)

七、__add__方法

触发时机:使用对象进行运算相加的时候自动触发

功能:对象运算

参数:两个对象参数

返回值:运算后的值(其中的运算规则可以自己定制)

类似的还有如下(了解):

	__sub__(self, other)           # 定义减法的行为:-
	__mul__(self, other)           # 定义乘法的行为:
	__truediv__(self, other)       # 定义真除法的行为:/

基本语法及小练习

class MyAdd():
	def __init__(self,num):
		self.num = num

	# 对象在加号+左侧的时,自动触发
	def __add__(self,other):
		return self.num + other
		
	def __radd__(self,other):
		return self.num + other*2
		
# 情况一
a = MyAdd(7)
res = a + 7
print(res)
# self 接受a   other接受7 , 触发的是__add__方法

# 情况二
a = MyAdd(7)
res = 7 + a
print(res)
# self 接受a   other接受7 , 触发的是__radd__方法

# 情况三
a = MyAdd(7)
b = MyAdd(8)
res = a+b
print(res)
'''
a+b 先触发 __add__  ,self 接受的7 , other 接受的是b
res = 7+b

7+b 再触发 __radd__ ,self 接受的b , other 接受的是7
return  8+7*2 = 22
res = 22
'''

八、__len__方法

触发时机:使用len(对象)时自动触发

功能:用于检测对象中或者类中成员的个数

参数:一个self参数,用来接收当前对象

返回值:必须是整型

类似的还有如下(了解):

__iter__(self)                 # 定义迭代容器中的元素的行为
__reversed__(self)             # 定义当被 reversed() 调用时的行为
__contains__(self, item)       # 定义当使用成员测试运算符(in 或 not in)时的行为

基本语法及使用

class MyClass():
	pty1 = 1
	pty2 = 2
	__pty3 = 3
	
	def func1():
		pass
		
	def func2():
		pass
	def __func3():
		pass
	
	def func4():
		pass
		
	def __len__(self):
		# print(MyClass.__dict__)
		# lst = []
		# for i in MyClass.__dict__:
			# print(i)
			# if not(  i.startswith("__") and i.endswith("__")  ):
				# lst.append(i)
		# print(lst)	
		
		# 简写
		lst = [i for i in MyClass.__dict__ if not(  i.startswith("__") and i.endswith("__")  )]
		return len(lst)
		
obj = MyClass()
print(len(obj))

九、__getattr__方法

基本语法及使用

当对象访问一个不存在的属性时候,会触发该方法。

class Student:
    def __init__(self, name, sex, age):
        self.name = name
        self.sex = sex
        self.age = age

    def __getattr__(self,x):
        return '你没有这个属性,小老弟'

s = Student('yang','male',18)
print(s.name)
print(s.salary)
------------------
yang
你没有这个属性,小老弟

十、魔术属性

以__开头__结尾的属性,称为魔术属性,如之前ATM项目中使用到的__name__就是魔术属性.

本笔记记录常用的五种魔术属性,dict,doc,name,class,bases

class Man():
	pass

class Woman():
	pass

class Children(Man,Woman):

	"""
	成员属性: eye 
	成员方法: skylight moonread __makebaby
	完成的功能: 描述宇智波一族的天赋技能.
	"""

	eye = "血轮眼"
	
	def skylight(self):
		print("使用")
		
	def moonread(self,func):
		print("使用了月读,世界都幻境里~")
		print(func.__name__ , type(  func.__name__  )) # earth_boom
	
	def __makebaby(self):
		print("这一手招数,只能我自己用")

obj = Children()

# __dict__ 获取对象或类的内部成员结构
print(obj.__dict__)
print(Children.__dict__)

# __doc__  获取对象或类的内部文档
print(obj.__doc__)
print(Children.__doc__)

# __name__  获取类名函数名
def earth_boom():
	print("使出一招地爆天星")
obj.moonread(earth_boom)
obj.moonread(Children)

# __class__ 获取当前对象所属的类
print(obj.__class__)

# __bases__ 获取一个类直接继承的所有父类,返回元组
print(Children.__bases__) # (<class '__main__.Man'>, <class '__main__.Woman'>)
原文地址:https://www.cnblogs.com/chiyun/p/14066047.html