zoukankan      html  css  js  c++  java
  • 面向对象高级B(元类)

    元类

    python一切皆对象,类实际上也是一个一个对象

    类是一个对象,那他一定是由一个类实例化得到,这个类就叫元类

    如何找元类

    class Person:
        def __init__(self, name):
            self.name = name
        def score(self):
    		print('分数是100')
    
    print(type(Person))
    
    #<class 'type'>
    
    #所有类的元类都是type 
    

    常规的class 类名 会把类构造出来,实际上是元类实例化产生类这个对象,

    Person类是对象,一定是由一个类实例化产生的,所以type()产生对象,调用__init__方法,看源码里面需要穿三个参数

    **class底层实现原理是: type(object_or_name, bases, dict), **

    1. object_or_name: 类的名字,是个字符串

    2. bases: 是它的所有父类,基类

    3. 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,), l) # 等同于生成一个Person类,其中具有school属性,对象有name属性,有score方法
    
    
    ### 下面几句可以生成一个Person类,与上面的语句实现相同的功能
    #def __init__(self, name):
        #self.name = name
    #Person = type('Person', (object,), {'school':'
    # oldboy','__init__':__init__})
    
    
    
    

    自定义元类

    来控制类的产生,可以控制类名,可以控制类的继承关系 ,控制类的名称空间

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

    class Mymeta(type):
        def __init__(self, name, bases,dic):
            #练习一:加限制 控制类名必须以sb 开头
            if not name.startswith('sb'):
                raise Exception(’类名没有以sb开头‘)# 如果不是以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')
    
    
    1. 自定义一个元类,控制类产生,类的名称空间必须有name字段才能创建成功,否则失败
    class Mymeta(type):
        def __init__(self, x, y, z):
            for k, v in self.__dict__.items():
                print(k,v)
            # print(self.__dict__)
            if 'name' not in self.__dict__.values() and 'name'not in self.__dict__.keys():
                raise Exception('你的类没有“name”这个字段')
            else:
                print('名称空间已经存在"name"')
    
    1. 自定义一个元类,定义一个类,继承字典,使其具备 点取值和赋值功能,通过元类控制对象的产生,把所有对象的属性都放在attr字典中,属性全部删除

    例如di=Mydict(name='lqz', age=18) di的名称空间中没有name和age属性,但是有attr字典属性,字典包含{'name':'lqz', 'age':18} (待修改)

    class Mymeta(type):
        def __call__(self, name, age):#要有返回值
        	obj = object.__new__(self)
            obj.__dict__['attr'] = {'name':name,'age':age}
    		return obj
    class Person(metaclass=Mymeta):
        def __init__(self,name,age):
            self.name = name
            self.age = age
    p = Person('lje', 18)
    print(p.__dict__)
    print(p.attr['name'])
    
    
    '''
    {'attr': {'name': 'lje', 'age': 18}}
    lje
    '''
    
    
    ##延伸(对类名称空间中的属性单独放到attr字典里,但是该字典依然在类名称空间的字典里)
    class Mymeta(type):
        def __init__(self,name,bases,dic):
            pass
        def __new__(cls, name,bases,dic):#要有返回值
            dic2={'attr':{}}#单独列一个字典,用于盛放类的属性
            for k,v in dic.items():
                if not k.startswith('__'):#如果key值以__开头,就把大拿出来放到dic2中
                    dic2['attr'][k]=v
            print('-------',dic2)
            return type.__new__(cls,name,bases,dic2)#把dic2当成名称空间返回,但是类的名称空间还是原来的dic,只不过属性放到attr小字典里了
    class Person(metaclass=Mymeta);#Person=Mymeta(name,bases,dic) 调用type的__call__,内部调用了Mymeta.__new__,又调用了Mymeta的__init__
    	school = 'Tshinghua'
        age = 10
        def __init__(self, name, age):
            self.name = name
            self.age = age
    print(Person.__dict__)
    print(Person.attr['school'])
    
    '''
    ------- {'attr': {'school': 'oldboy', 'age': 10}}
    {'attr': {'school': 'oldboy', 'age': 10}, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
    Tshinghua
    '''
    
    
  • 相关阅读:
    645. 错误的集合『简单』
    1078. Bigram 分词『简单』
    1018. 可被 5 整除的二进制前缀『简单』
    1010. 总持续时间可被 60 整除的歌曲『简单』
    1417. 重新格式化字符串『简单』
    1413. 逐步求和得到正数的最小值『简单』
    1394. 找出数组中的幸运数『简单』
    1374. 生成每种字符都是奇数个的字符串『简单』
    1365. 有多少小于当前数字的数字『简单』
    1360. 日期之间隔几天『简单』
  • 原文地址:https://www.cnblogs.com/michealjy/p/11456351.html
Copyright © 2011-2022 走看看