zoukankan      html  css  js  c++  java
  • 第一阶段:Python开发基础 day29 面向对象之元类以及元类延伸的相关知识

    上节课内容回顾

    # 面试题:这俩有什么区别
    # sorted()
    # l=[1,3]
    # l.sort()
    #
    # len()
    # l.__len__()
    
    # 反射
    
    # setattr() #向对象中设置属性或方法
    # getattr() #获取对象中的属性或方法
    # delattr() #删除对象中的属性或方法
    # hasattr()  #判断对象中是否有该属性或方法(属性或方法用字符串表示# )
    # import os
    # hasattr(os,'path')
    # p=getattr(os,'path1',None)
    # print(p)
    # setattr(对象,key,value)
    # delattr()
    
    
    #内置方法(魔法方法)
    
    # __str__  print 打印的时候,会自动触发该函数的执行
    #点拦截方法   对象加  .  就会触发
    # __setattr__ : 对象加.赋值或修改值会触发
    #__getattr__  : 对象加.获取值,如果取不到,会触发
    #__delattr__  :对象加. 删除值,会触发
    
    
    # dic=dict(name='lqz',age=18)
    # dic.name
    # dic['name']
    
    # class Mydic(dict):
    #     def __setattr__(self, key, value):
    #
    #         # print('xxxx')
    #         self[key]=value
    #     def __getattr__(self, item):
    #         print('yyyy')
    #
    #         a=self[item]
    #         return a
    #
    # di=Mydic(name='lqz',age=18)
    # # print(di['name'])
    #
    # print(di.name)
    # di.sex='male'
    # print(di['sex'])
    
    # class Foo():
    #     def __init__(self,name):
    #         self.name=name
    #
    #     def __setattr__(self, key, value):
    #         # print('xxxx')
    #         #这种方式有问题!出现递归
    #         # setattr(self,key,value)
    #         #第一种方法(名称空间字典):
    #         # self.__dict__[key]=value
    #         #第二种方法(推荐)
    #         super().__setattr__(key,value)
    #         # object.__setattr__(self,key,value)
    #     def __getattr__(self, item):
    #             return '没有值'
    #
    #
    # f=Foo('nick')
    #
    # f.name1='lqz'
    # print(f.name)
    # print(f.name1)
    
    # @auth
    # def tett():
    #     pass
    
    
    #__call__
    # class Foo():
    #     # pass
    #     def __call__(self, *args, **kwargs):
    #
    #         print(kwargs)
    
    # f=Foo()
    # f(a=1,b=2)
    

    一、元类是什么

    #一切皆对象:类实际上一个一个对象
    #Person类也是个对象,那他一定是由一个类实例化得到,这个类,就叫元类
    #type是内置的一个元类,所有的类都是由type实例化得到
    # 产生类的类,叫元类
    class Person:
        def __init__(self,name):
            self.name=name
        def score(self):
            print('分数是100')
    
    p=Person('nick')
    
    # a=Person
    # p1=a('nick')
    # print(p1.name)
    
    #如何找元类?
    # print(type(p))
    #同理:type类是产生所有类的元类
    # print(type(Person))
    print(type(dict))
    print(type(list))
    print(type(str))
    print(type(object))
    
    print(type(type))
    
    type
    

    二、class底层原理分析

    #class 类名   会把类构造出来
    #实际上是:元类实例化产生类  这个对象
    #类实例化产生对象,一定是:   类名()
    #Person  类是由type实例化产生,传一堆参数
    #type()  调用类的__init__方法
    # type()
    #type(object_or_name, bases, dict)
    # object_or_name:类的名字,是个字符串
    #bases:是它的所有父类,基类
    #dict:名称空间,是一个字典
    
    #通过type来直接产生类,不用class关键字了
    l={}
    exec('''
    school='oldboy'
    def __init__(self,name):
        self.name=name
    def score(self):
        print('分数是100')
    ''',{},l)
    def __init__(self,name):
        self.name=name
    
    # Person=type('Person',(object,),{'school':'oldboy','__init__':__init__})
    #
    Person=type('Person',(object,),l)
    
    # print(Person.__dict__)
    print(Person.__bases__)
    # p=Person('nick')
    # print(p.name)
    # print(p.__dict__)
    
    #class 底层就是调用type来实例化产生类(对象)
    
    
    # class Person:
    #     school='oldboy'
    #     def __init__(self,name):
    #         self.name=name
    #     def score(self):
    #         print('分数是100')
    # a=Person
    #
    # p=Person('nick')
    
    #exec()  eval()的区别
    # l={}
    # exec('''
    # school='oldboy'
    # def __init__(self,name):
    #     self.name=name
    # def score(self):
    #     print('分数是100')
    # ''',{},l)
    
    # print(l)
    # g={ 'x':1,'y':2}
    # l={}
    # exec('''
    # global x
    # x=100
    # z=200
    # m=300
    # ''',g,l)
    # print(g)
    # print(l)
    
    # x=1
    # y=2
    # def test():
    #     global x
    #     x = 100
    #     z = 200
    #     m = 300
    

    三、通过元类来控制类的产生

    #自定义元类;来控制类的产生:可以控制类名,可以控制类的继承父类,控制类的名称空间
    
    # type
    #自定义元类必须继承type,写一个类继承type     这种类都叫元类
    #
    # class Mymeta(type):
    #     # def __init__(self,*args,**kwargs):
    #     def __init__(self,name,bases,dic):
    #         # self 就是Person类
    #         # print(name)
    #         # print(bases)
    #         # print(dic)
    #         #练习一:加限制 控制类名必须以sb开头
    #         # if not name.startswith('sb'):
    #         #     raise Exception('类名没有以sb开头')
    #         #练习二:类必须加注释
    #         print(self.__dict__['__doc__'])
    # #metaclass=Mymeta  指定这个类生成的时候,用自己写的Mymeta这个元类
    # class Person(object,metaclass=Mymeta):
    #     '''
    #     注释
    #     '''
    #     school='oldboy'
    #     def __init__(self,name):
    #         self.name=name
    #     def score(self):
    #         print('分数是100')
    
    
    # p=Person()
    
    # class Mymeta(type):
    #     def __init__(self,name,bases,dic):
    #         print(self.__dict__['__doc__'])
    #         doc=self.__dict__['__doc__']
    #         if not doc:
    #             #没有加注释
    #             raise Exception('你的类没有加注释')
    # class Person(object,metaclass=Mymeta):
    #     '''
    #     我加了注释
    #     '''
    #     school='oldboy'
    #     def __init__(self,name):
    #         self.name=name
    #     def score(self):
    #         print('分数是100')
    

    四、通过元类控制类的调用过程

    #__call__
    #控制类的调用过程,实际上在控制:对象的产生
    # class Mymeta(type):
    #     def __call__(self, *args, **kwargs):
    #         # print('xxx')
    #
    #         return 1
    #
    # class Person(object,metaclass=Mymeta):
    #     school='oldboy'
    #     def __init__(self,name):
    #         self.name=name
    #     def score(self):
    #         print('分数是100')
    #
    # p=Person('nick')
    # print(p.name)
    
    
    # class Person():
    #     school='oldboy'
    #     def __init__(self,name):
    #         self.name=name
    #     def score(self):
    #         print('分数是100')
    #     def __call__(self, *args, **kwargs):
    #         print('xxxx')
    #
    # p=Person('nick')   #自动触发init的执行
    # #先触发元类的__call__
    # p()
    
    #__new__
    
    object
    #练习:给我吧对象中的所有属性都设置成私有的
    #分析
    # class Mymeta(type):
    #     def __call__(self, *args, **kwargs):
    #         #self 是Person这个类
    #         # print(args)
    #         # print(kwargs)
    #         # return self(*args)  #这里不行,会递归
    #         # self.__new__(self)
    #         #实例化产生一个Person类的对象,借助__new__来产生,需要把类传过去,才能产生对象
    #         #obj 是Person类的对象,只不过是空的
    #         obj=object.__new__(self)
    #         # obj=self.__new__(self)
    #         #调用__init__方法完成初始化
    #         #类来调用__init__方法,就是个普通函数,有几个参数就穿几个惨
    #         # self.__init__(obj,*args, **kwargs)
    #         #对象来调用__init__方法,对象的绑定方法,会把自身穿过来
    #         obj.__init__(*args, **kwargs)
    #         print(obj)
    #         return obj
    #
    #
    # class Person(object, metaclass=Mymeta):
    #     school = 'oldboy'
    #     def __init__(self, name):
    #         self.name = name
    #     def score(self):
    #         print('分数是100')
    # p = Person(name='nick')
    # print(p)
    # print(p.name)
    
    #把对象所有的属性都变成私有
    class Mymeta(type):
        def __call__(self, *args, **kwargs):
            obj=object.__new__(self)
            obj.__init__(*args, **kwargs)
            # print(obj.__dict__)
            obj.__dict__={ '_%s__%s'%(self.__name__,k):v for k,v in obj.__dict__.items()}
            # print(obj.__dict__)
            return obj
    
    class Person(object, metaclass=Mymeta):
        school = 'oldboy'
        def __init__(self, name):
            self.name = name
        def score(self):
            print('分数是100')
    p = Person(name='nick')
    print(p.__dict__)
    print(p.name)
    # print(p)
    # print(p.name)
    

    五、有了元类之后的属性查找

    #类的属性查找顺序:先从类本身中找--->mro继承关系去父类中找---->去自己定义的元类中找--->type中--->报错
    #对象的属性查找顺序:先从对象自身找--->类中找--->mro继承关系去父类中找--->报错
    
    class Mymeta(type):
        n=444
    
        def __call__(self, *args, **kwargs): #self=<class '__main__.OldboyTeacher'>
            obj=self.__new__(self)
            # print(self.__new__ is object.__new__) #True
            obj.__init__(*args, **kwargs)
            return obj
    
    
    class Bar(object):
        # n=333
        pass
    
        # def __new__(cls, *args, **kwargs):
        #     print('Bar.__new__')
    
    class Foo(Bar):
        # n=222
        pass
    
        # def __new__(cls, *args, **kwargs):
        #     print('Foo.__new__')
    
    class OldboyTeacher(Foo,metaclass=Mymeta):
        # n=111
    
        school='oldboy'
    
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        def say(self):
            print('%s says welcome to the oldboy to learn Python' %self.name)
    
    
        # def __new__(cls, *args, **kwargs):
        #     print('OldboyTeacher.__new__')
    
    
    o=OldboyTeacher('egon',18) #触发OldboyTeacher的类中的__call__方法的执行,进而执行self.__new__开始查找
    print(OldboyTeacher.n)
    # print(o.n)
    
  • 相关阅读:
    Dubbo教程:入门到实战
    阿里面试Java程序员都问些什么?
    Canon MF113W激光打印机双面打印方法
    MacBook Pro App Store无法下载和更新软件解决方案
    收不到Win10正式版预订通知?一个批处理搞定
    创业公司失败的20大原因:没市场需求排第一
    最新版本sublime text3注册码
    Spring MVC 知识点整理
    Nginx子域名配置
    Install Local SQL In Mac OS
  • 原文地址:https://www.cnblogs.com/foreversun92/p/11528938.html
Copyright © 2011-2022 走看看