类的高阶、元类、class底层实现原理

一、元类

​ 在python中一切皆对象,类实际上也是一个对象。既然类是一个对象,那它一定有一个由一个类实例化得到,这个类,就叫做元类。也就是说产生类的类,叫元类。

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

​ 在python中可以通过type()方法查看对象的类

print(type(dict))
print(type(list))
print(type(str))
print(type(object))

# 他们都是type

二、class底层原理分析

​ type(object_or_name, bases, dict)----> 调用type()的__init__方法

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

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

dict:名称空间,是一个字典

class底层就是调用type来实例化产生类(对象)

# 通过type来直接产生类,不用class关键字了
l = {}
exex('''
school = 'old_boy'
def __init__(self, name):
	self.name = name
def score(self):
	print('分数是100')
''', {}, l)  # 属性和方法、全局名称空间、局部名称空间

Person = type('Person', (object,), l)

print(Person.__dict__)
print(Person.__bases__)
p = Person('nick')
print(p.name)
print(p.__dict__)

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

​ 自定义元类:来控制类的产生,可以控制类名,可以控制类的继承父类和控制类的名称空间。

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

练习一:加限制,控制类名必须以sb开头

class Mymeta(type):
    def __init__(self, name, bases, dic):
        # 练习一:加限制 控制类名必须以sb开头
        if not name.startswith('sb'):
            raise Exception('类名必须以sb开头')

# metaclass = Mymeta 指定这个类生成的时候,用自己写的Mymeta这个元类
class Person(object, metaclass=Mymeta):
    school = 'old_boy'
    def __init__(self, name):
        self.name = name
    def score(self):
        print('分数是100')

p = Person('nick')
# 运行程序控制台报错:'类名必须以sb开头'

练习二:类必须加注释

class Mymeta(type):
    def __init__(self, name, bases, dic):
        # 练习二:类中必须要有类注释
        doc = self.__dict__['__doc__']
        if not doc:
            # 没有加注释
            raise Exception('你的类没有加注释')
           
class Person(object, metaclass=Mymeta):
    """
    我是注释
    """
    school = 'oldboy'
    def __init__(self, name):
        self.name = name
       
p = Person('nick')
# 运行程序控制台不报错,因为类中有类注释

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

​ 控制类的调用过程,实际上就是控制对象的产生

练习:将对象中所有的属性都变成私有的

class Mymeta(type):
    def __call__(self, *args, **kwargs):
        # return self(*args) 会无限递归
        # 实例化产生一个Person类的对象,借助__new__来产生,需要把类传过去,才能产生对象
        obj = object.__new__(self)
        # 调用__init__方法完成初始化
        obj.__init__(*args, **kwargs)
        obj.__dict__ = {f'_{self.__name__}__{k}':v for k,v in obj.__dict__.items()}
        return obj
   
class Person(object, metaclass=Mymeta):
    school = 'old_boy'
    def __init__(self, name):
        self.name = name
    def score(self):
        print('分数是100')

P = Person(name='nick')
print(p.__dict__)
print(p.name)

五、有了元类的属性查找

类的属性查找顺序:先从类本身中找--->mro继承关系去父类中找--->去自己定义的元类中找--->type中--->报错

对象的属性查找顺序:先从对象自身找--->类中找--->mro继承关系去父类中找--->报错

posted @ 2019-09-03 16:25  17vv  阅读(299)  评论(0编辑  收藏  举报