day25:7个魔术方法&5个关于类的魔术属性
目录
一个小表格方便记忆哈
__del__ (析构方法)
__del__简要介绍
1.触发时机:当对象被内存回收的时候自动触发
(1)页面执行完毕回收所有变量
(2)所有对象被del的时候
2.功能:对象使用完毕后资源回收
3.参数:一个self接受对象
4.返回值:无
第一种情况:页面执行完毕回收所有变量
class LangDog(): food = "改吃蔬菜" def __init__(self, name): self.name = name def __del__(self): print("析构方法被触发") print("0001=====") obj = LangDog("肉丝") print("0002=====") # 1.页面执行完毕回收所有变量 print(obj.name) # 当执行完这句话后,才算页面执行完毕,这个时候触发__del__析构方法 ''' 运行结果: ===== ===== 肉丝 析构方法被触发 '''
第二种情况:所有对象被del的时候
如何理解第二种情况中所说到的所有对象?
代码如下:
class LangDog(): food = "改吃蔬菜" def __init__(self, name): self.name = name def __del__(self): print("析构方法被触发") obj1 = LangDog("肉丝") obj2 = obj1 print("<=====start=====>") del obj1 print("<=====end=====>")
打印结果:
虽然obj1对象被删除了,但是obj2对象并没有被删除,所以不会触发析构方法
打印了“析构方法被触发”是因为整个页面执行完毕了,也会触发析构方法
使用__del__模拟文件操作
# 3.模拟文件操作 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): # 读取文件 return self.fp.read() def __del__(self): # 关闭文件 self.fp.close() obj = ReadFile("1.txt") if obj is not None: res = obj.readcontent() print(res) else: print("没有该类文件") # 当然,也可以用三元运算符来实现 """ 真值 if 条件表达式 else 假值 """ print(obj.readcontent()) if obj is not None else print("没有该类文件")
魔术方法:__str__
__str__简要介绍
1.触发时机: 使用print(对象)或者str(对象)的时候触发
2.功能: 查看对象
3.参数: 一个self接受当前对象
4.返回值: 必须返回字符串类型
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,5000) # __repr__ = __str__ tom = Cat("汤姆") # 方法一. print(对象) print(tom) # 方法二. str(对象) res = str(tom) print(res)
魔术方法:__repr__
1.触发时机: 使用repr(对象)的时候触发
2.功能: 查看对象,与魔术方法__str__相似
3.参数: 一个self接受当前对象
4.返回值: 必须返回字符串类型
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) # 系统在底层,自动加了一句赋值操作 __str__ = __repr__ jerry = Mouse("杰瑞") res = repr(jerry) print(res) # 因为系统底层赋值的原因,在打印对象或者强转对象为字符串的时候,仍然可以触发; print(jerry) res = str(jerry) print(res)
魔术方法:__call__
1.触发时机:把对象当作函数调用的时候自动触发
2.功能: 模拟函数化操作
3.参数: 参数不固定,至少一个self参数
4.返回值: 看需求
基本用法
# (1) 基本用法 class MyClass(): a = 1 def __call__(self): print("call魔术方法被触发了") obj = MyClass() # 实例化一个对象 obj() # 把对象当做函数调用,此时会触发__call__方法
模拟洗衣服的过程
# (2) 模拟洗衣服的过程 class Wash(): def __call__(self,something): print("我现在要洗{}".format(something)) self.step1() self.step2() self.step3() return "洗完了" def step1(self): print("加热水,家洗衣粉,加洗衣液,加洗涤剂") def step2(self): print("衣服泡进去搅乱 打散 搓一搓~ ") def step3(self): print("脱水,穿上") obj = Wash() # 方法一 # obj.step1() # obj.step2() # obj.step3() # 方法二 res = obj("衣服") # 把对象obj当做函数进行调用,此时触发__call__方法,执行__call__方法所有内容 print(res)
模拟内置的int方法,实现相应的操作(有时间再分析)
# (3) 模拟内置int 实现相应的操作 import math class MyInt(): def calc(self,num,sign=1): # print(num,sign) # 去掉左边多余的0 strvar = num.lstrip("0") # print(strvar) # 为了防止都是0 ,如果去掉之后为空,返回0 if strvar == "": return 0 # 正常情况下,执行存数字字符串变成数字 , 在乘上相应的符号,得出最后的结果 return eval(strvar) * sign def __call__(self,num): if isinstance(num , bool): if num == True: return 1 elif num == False: return 0 elif isinstance(num,int): return num elif isinstance(num,float): # 方法一 """ strvar = str(num) lst = strvar.split(".") return eval(lst[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.calc(num[1:],sign) elif num.isdecimal(): return self.calc(num) else: return "老铁,这个真转不了" myint = MyInt() # myint(5) => 5 # myint(3.14) => 3 res = myint(True) print(res) res = myint(100) print(res) res = myint(3333.14) print(res, type(res)) # 3 # bool int float "12312312323" # int(3.14) => 3 print(int(3.14)) # 3 print(int(-3.14)) # -3 print("<===>") print(myint(3.14)) print(myint(-0.2)) print("<===>") print(int("0000000000000000000000000000000000000000001230000000")) print(int("00000000000000000000000000000000000000000"),"1111222333") print(int("+000000000000000000000000000000000000000000123")) print(int("-000000000000000000000000000000000000000000123")) print(int("000000000000000000000000000000000000000000123")) print("<==111=>") print(myint("+000000000234")) print(myint("000000000000000000000000000000000000000000123")) print(myint("456899200")) print(myint("3.143434")) print(myint(+-++-+-+-+-+-+-+-+-+-+-++++++++-----234234),"<====>") print(int(+-++-+-+-+-+-+-+-+-+-+-++++++++-----234234),"<====>") """ exec("a = 3") print(a) eval("4") """ # print(math.floor(0.14)) # 0 # print(math.floor(3.14)) # 3 # print(math.ceil(-3.14)) # -3
魔术方法:__bool__
__bool__简要介绍
1.触发时机:使用bool(对象)的时候自动触发
2.功能:强转对象
3.参数:一个self接受当前对象
4.返回值:必须是布尔类型
class MyClass(): def __bool__(self): return False obj = MyClass() res = bool(obj) print(res)
类似的还有如下等等(了解):
__complex__(self) 被complex强转对象时调用
__int__(self) 被int强转对象时调用
__float__(self) 被float强转对象时调用
...
...
魔术方法:__add__,__radd__
__add__简要介绍
1.触发时机:使用对象进行运算相加的时候自动触发
2.功能:对象运算
3.参数:二个对象参数
4.返回值:运算后的值
5.注意点:
对象在加号+的左侧时,自动触发__add__方法
对象在加号+的右侧时,自动触发__radd__方法
加号左侧和右侧都是对象时,先触发__add__方法,再触发__radd__方法
class MyClass1(): def __init__(self,num): self.num = num # 对象在加号+的左侧时,自动触发 def __add__(self,other): # print(self) # print(other) return self.num + other # return 10 + 7 = 17 # 对象在加号+的右侧时,自动触发 def __radd__(self,other): # print(self) # print(other) return self.num * 2 + other # 第一种 a = MyClass1(10) res = a + 7 print(res) # 第二种 b = MyClass1(5) res = 20 + b print(res) # 第三种 print("<============>") res = a+b print(res) """ 第一次触发魔术方法, a+ =>触发__add__方法 self => a other => b self.num + other => a.num+ b => 10 + b res = 10 + b 第二次触发魔术方法 __radd__ self => b other=> 10 self.num * 2 + other => b.num*2 + other => 5 * 2 + 10 => 20 res = 20 """
类似的还有如下等等(了解):
__sub__(self, other) 定义减法的行为:-
__mul__(self, other) 定义乘法的行为:*
__truediv__(self, other) 定义真除法的行为:/
...
...
魔术方法:__len__
__len__简要介绍
1.触发时机:使用len(对象)的时候自动触发
2.功能:用于检测对象中或者类中成员的个数
3.参数:一个self接受当前对象
4.返回值:必须返回整型
class MyClass(): pty1 = 1 pty2 = 2 __pty3 = 3 pyt3 =10 pty100 = 90 def func1(): pass def __func2(): pass def __func3(): pass def __len__(self): lst = [] dic = MyClass.__dict__ # 方法一 # print(MyClass.__dict__) # 获取类当中的所有成员 # print(object.__dict__) # 获取对象中的所有成员 dic = MyClass.__dict__ # 遍历类中所有成员 for i in dic: # 遍历类中所有成员 if not(i.startswith("__") and i.endswith("__")): # 如果开头和结尾都不是以双下划线结尾 lst.append(i) # 将符合条件的成员添加到列表中 return len(lst) # 方法二 lst = [i for i in dic if not(i.startswith("__") and i.endswith("__"))] return len(lst)
与类相关的魔术属性
__dict__ 获取对象或类的内部成员结构
__doc__ 获取对象或类的内部文档
__name__ 获取类名函数名
__class__ 获取当前对象所属的类
__bases__ 获取一个类直接继承的所有父类,返回元组
class Man(): pass class Woman(): pass class Children(Man,Woman): """ 功能: 描述小孩天生的属性 成员属性:eye , skin 成员方法:skylight , moonread , __makebaby """ eye = "万花筒血轮眼" skin = "白色" def skylight(self): print("宇智波家族的小孩,天生能够发动天照技能") def moonread(self,func): # func = func111 print("宇智波家族的小孩,能够发动月亮的光照消灭你~") res = func.__name__ print(res,type(res)) def __makebaby(self): print("这一手招数,只能我自己用") # __dict__ 获取对象或类的内部成员结构 obj = Children() print(obj.__dict__) print(Children.__dict__) # __doc__ 获取对象或类的内部文档 print(obj.__doc__) print(Children.__doc__) # __name__ 获取类名函数名 def func111(): print("我是func111方法") # 获取函数名 obj.moonread(func111) # 获取类名 obj.moonread(Man) # __class__ 获取当前对象所属的类 print(obj.__class__) # __bases__ 获取一个类直接继承的所有父类,返回元组 print(Children.__bases__)