• 2019.9.3学习内容及笔记


    小结

    元类

    首先明确python中一切皆对象,那么 类实际上也是对象
    例如:现有一个Person类, 现在我们说一切皆对象,类也是对象,那么这个Person也一定是由一个类实例化得到的,这个类,就叫做元类

    **type是内置的一个元类,所有的类都是由type实例化的得到

    总结:能产生类的类,叫元类

    class Person:
        def __init__(self,name):
            self.name=name
        def score(self):
            print('分数是100')
    p=Person('nick')
    #p.score()#分数是100
    
    a=Person #Person是类名
    p1=a('tank') #a实例化产生对象p1
    print(p1.name) #tank
    
    #如何找元类
    #print(type(p))#<class '__main__.Person'>
    
    #type类是产生所有类的元类
    print(type(Person)) #<class 'type'>
    print(type(dict))#<class 'type'>
    print(type(list))#<class 'type'>
    print(type(str))#<class 'type'>
    print(type(object))#<class 'type'>
    print(type(type))#<class 'type'>
    
    

    2 .class底层分析原理

    通过 class 类名: 会把类构造出来
    实际上是:元类实例化产生类 这个对象
    类实例化产生对象,一定是通过: 类名()

    例如:Person 类是由type 实例化产生,传一堆参数
    type() 调用类的 _ _init _ _方法

    #class 类名   会把类构造出来
    #实际上是:元类实例化产生类  这个对象
    #类实例化产生对象,一定是:   类名()
    #Person  类是由type实例化产生,传一堆参数
    #type()  掉用类的__init__方法
    #type()
    
    #type(object_or_name, bases, dict)
    # object_or_name: 类的名字,是个字符串(加引号)
    # bases: 是它所有父类,基类
    # dict: 名称空间,是一个字典
    
    #通过type来直接产生类,不要class关键字
    # dic = {}
    # exec('''
    # school='oldboy'
    # def __init__(self,name):
    #     self.name=name
    # def score(self):
    #     print('分数是100')
    # ''', {}, dic)
    # def __init__(self,name):
    #     self.name=name
    #
    # Person=type('Person',(object,), dic)
    
    #print(Person.__dict__) #exec里面的参数全在字典里(因为exec做了一件事,把里面的参数全部放在了局部名称空间dic里面了,如果在参数前面加gloabe,就会把参数放在{}的全局名称空间里面)
    # 也可以自行添加,在dic字典{}中添加相应的key和value值,如下
    #Person=type('Person',(object,),{'school':'oldboy','__init__':__init__})
    
    #print(Person.__bases__) #(<class 'object'>,)打印父类
    
    # p=Person('nick')
    # print(p.name) #nick
    # print(p.__dict__)#{'name': 'nick'}
    #
    # # class底层原理就是调用type来实例化产生类(对象)
    #
    # class Person:
    #     school='oldboy'
    #     def __init__(self,name):
    #         self.name=name
    #     def score(self):
    #         print('分数是100')
    # a=Person
    # p1=a('nick')
    # print(p1.name)#nick
    
    # exec(), eval()的区别
    # l={}
    # exec('''
    # school='oldboy'
    # def __init__(self,name):
    #     self.name=name
    # def score(self):
    #     print('分数是100')
    # ''', {}, l)
    #print(l): 将exec下的属性全部放到局部名称空间l中
    
    x=1
    x=2
    def test():
        global x
        x =100
        z =200
        m =300
    

    3.通过元类来控制类的产生
    自定制元类:来控制类的产生:可以控制类名,可以控制类的继承,控制类名的名称空间

    type

    自定义元类必须继承type,写一个类继承type, 这种类都叫元类

    #自定义元类;来控制类的产生:可以控制类名,可以控制类的继承父类,控制类的名称空间
    
    # type
    #自定义元类必须继承type,写一个类继承type     这种类都叫元类
    class Mymeta(type):
        #def __init__(self, *args, **kwargs):
        def __init__(self, name, bases,dic):
            #练习一:加限制 控制类名必须以sb开头
            if not name.stratswiths('sb'):
                print(name)
                print(bases)
                print(dic)
                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('nick')
    # class Mymeta(type):
    #     def __init__(cls,name,bases, dic):
    #         print(cls.__dict__['__doc__'])
    #         doc=cls.__dict__['__doc__']
    #         if not doc:
    #             raise Exception('你的类没有加注释')
    # class Person(object, metaclss= 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) #'int' object has no attribute 'name' (前面return值是1,p就是1)
    
    # class Person():
    #     school='oldboy'
    #     def __init__(self,name):
    #         self.name=name
    #     def score(self):
    #         print('分数是100')
    #     def __call__(self, *args, **kwargs):
    #         print('xxx')
    # p=Person('nick') #自动触发init的执行
    ##先触发元类的__call__
    #p() #xxx
    
    
    #__new__
    #objict
    #练习:把对象中的所有属性都设置成私有的
    #分析
    # class Mymeta(type):
    #     def __call__(self, *args, **kwargs):
            #self 是Person这个类
            #print(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) #<__main__.Person object at 0x00000000029BF080>
    
            #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.name) #nick
    
    #把对象所有的属性都变成私有
    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__) #{'_Person__name': 'nick'} 已隐藏
    #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)
    
  • 相关阅读:
    POJ 2672 Tarjan + 缩点 + 拓扑思想
    HDU1269迷宫城堡(裸Tarjan有向图求强连通分量个数)
    Tarjan求有向图强连通详解
    Jedis源代码探索
    多线程下使用Jedis
    Jedis分片连接池
    Jedis使用过程中踩过的那些坑
    jedis提纲
    jedis中的一致性hash算法
    字典:dict.c/dict.h
  • 原文地址:https://www.cnblogs.com/chmily/p/11455664.html
Copyright © 2020-2023  润新知