第一阶段:Python开发基础 day29 面向对象之元类以及元类延伸的相关知识

上节课内容回顾

# 面试题:这俩有什么区别
# 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)
posted @ 2019-09-16 18:44  foreversun92  阅读(161)  评论(0编辑  收藏  举报