反射,装饰器,类当中的方法,property---day24

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

 

posted @ 2020-06-01 21:53  我在路上回头看  阅读(226)  评论(0编辑  收藏  举报