上节课内容回顾
# 面试题:这俩有什么区别
# sorted()
# l=[1,3]
# l.sort()
#
# len()
# l.__len__()
# 反射
# setattr() #向对象中设置属性或方法
# getattr() #获取对象中的属性或方法
# delattr() #删除对象中的属性或方法
# hasattr() #判断对象中是否有该属性或方法(属性或方法用字符串表示# )
# import os
# hasattr(os,'path')
# p=getattr(os,'path1',None)
# print(p)
# setattr(对象,key,value)
# delattr()
#内置方法(魔法方法)
# __str__ print 打印的时候,会自动触发该函数的执行
#点拦截方法 对象加 . 就会触发
# __setattr__ : 对象加.赋值或修改值会触发
#__getattr__ : 对象加.获取值,如果取不到,会触发
#__delattr__ :对象加. 删除值,会触发
# dic=dict(name='lqz',age=18)
# dic.name
# dic['name']
# class Mydic(dict):
# def __setattr__(self, key, value):
#
# # print('xxxx')
# self[key]=value
# def __getattr__(self, item):
# print('yyyy')
#
# a=self[item]
# return a
#
# di=Mydic(name='lqz',age=18)
# # print(di['name'])
#
# print(di.name)
# di.sex='male'
# print(di['sex'])
# class Foo():
# def __init__(self,name):
# self.name=name
#
# def __setattr__(self, key, value):
# # print('xxxx')
# #这种方式有问题!出现递归
# # setattr(self,key,value)
# #第一种方法(名称空间字典):
# # self.__dict__[key]=value
# #第二种方法(推荐)
# super().__setattr__(key,value)
# # object.__setattr__(self,key,value)
# def __getattr__(self, item):
# return '没有值'
#
#
# f=Foo('nick')
#
# f.name1='lqz'
# print(f.name)
# print(f.name1)
# @auth
# def tett():
# pass
#__call__
# class Foo():
# # pass
# def __call__(self, *args, **kwargs):
#
# print(kwargs)
# f=Foo()
# f(a=1,b=2)
一、元类是什么
#一切皆对象:类实际上一个一个对象
#Person类也是个对象,那他一定是由一个类实例化得到,这个类,就叫元类
#type是内置的一个元类,所有的类都是由type实例化得到
# 产生类的类,叫元类
class Person:
def __init__(self,name):
self.name=name
def score(self):
print('分数是100')
p=Person('nick')
# a=Person
# p1=a('nick')
# print(p1.name)
#如何找元类?
# print(type(p))
#同理:type类是产生所有类的元类
# print(type(Person))
print(type(dict))
print(type(list))
print(type(str))
print(type(object))
print(type(type))
type
二、class底层原理分析
#class 类名 会把类构造出来
#实际上是:元类实例化产生类 这个对象
#类实例化产生对象,一定是: 类名()
#Person 类是由type实例化产生,传一堆参数
#type() 调用类的__init__方法
# type()
#type(object_or_name, bases, dict)
# object_or_name:类的名字,是个字符串
#bases:是它的所有父类,基类
#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,),{'school':'oldboy','__init__':__init__})
#
Person=type('Person',(object,),l)
# print(Person.__dict__)
print(Person.__bases__)
# p=Person('nick')
# print(p.name)
# print(p.__dict__)
#class 底层就是调用type来实例化产生类(对象)
# class Person:
# school='oldboy'
# def __init__(self,name):
# self.name=name
# def score(self):
# print('分数是100')
# a=Person
#
# p=Person('nick')
#exec() eval()的区别
# l={}
# exec('''
# school='oldboy'
# def __init__(self,name):
# self.name=name
# def score(self):
# print('分数是100')
# ''',{},l)
# print(l)
# g={ 'x':1,'y':2}
# l={}
# exec('''
# global x
# x=100
# z=200
# m=300
# ''',g,l)
# print(g)
# print(l)
# x=1
# y=2
# def test():
# global x
# x = 100
# z = 200
# m = 300
三、通过元类来控制类的产生
#自定义元类;来控制类的产生:可以控制类名,可以控制类的继承父类,控制类的名称空间
# type
#自定义元类必须继承type,写一个类继承type 这种类都叫元类
#
# class Mymeta(type):
# # def __init__(self,*args,**kwargs):
# def __init__(self,name,bases,dic):
# # self 就是Person类
# # print(name)
# # print(bases)
# # print(dic)
# #练习一:加限制 控制类名必须以sb开头
# # if not name.startswith('sb'):
# # 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()
# class Mymeta(type):
# def __init__(self,name,bases,dic):
# print(self.__dict__['__doc__'])
# doc=self.__dict__['__doc__']
# if not doc:
# #没有加注释
# raise Exception('你的类没有加注释')
# class Person(object,metaclass=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)
# class Person():
# school='oldboy'
# def __init__(self,name):
# self.name=name
# def score(self):
# print('分数是100')
# def __call__(self, *args, **kwargs):
# print('xxxx')
#
# p=Person('nick') #自动触发init的执行
# #先触发元类的__call__
# p()
#__new__
object
#练习:给我吧对象中的所有属性都设置成私有的
#分析
# class Mymeta(type):
# def __call__(self, *args, **kwargs):
# #self 是Person这个类
# # print(args)
# # print(kwargs)
# # return self(*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)
# 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)
# print(p.name)
#把对象所有的属性都变成私有
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__)
print(p.name)
# print(p)
# 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)
# print(o.n)