1.反射
# ### 反射(针对于类对象 模块) '''概念:通过字符串去操作类对象或者模块当中的成员(属性方法)''' 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__)) def __makebaby(self): print("这一手招数,只能我自己用") obj = Children() #(1) 反射类对象中的成员 # hasattr() 检测对象/类是否有指定的成员 #对象 res = hasattr(obj,"eye") print(res) #True #类 res = hasattr(Children,"skylight") #True res = hasattr(Children,"__makebaby") #False print(res) # getattr() 获取对象/类成员的值 #对象 func = getattr(obj,"skylight") func = getattr(obj,"__makebaby") #报错 func() # =>skylight() 通过对象反射出来的方法是绑定方法 #类 func = getattr(Children,"skylight") func(1) #通过类反射出来的是一个普通方法 #当类对象中的成员不存在时,可以设置默认值(第三个参数是默认参数) func = getattr(obj,"moonread123","对不起,该成员不存在") print(func) #综合案例 ''' strvar = input("请输入你要调用的方法") if hasattr(obj,strvar): #判断obj对象是否有这个属性 func = getattr(obj,strvar) #获取对象的这个属性 func() ''' #setattr() 设置对象/类成员的值 #对象 setattr(obj,"eye","白眼") print(obj.eye) #类 setattr(Children,"tcut",lambda : print("小孩一下生就能使用雷切")) Children.tcut() #obj.tcut() #tcut是一个无参普通方法,只能类调用 #delattr() 删除对象/类成员的值 #对象 delattr(obj,"eye") print(obj.eye) #类 delattr(Children,'eye') print(Children.eye) #(2)反射模块中的成员 '''sys.modules返回一个系统的字典,加载系统模块展现出来''' import sys print(sys.modules) #获取本模块的对象 print(sys.modules["__main__"]) selfmodule = sys.modules["__main__"] def func1(): print("我是func1方法") def func2(): print("我是func2方法") def func3(): print("我是func3方法") #综合案例 while True: strvar = input("请输入你要反射的方法") if hasattr(selfmodule,strvar) func = getattr(selfmodule,strvar) func() elif strvar.upper() == "Q": break else: print("没有这个方法")
2.装饰器
# ### 装饰器 ''' 装饰器:为原函数扩展新功能,用新功能去替代旧功能 作用:在不改变原有代码的基础上,实现功能上的扩展 符号:@(语法糖) ''' # 1.装饰器的基本使用 def outer(f):# f = func def inner(): print("测试前") f() print("测试后") return inner def func(): print("我叫高富帅") func = outer(func) func() #func() = inner() #2. @符号的使用 ''' @符号使用: (1)可以自动把@符号下面的函数当成参数传递给装饰器 (2)把新函数进行返回,让新函数去替换旧函数,以实现功能的扩展 # func = inner <==> func() = inner() ''' def outer(f): #f = func def inner(): print("测试前") f() #真正执行函数的调用 =func print("测试后") return inner @outer #先调用outer,并把下面函数名传给参数f,即func = outer(func) def func(): #被调用的真正函数 print("我叫高富帅") func() #func() = inner() #3.装饰器的嵌套 def outer1(f): def inner(): print("测试前1") f() print("测试后2") return inner def outer2(f): def inner(): print("测试前3") f() print("测试后4") return inner @outer2 #3 1 5 2 4 @outer1 #调用outer1并把func传给f 1 5 2 def func(): print("我是白富美5") func() #31524 ''' 解析 1.调用outer1并把func传给f,返回inner,执行func()想当于执行inner() outer1的打印顺序为 1 5 2 2.然后再调用outer2把func传给f,返回inner,执行func()想当于执行inner() outer2的打印顺序为3 1 5 2 4 ''' #4.用装饰器修饰带有参数的函数 '''拓展的新功能和原函数的功能,在参数和返回值上,要保持一致性''' def outer(f): def inner(who,where): print("测试前") f(who,where) print("测试后") return inner @outer # func = outer(func) def func(who,where): print("{who}在{where}吃饭".format(who=who,where=where)) func("小白","餐厅") #5.用装饰器修饰带有参数返回值的函数 def outer(f): def inner(*args,**kwargs): # 函数的定义处, *号的打包操作 print("测试前") res = f(*args,**kwargs) # 函数的调用处,*号解包操作 print("测试后") return res return inner @outer #func = outer(func) def func(*args,**kwargs): dic = {"wz":"王振","xb":"小白","ww":"伟伟"} lst = [] strvar = "" #遍历玩耍的地点 for i in args: print("玩耍的地点",i) #print(args) #print(kwargs) ''' 正常写法 for k,v in kwargs.items(): if k in dic: strvar = dic[k] + "留下" + v + "黄金" lst.append(strvar) return lst ''' #推导式 return [dic[k] + "留下" + v + "黄金" for k,v in kwargs.items() if k in dic] #谁留下多少黄金 res = func("电影院",'水里',wz="18斤",xb="18吨",ww="18克",zzz = "19k") print(res) #6. 用装饰器来拓展原函数 class outer(): def __call__(self,func): #第二步 #触发call方法,把func传给func return self.outer1(func) #第三步 #调用outer1并把func传给func def outer1(self,func): #第四步 def inner(): #第七步 #执行第六步相当于执行这一步func()=inner() print("测试前1") #第八步 打印 func() #第九步 #真正函数调用打印测试进行时 print("测试后2") #第十二步 return inner #第五步 #func = inner def outer2(func): def inner(): print("测试前3") func() #真正函数调用打印测试进行时 print("测试后4") return inner #方法一 ''' @outer.outer2 outer(func).outer2 def func(): print("测试进行时...") func() ''' #方法二 ''' @outer() => @obj<=>对象 => obj(func) <=>把对象当成函数进行使用了,自动触发__call__魔术方法 把新函数inner返回了 => @发动第二个既能,将新函数去替换旧函数,func = inner func() = inner() def func(): print("测试进行时...") func() ''' @outer() #第一步 #outer() = > obj对象,然后@obj => func = obj(func),把obj对象当做函数调用会自动触发call方法 def func(): #第十步 执行第九步 就相当于执行真正的函数调用 print("测试进行时") #第十一步 func() #第六步 func() = inner() #7. 带有参数的函数装饰器 def outer(num): def kuozhan(func): #第二步 #func = func1 def inner1(self): #第五步 调用func1相当于调inner1 print("测试前1")#第六步 res = func(self) #第七步 print("测试后2") #第十步 return res def inner2(self): print("测试前3") res = func(self) print("测试后4") return res if num == 1: return inner1 #第三步 #func1 = inner1 elif num == 2: return inner2 elif num == 3: #把方法变成属性 return "我是男性" return kuozhan class MyClass(): @outer(1)#第一步 outer(1)=>返回kuozhan,@kuozhan=> func1=kuozhan(func1)[@符号第一次发动技能] <=> func2 = newfunc2 [@符号第二次发动技能] def func1(self): #第八步,第七步执行的真正函数是这个 print("试一试") #第九步 @outer(2)#outer(2)=>返回kuozhan ,@kuozhan <==> func2=kuozhan(func2) [@符号第一次发动技能] <=> func2 = newfunc2 [@符号第二次发动技能] def func2(self): print("拼一拼") @outer(3) def func3():# outer(3)=>kuozhan , @kuozhan <=> func3=kuozhan(func3) [@符号第一次发动技能] <=> func3 = "我是男性" print("搏一搏") obj = MyClass() obj.func1() #第四步 obj.func2() #func2() <==> newfunc2() #把方法变成属性 print(obj.func3) #func3=kuozhan(func3) => func3 = "我是男性" #8.带有参数的类装饰器 ''' 如果参数是1,就为当前类添加成员属性和方法 如果参数是2,就把原方法run变成属性 ''' class outer(): ad = "贵族茅房,每小时100元,贵族茅房,欢迎您来,欢迎您再来" def __init__(self,num): self.num = num def __call__(self,cls): #第二步 把MyClass传入 cls接收 if self.num == 1: return self.inner1(cls) #第三步 执行inner1函数 elif self.num == 2: return self.inner2(cls) def money(self): print("茅中贵族,百岁山") #参数为1的情况 def inner1(self,cls): #第四步 cls接收MyClass def inner(): #第七步 #为当前cls这个类,添加属性(为MyClass) cls.ad = outer.ad #第八步 #为当前cls这个类,添加方法(为MyClass) cls.money = outer.money #第九步 return cls() #第十步 #对象obj = cls() return inner # 第五步 返回 MyClass = inner #参数为2的情况 def inner2(self,cls): def inner(): if "run" in cls.__dict__: #调用类中的方法,拿到返回值 res = cls.run() #把返回值重新赋值给run属性,后者覆盖了前者,方法变成了属性 cls.run = res #再把值赋值给MyClass的run属性 return cls() #返回对象 return inner #obj = outer(1) ''' @obj [@符号第一次发动技能] <==>obj(MyClass) 把对象当成函数使用了,触发__call__魔术方法 self.inner1(cls) <==> return inner <==> [@符号第二次发动技能] 将新函数替换旧函数 MyClass = inner obj = MyClass() <==> inner() => cls() => obj对象 情况一 @outer(1) #第一步 @obj => MyClass = obj(MyClass) 对象obj当成函数调用触发call方法 class MyClass(): def run(): return "亢龙有悔" obj = MyClass() #第六步 MyClass() = inner() = cls() print(obj.ad) #第十一步 obj.money() ''' ''' @obj [@符号第一次发动技能] <==> obj(MyClass) 把对象当成函数使用了,触发__call__魔术方法 self.inner2(cls) <==> return inner <==> [@符号第二次发动技能] 将新函数替换旧函数 MyClass = inner obj = MyClass() <==> inner() => cls() => obj对象 ''' #情况二 @outer(2) # outer(2) => obj对象,@obj => MyClass = obj(MyClass),obj(MyClass) 把对象当成函数使用了,触发__call__魔术方法 class MyClass(): def run(): return "亢龙有悔" obj = MyClass() # MyClass() => inner()返回cls() => obj print(obj.run) #亢龙有悔 ''' obj = MyClass()的解释 #第一部分 定义一个类 class Ceshi(): c = 100 obj = Ceshi() print(obj.c) #第二部分,定义两个函数 def func22(): print(111) def func(cls): cls.aabbcc = 200 obj = cls() return obj #第三部分,把类当成参数传递给func,类在func函数中形成了一个独立的副本 obj= func(Ceshi) #第四部分,把这个类做替换,变成函数,那么现在在全局空间的Ceshi已经变成了函数,不再是类 Ceshi = func22 #第五部分,调用局部空间obj,还是可以得到原来类中的成员属性和方法 print(obj.c) print(obj.aabbcc) '''
3.类当中的方法
# ### 面向对象中的方法 ''' 普通方法:可以有参数,或者无参数,当成正常的函数调用 绑定方法:(1)绑定到对象(自动传递参数为对象)(2)绑定到类(自动传递参数为类) 静态方法:无论是对象还是类,都可以调用,默认不用传递任何参数 ''' class Dog(): name = "旺财" #普通方法 def jiao(): print("小狗哇哇哇的叫唤") #绑定方法(对象) def eat(self): print("小狗喜欢吃骨头") #绑定方法(类) 类方法 @classmethod def tail(cls): print(cls) print("小狗看到主人喜欢摇尾巴") #静态方法 @staticmethod def jump(num): print("小狗喜欢接飞盘") obj = Dog() #普通方法(无参方法只能类调用) #obj.jiao() error Dog.jiao() #绑定self方法(一般用对象调用) obj.eat() #推荐 Dog.eat(123) #类调用绑定方法 不推荐 #绑定类方法(classmethod类的专属方法推荐用类调用) '''系统自己把类当成参数进行传递''' Dog.tail() #类调用方法 推荐 obj.tail() #静态方法(staticmethod不会默认传递任何参数,如果有参数,当成普通方法调用自己) obj.jump(1) Dog.jump(2) ### 在类外,为对象添加成员方法,默认皆是静态方法 obj.func = lambda : print(123) obj.func()
4.property装饰器
# ### property ''' property 可以把方法变成属性使用 作用:控制属性的获取 设置 删除操作 变相的增加成员的安全性,可以通过自定义逻辑对成员进行控制 自动触发:要求是同一个名字 获取 @property 设置@属性名.setter 删除@属性名.deleter ''' #方法一 class MyClass(): def __init__(self,name): self.name = name @property def username(self): return self.name #pass @username.setter def username(self,val): print(2131231) val = "朴仁猛" self.name = val @username.deleter def username(self): #如果发现有删除行为,可以在这个方法中拒绝删除 #pass del self.name obj = MyClass("小芳") #获取属性(自动触发获取方法@property) #print(obj.username())#TypeError: 'str' object is not callable print(obj.username) #把方法当做属性 #设置属性(自动触发设置方法)val形参自动接收设置的值 obj.username = "朴仁猛" print(obj.username) #删除属性 del obj.username #print(obj.username) error #方法二 class MyClass(): def __init__(self,name): self.name = name #获取 def get_username(self): return self.name #设置 def set_username(self,val): # val = "朴仁猛" self.name = val #删除 def del_username(self): #如果发现有删除行为,可以在这个方法中拒绝删除 del self.name #顺序必须按照 获取 ->设置 ->删除的参数进行传递 username = property(get_username,set_username,del_username) obj = MyClass("朴飘乐") #获取 print(obj.username) #设置 obj.username = "朴一辈" print(obj.username) #删除 del obj.username print(obj.username) #error 被删掉了
总结:
今天主要讲了反射 装饰器,类当中的方法普通方法,类方法,静态方法,property装饰 反射就是通过字符串去操作对象或者模块中的成员(属性或者方法) 可以反射类或者对象中的成员 主要有 hasattr 检测类或者对象中是否有该成员 返回True或者False getattr 获取类或者对象中的成员 存在则获取到,不存在则报错,可以设置第三个参数防止报错 setattr 设置类或者对象成员的值 delattr 删除类或者对象成员 装饰器函数 为原函数拓展新功能,用新功能去替代旧功能 作用:在不改变原有代码的基础上,实现功能上的拓展 符号:@符号 @符号的作用 自动把@符号下面的函数当成参数传递给装饰器 把新函数进行返回,让新函数去替换旧函数,以实现功能的拓展 装饰器的嵌套 用装饰器修饰带有参数的函数 用装饰器修饰带有参数返回值的函数 装饰器拓展原函数 带有参数的函数装饰器 带有参数的类装饰器 面向对象中的方法 普通方法:可以有参数,或者无参数,当成正常的函数调用 绑定方法:绑定到对象(自动传递参数为对象)self方法(2)绑定到类(自动传递参数为类)类方法,需要用@classmethod装饰,参数至少为一个cls 静态方法:@staticmethod 无论对象还是类,都可以调用,默认不用传递任何参数 property装饰器 可以把方法变成属性使用 作用控制属性的获取 设置 删除操作 变相的增加成员的安全性,可以通过自定义逻辑对成员进行控制 自动触发的时候,要求是用一个名字 获取 @property 设置 @属性名.setter 删除 @属性名.deleter