魔术方法和反射
1. __init__构造方法: 在实例化对象,初始化的时候触发,功能是可以为对象添加成员,参数至少有一个self,无返回值
class Travel(): def __init__(self,didian): self.didian = didian # 实例化 obj = Travel("海南") print(obj.didian) # 海南 # 可以通过一个类实例化不同的对象 class Travel(): def __init__(self,didian,time): self.didian = didian self.time = time def shan(self): print("山:{}去{}玩".format(self.time,self.didian)) def shui(self): print("水:{}去{}玩".format(self.time, self.didian)) def hai(self): print("海:{}去{}玩".format(self.time,self.didian)) # 第一个对象: wudangshan = Travel("湖北","5月") wudangshan.shan() # 山:5月去湖北玩 # 第二个对象: xihu = Travel("杭州","6月") xihu.shui() # 水:6月去杭州玩 # 第三个对象 dadonghai = Travel("三亚","7月") dadonghai.hai() # 海:7月去三亚玩
2. __new__魔术方法: 触发时机: 实例化生成对象的时候触发,时间比__init__早
功能: 控制对象的创建过程
参数: 至少一个cls接收当前的类,其实的参数根据情况而定
返回值: 通常返回对象或者None
2. 1 __new__ 返回值的三种情况:
class Tree(object): def __new__(cls): obj = object.__new__(cls) return obj # (1) 借助父类.方法(),返回本类自己的对象 obj_tree = Tree() print(obj_tree) # <__main__.Tree object at 0x000002C288074208> class Tree(object): def __new__(cls): obj = object.__new__(cls) return None # (2) 不返回任何对象 obj_tree = Tree() print(obj_tree) # None class Grass(): name = "我是小草" obj_grass = Grass() class Tree(object): def __new__(cls): obj = object.__new__(cls) return obj_grass # (3) 返回别的类的对象 obj_tree = Tree() print(obj_tree.name) # 我是小草
2.2 __new__的使用方式:
class Tree(): def __new__(cls): print("第一个") def __init__(self): print("第二个") obj = Tree() # 第一个 证明__new__触发时间早于__init__,先创建对象,再初始化对象 # new方法的参数要和init方法的参数保持一致,否则程序报错 class Tree(): def __new__(cls,name): print("第一个") return object.__new__(cls) def __init__(self,name): self.name = name obj1 = Tree("bob") print(obj1.name) # 优化:利用收集参数,无需再考虑new方法的参数是否保持了一致,也为后续类再添加参数提供了方便 class Tree(): def __new__(cls, *args, **kwargs): print("第一个") return object.__new__(cls) def __init__(self,name,age): self.name = name self.age = age obj666 = Tree("bob",18) print(obj666.name,obj666.age) # 注意点: 如果new方法返回的不是自身的对象,那么init方法不会被触发,init里面的代码也不会被执行 class Tree(): def __new__(cls, *args, **kwargs): print("第一个") return obj666 def __init__(self,name): self.name = name print("第二个") obj_this = Tree("bob") print(obj_this.name) # 第一个 # bob
3. __del__魔术方法: 也叫析构方法
触发时机:当对象被内存回收的时候自动触发(1,页面执行完毕,回收所有变量 2,所有对象被del的时候)
功能: 对象使用完毕后资源回收
参数: 一个self接收对象
返回值: 无
3.1 触发情况:
class Tree(): def __init__(self,name): self.name = name def __del__(self): print("资源被回收") # 情况一: 页面执行完毕,系统自动调用__del__方法 obj = Tree("大树") print(obj.name) # 大树 # 资源被回收 # 情况二: 所有对象被删除,如果有两个或以上的变量指向这个类的对象,必须是将这些变量都删除的情况下才会自动触发__del__方法 print("开始") obj1 = Tree("大树") obj2 = obj1 del obj1 print("结束") # 开始 # 结束 # 资源被回收 print("开始") obj1 = Tree("大树") obj2 = obj1 del obj1 del obj2 print("结束") # 开始 # 资源被回收 # 结束
3.2 用面向对象模拟文件操作小案例
import os class ReadFile(): # 判断文件是否存在 def __new__(cls,filepath): if os.path.exists(filepath): return object.__new__(cls) else: print("此文件不存在") # 打开文件 def __init__(self,filepath): self.f1 = open(filepath,mode="r+",encoding="utf-8") # 读取文件 def readcontent(self): content = self.f1.read() return content # 关闭文件 def __del__(self): self.f1.close() obj = ReadFile(r"D:\python学习\python代码练习\每天代码练习\111.txt") res = obj.readcontent() print(res)
4. __str__魔术方法:
触发时机: 使用print(对象)或者str(对象)的时候
功能: 查看对象
参数: 一个self接收对象
返回值: 必须返回字符串类型
class Product(): def __init__(self,name,time): self.name = name self.time = time def info(self): return "{}经过{}天,可以制成成品".format(self.name,self.time) def __str__(self): return self.info() obj = Product("橡胶",10) print(obj) # 橡胶经过10天,可以制成成品 print(str(obj)) # 橡胶经过10天,可以制成成品
5. __repr__方法:
触发时间: 使用repr(对象)的时候
功能: 查看对象,与__str__方法类似
参数: 一个self接收当前对象
返回值:必须返回字符串类型
在系统底层,如果定义了repr,自动默认将repr赋值给str,即__repr__ = __str__
class Tree(): def __init__(self,name,color): self.name = name self.color = color def __repr__(self): return "{}是{}的".format(self.name,self.color) obj = Tree("大树","绿色") print(repr(obj)) # 大树是绿色的 print(obj) # 大树是绿色的 print(str(obj)) # 大树是绿色的 # repr可以赋值给str,但是str并不能赋值给repr
6. __call__方法:
触发时机:把对象当做函数调用的时候触发
功能: 模拟函数化操作
参数: 至少一个self参数
返回值: 根据需求而定
class Cai(): def __call__(self, *args, **kwargs): self.one() self.two() self.three() self.four() def one(self): print("先放一点油") def two(self): print("把菜倒进锅里") def three(self): print("放一点盐") def four(self): print("盛出来,装盘") obj = Cai() obj() """ 先放一点油 把菜倒进锅里 放一点盐 盛出来,装盘 """
6.2 用__call__方法模拟int函数
import math class Myint(): def calc(self,num,sign=1): strvar = num.lstrip("0") if strvar == "": return 0 return eval(strvar)*sign def __call__(self,num): # 如果是整型 if isinstance(num,int): return num # 如果是bool值 elif isinstance(num,bool): if num == True: return 1 else: return 0 # 如果是浮点型 elif isinstance(num,float): 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.startswith("+") or num.startswith("-")) 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 "这个字符串不能转为整型" obj = Myint() a = +---19 res1 = obj(a) res2 = int(a) print(res1, res2)
7. __bool__, __complex__, __float__, __int__
触发时机:使用bool(对象)的时候自动触发
功能:强转对象
参数: 一个self接收当前对象
返回值: 必须是bool类型
__complex__(self) __float__(self) __int__(self)使用方法与功能跟__bool__(self)一样
class Tree(): def __bool__(self): return True obj = Tree() print(bool(obj)) # True
8. __add__方法:
触发时机: 使用对象进行运算相加的时候自动触发
功能: 对象运算
参数: 两个对象参数
返回值: 运算后的值
反向加法是__radd__
__sub__是定义减法运算的,用法与__add__一样
__mul__是定义乘法运算的,用法与__add__一样
__truediv__是定义真除法运算的,用法与__add__一样...
class YunSuan(): 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 = YunSuan(7) print(a+5) # 12 b = YunSuan(3) print(5+b) # 13 print(a+b) # 17 """ 第一步: a+b 先触发add方法 num = 7 other= b 第二步: 7+b 触发radd方法 num=3 other=7 """
9. __len__方法:
触发时机: 使用len(对象)的时候自动触发
功能: 用于计算类中或者对象中的成员个数
参数: 一个self接收对象
返回值: 必须返回整型
类似的还有如下等等(了解):
__iter__(self) 定义迭代容器中的元素的行为
__reversed__(self) 定义当被 reversed() 调用时的行为
__contains__(self, item) 定义当使用成员测试运算符(in 或 not in)时的行为
class Tree(): a = 1 b =2 def jisuan(self): print("计算这个类中自定义成员的个数") def __len__(self): lst = [i for i in Tree.__dict__ if not (i.startswith("__") and i.endswith("__"))] return len(lst) obj = Tree() print(len(obj)) # 3
10. 与类相关的魔术属性
__dict__ , __doc__, __name__ , __class__, __bases__
class Job(): def __init__(self,salary): self.salary = salary class Money(Job): """ 成员属性:salary 成员方法:play() learn() bank() 功能: 计算工资的分配 """ def play(self): print("工资{}的三分之一用于玩:{}".format(self.salary,self.salary*0.3)) def learn(self): print("工资{}的三分之一用于学习:{}".format(self.salary,self.salary*0.3)) def bank(self): print("工资{}的三分之一用于存储:{}".format(self.salary, self.salary * 0.3)) obj1 = Money(20000) # (1) __dict__ : 获取类或者兑现中的内部成员结构 print(Money.__dict__) # {'__module__': '__main__', '__doc__': '\n # 成员属性:salary\n 成员方法:play() learn() bank()\n # 功能: 计算工资的分配\n ', # 'play': <function Money.play at 0x0000024E7EABC510>, # 'learn': <function Money.learn at 0x0000024E7EABC598>, # 'bank': <function Money.bank at 0x0000024E7EABC620>} print(obj1.__dict__) # {'salary': 20000} # (2) __doc__ 获取类或者对象内部的文档 print(Money.__doc__) print(obj1.__doc__) """ 成员属性:salary 成员方法:play() learn() bank() 功能: 计算工资的分配 """ # (3) __name__ 获取类名函数名 print(Money.__name__) # Money # (4) __class__ 获取当前对象所属的类 print(obj1.__class__) # <class '__main__.Money'> # (5) __bases__ 获取一个类直接继承的所有父类,返回元祖 print(Money.__bases__) # (<class '__main__.Job'>,)
11. 反射:针对于类对象或者模块,用字符串去操作类对象或者模块中的成员
11.1 类或者成员中的反射应用:
class Tree(): name = "大树" __age = 18 def grow(self): print("小树长成大树") def forest(self): print("树聚集成森林") obj = Tree() # (1) hasattr(): 检查类或者对象是否具有指定的成员 res = hasattr(Tree,"name") print(res) # True res = hasattr(obj,"name") print(res) # True res = hasattr(obj,"__age") print(res) # False 私有成员时检测不到的 res = hasattr(Tree,"grow") print(res) # True res = hasattr(obj,"grow11") print(res) # False # (2) getattr(): 获取类或者对象中的值 func1 = getattr(Tree,"grow") func1("self") # 小树长成大树 通过类获取的是普通方法,所以调用的时候需任意给一个参数 res = getattr(Tree,"name") print(res) # 大树 # 当获取的成员不存在时,可以设置默认值 func1 = getattr(obj,"grow11","这个成员不存在") print(func1) # 这个成员不存在 # 小案例 strvar = input("请输入您要使用的方法:") if hasattr(obj,strvar): func = getattr(obj,strvar) func() # (3) setattr(): 设置对象或成员的值 setattr(obj,"name","巨树人") print(obj.name) # 巨树人 setattr(Tree,"green",lambda : print("成片的绿叶子")) Tree.green() # 成片的绿叶子 # (4) delattr(): 删除类或者成员中的值 delattr(obj,"name") delattr(Tree,"name") print(obj.name) # 报错 delattr(Tree,"grow") obj.grow() # 报错
11.2 模块中反射的应用:
import sys selfmodules = sys.modules["__main__"] # 获取系统中本模块所包含的对象 def one(): print("第一个") def two(): print("第二个") def three(): print("第三个") while True: strvar = input("请输入您要反射的模块名称:") if hasattr(selfmodules,strvar): func = getattr(selfmodules,strvar) func() elif strvar.upper() == "Q": break else: print("这个不存在")