python3-元类

目录

元类:用class关键字定义的类本身是一个对象。

           基于此,负责产生该对象的类称之为元类(类的类),内置的元类为type。

控制类调用的过程(元类体使用__call__)

属性查找顺序


元类:用class关键字定义的类本身是一个对象。

           基于此,负责产生该对象的类称之为元类(类的类),内置的元类为type。

class People:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def score(self):
        print('%s is scoring' % self.name)


p = People('name', 18)
print(type(p))
print(type(People))

'''
对象是调用类的到的,若一切皆对象,则类也是一个对象。
且对象都是调用类实例化而来,即 People = 元类(……);内置的元类为type

关系:
    1.调用元类---》自定义的类
    2.调用自定义的类--->自定义的对象

class关继字底层工作原理(4步):
    1.拿到类名'People'
    2.拿到基类:(object,)
    3.拿到类的名称空间
    4.调用元类实例化的到自定义的类
        People = type('People',(object,),{……})
    
自定义类的三个关键组成部分:
    1.类名
    2.类的基类
    3.类的名称空间
'''
# 不依赖class关键字创建一个自定义类
# 1.类名
class_name = 'People'
# 2,类的基类
class_bases = (object,)
# 3.类的名称空间
class_dic = {}
# 4.类的执行代码块
class_body = """
school = 'college'

def __init__(self,name,age,sex):
    self.name=name
    self.age=age
    self.sex=sex

def score(self):
    print('%s is scoring' %self.name)
"""

# exec(object,globals,locals) exec(执行对象,全局容器{必须为字典},本地容器{任何映射对象})
# exec 返回值永远为 None。
exec(class_body, {}, class_dic)
# 获取类的名称空间
print(class_dic)

# 5.调用tyoe的到自定义的类
people = type(class_name, class_bases, class_dic)
print(people.__dict__)

'''自定义元类来控制类的产生 (通过__init__) '''
# 模板
class Mymeta(type):  # 但凡继承了type的类,称之为自定义元类
    def __init__(self,class_name,class_bases, class_dic):
        print(self)
        print(class_name)
        print(class_bases)
        print(class_dic)


# People = Mymeta('People',(object,),{……})
class People(object,metaclass=Mymeta):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def score(self):
        print('%s is scoring' % self.name)

# 控制类的产生:
#   1.类名必须用驼峰体
#   2.类体必须有文档注释,且不能为空
class Mymeta(type):
    def __init__(self, class_name, class_bases, class_dic):
        if class_name.islower():
            raise TypeError('类名必须使用驼峰体')
        doc = class_dic.get('__doc__')
        if doc is None or len(doc) == 0 or len(doc.strip('\n ')) == 0:
            raise TypeError('类体中必须有文档注释,且不能为空')


# People = Mymeta('People',(object,),{……})
class People(object, metaclass=Mymeta):
    '''
    111
    '''
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def score(self):
        print('%s is scoring' % self.name)


控制类调用的过程(元类体使用__call__)

'''
# 控制类调用的过程

# 实例化过程:
# 1. 先产生一个空对象
# 2. 执行__init__方法,完成对象的初始属性操作
# 3. 返回初始化好的那个对象
#
# 总结:对象之所以可以调用,是因为对象的类中有一个函数__call__
# 推导:如果一切皆对象,那么类也是一个对象,该对象之所可以调用,肯定是这个对象的类中也定义了一个函数__call__
'''
class Mymeta(type):
    def __call__(self, *args, **kwargs):  # self=People这个类,args=('name',18,'male'),kwargs={}
        # 1. 先产生一个空对象
        #__new__ 是在__init__之前被调用的特殊方法
        # __new__是用来创建对象并返回之的方法
        p_obj = self.__new__(self)  # p_obj是People这个类的对象

        # 2. 执行__init__方法,完成对象的初始属性操作
        self.__init__(p_obj, *args, **kwargs)

        # 3. 返回初始化好的那个对象
        return p_obj


# People = Mymeta('People',(object,),{……})
class People(object, metaclass=Mymeta):
    '''
    111
    '''

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def score(self):
        print('%s is scoring' % self.name)


p = People('name', 18, 'male')  # 会触发OldboyTeacher的类(即元类)中的__call__函数
print(p)
print(p.__dict__)

属性查找顺序

'''
属性查找顺序:
    1、对象层,基于mro列表的查找
    2、元类层
对象的类-》父类-》父父类……——》object类-》元类(自定义)—》type
'''
class Mymeta(type):
    n = 444

    def __call__(self, *args, **kwargs):
        # self=
        obj = self.__new__(self)
        print(self.__new__ is object.__new__)  # True


class Bar(object):
    n = 333

    # def __new__(cls, *args, **kwargs):
    #     print('Bar.__new__')


class Foo(Bar):
    n = 222

    # def __new__(cls, *args, **kwargs):
    #     print('Foo.__new__')


class Teacher(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('Teacher.__new__')


Teacher('egon', 18)
# 触发Teacher的类中的__call__方法的执行,进而执行self.__new__开始查找

你可能感兴趣的:(python)