• 反射,装饰器,类当中的方法,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
  • 相关阅读:
    [NOI2018]归程 kruskal重构树
    [NOIP2017]逛公园 最短路图 拓扑序DP
    [bzoj4398] 福慧双修 最短路 二进制分组
    【HDOJ】【4405】Aeroplane chess飞行棋
    【ZOJ】【3329】One Person Game
    【POJ】【2096】Collecting Bugs
    【BZOJ】【3093】【FDU校赛2012】A Famous Game
    【BZOJ】【3143】【HNOI2013】游走
    【UVA】【10828】随机程序
    【UVA】【11762】Race to 1(得到1)
  • 原文地址:https://www.cnblogs.com/weiweivip666/p/13027714.html
Copyright © 2020-2023  润新知