小结
元类
首先明确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)