• 31、反射与内置方法、元类


    一、反射

    1.1、什么是反射

      动态语言:未指定数据类型,执行时设定类型

      静态语言:指定数据类型,定义时设定类型

      python是一种动态语言,在程序运行过程中,可以“动态”’的(执行前)获取类型信息

    1.2、为什么需要反射

      提前知道对象的属性,判断己方是否拥有,避免报错

    1.3、怎么使用反射

      四种判断字符串属性的方法:

      hasattr():判断字符串是否哟属性
      getattr()得到字符串的属性

      setattr()更改字符串的属性

      delattr()删除字符串的属性

    class People:
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        def say(self):
            print('<%s:%s>' %(self.name,self.age))
    
    obj=People('辣白菜同学',18)
    
    # 实现反射机制的步骤
    四个内置函数的使用:通过字符串来操作属性值
    1、hasattr()                                 #判断字符串有无属性,相当于obj.name
    print(hasattr(obj,'name'))
    print(hasattr(obj,'x'))
    
    2、getattr()                                 #得到字符串的属性
    print(getattr(obj,'name'))
    
    3、setattr()                                      #更改字符串的属性
    setattr(obj,'name','EGON') # obj.name='EGON'
    print(obj.name)
    
    4、delattr()                                      #删除字符串的属性
    delattr(obj,'name') # del obj.name
    print(obj.__dict__)
    
    
    res1=getattr(obj,'say') # obj.say
    res2=getattr(People,'say') # People.say
    print(res1)
    print(res2)                        

    二、内置方法

    2.1、什么是内置方法

      定义在类的内部,以__开头,并且以__结尾

      在某种特定条件下会自动触发执行

    2.2、为什么要内置方法

      为了定制化:类或者对象

    2.3、怎么使用内置方法

    2.3.1、__str__:在打印对象的时候自动触发,将返回值(必须是字符串)当做本次打印的输出结果

    class People:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def __str__(self):
            # print('运行了...')
            return "<%s:%s>" %(self.name,self.age)
    
    
    obj = People('辣白菜同学', 18)
    
    # print(obj.__str__())
    print(obj)  # <'辣白菜同学':18>
    
    # obj1=int(10)
    # print(obj1)

    2.3.2、__del__:在清理对象的时候(对象运行结束后)自动触发,会先执行该方法

    class People:
        def __init__(self, name, age):
            self.name = name
            self.age = age
            self.x = open('a.txt',mode='w')
            # self.x = 占据的是操作系统资源
    
        def __del__(self):
            # print('run...')
            # 发起系统调用,告诉操作系统回收相关的系统资源
            self.x.close()
    
    obj = People('辣白菜同学', 18)
    # del obj # obj.__del__()
    print('============>')

    三、元类

    3.1、什么是元类

      源于一句话:python中一切皆对象

      元类就是实例化产生的类

      即  元类====》实例化====》类====》实例化====》对象

      默认class产生的类都是基于type元类产生的类,对于元类来讲,类就是对象

    3.2、class关键字创建类的步骤

    3.2.1、类的三大特征

      1.类名

      2.类的基类

      3.执行类体代码拿到类的空间名称

    People=type(class_name,class_bases,class_dic)

    3.2.2、调用元类

    3.3、如何来自定义元类来控制类的产生

      调用元类发生的三件事

      1.先建一个空对象,调用类内的__new__方法

      2.调用类内的__init__方法,完成初始化对象的操作

      3.返回初始化号的对象

    注:只要是调用类,就会调用类内的__init__以及__new__

    class Mymeta(type): # 只有继承了type类的类才是元类
        #            空对象,"People",(),{...}
        def __init__(self,x,y,z):
            print('run22222222222....')
            print(self)
            # print(x)
            # print(y)
            # print(z)
            # print(y)
            # if not x.istitle():
            #     raise NameError('类名的首字母必须大写啊!!!')
    
        #          当前所在的类,调用类时所传入的参数
        def __new__(cls, *args, **kwargs):
            # 造Mymeta的对象
            print('run1111111111.....')
            # print(cls,args,kwargs)
            # return super().__new__(cls,*args, **kwargs)
            return type.__new__(cls,*args, **kwargs)

    3.4、__call__:如果想要让一个对象可以加上括号()调用,需要在对象的类内加一个方法__call__

      该例题中:对象为:====》类内的__call

           类()为====》自定义元素内的____call__

           自定义元素为====》内置元素__call__

    class Foo:
        def __init__(self,x,y):      
            self.x=x
            self.y=y
    
        #            obj,1,2,3,a=4,b=5,c=6
        def __call__(self,*args,**kwargs):            
            print('===>',args,kwargs)
            return 123
    
    obj=Foo(111,222)
    # print(obj) # obj.__str__
    res=obj(1,2,3,a=4,b=5,c=6) # res=obj.__call__()
    print(res)

    3.5、从自定义元素控制类的调用====》类的对象的产生

    class Mymeta(type): # 只有继承了type类的类才是元类
        def __call__(self, *args, **kwargs):
            # 1、Mymeta.__call__函数内会先调用People内的__new__
            people_obj=self.__new__(self)
            # 2、Mymeta.__call__函数内会调用People内的__init__
            self.__init__(people_obj,*args, **kwargs)
    
            # print('people对象的属性:',people_obj.__dict__)
            people_obj.__dict__['xxxxx']=11111
            # 3、Mymeta.__call__函数内会返回一个初始化好的对象
            return people_obj
    
    # 类的产生
    # People=Mymeta()=》type.__call__=>干了3件事
    # 1、type.__call__函数内会先调用Mymeta内的__new__
    # 2、type.__call__函数内会调用Mymeta内的__init__
    # 3、type.__call__函数内会返回一个初始化好的对象
    
    class People(metaclass=Mymeta):
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        def say(self):
            print('%s:%s' %(self.name,self.name))
    
        def __new__(cls, *args, **kwargs):
            # 产生真正的对象
            return object.__new__(cls)
    
    # 类的调用
    # obj=People('egon',18) =》Mymeta.__call__=》干了3件事
    # 1、Mymeta.__call__函数内会先调用People内的__new__
    # 2、Mymeta.__call__函数内会调用People内的__init__
    # 3、Mymeta.__call__函数内会返回一个初始化好的对象
    
    obj1=People('egon',18)
    obj2=People('egon',18)
    # print(obj)
    print(obj1.__dict__)
    print(obj2.__dict__)

    四、属性的查找

      从对象出发的属性查找原则:对象====》类====》父类====》objck          父类不是元类

      从类出发的属性查找原则:类====》父类====》objck====》元类====》type

      

    class Mymeta(type):
        n=444
    
        def __call__(self, *args, **kwargs): #self=<class '__main__.StanfordTeacher'>
            obj=self.__new__(self) # StanfordTeacher.__new__
            # obj=object.__new__(self)
            print(self.__new__ is object.__new__) #True
            self.__init__(obj,*args,**kwargs)
            return obj
    
    class Bar(object):
        # n=333
    
        # def __new__(cls, *args, **kwargs):
        #     print('Bar.__new__')
        pass
    
    class Foo(Bar):
        # n=222
    
        # def __new__(cls, *args, **kwargs):
        #     print('Foo.__new__')
        pass
    
    class StanfordTeacher(Foo,metaclass=Mymeta):
        # n=111
    
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
    
    obj=StanfordTeacher('lili',18)
    print(obj.__dict__)
    # print(obj.n)                 #从对象出发
    # print(StanfordTeacher.n)         #从类出发

      

  • 相关阅读:
    LINQ学习(1)
    [转]键盘上的标点符号的中英文名称对照表
    微信Android ANR原理解析及解决方案
    IOS错误日志抓取和分析
    蚂蚁金服测开面试题--转账功能
    MySQL CONV()函数
    分页功能
    在alert里面加入一个页面,子页面传值父页面
    com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; che
    缘起 网络编程
  • 原文地址:https://www.cnblogs.com/jingpeng/p/12709101.html
Copyright © 2020-2023  润新知