小结

元类

首先明确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)