• python 吐血总结【面向对象元类】


    什么是元类

    元类是python面向对象编程的深层魔法,很多人都不得要领。

    在python中一切皆是对象,用class定义得类本身也是一个对象,负责产生该对象的类称之为元类,即元类可以简称为类的类。

    简单来说,只要继承了type,他就是元类

    # Person也是一个对象,那么他一定是由一个类实例化得到的,这个类也就是元类
    class Person:
        pass
    p1 = Person
    # type类 是产生所有类的元类
    print(type(Person)) print(type(list)) print(type(dict)) print(type(object)) # <class 'type'>

    为什么用到元类

    元类是负责产生类的,所以我们学习元类或者自定义元类的目的,是1、为了控制类的产生过程,2、还可以控制对象的产生过程。

    class创建类

    class People:            # People = type()
        country = 'China'
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def eat(self):
            print('%s is eating' % self.name)
    class加类名,就会把类构造出来
    
    用class关键字创建一个类,用默认的元类type。

    type元类

    Person类是有type实例化产生的,向type传了一堆参数,然后type()类调用__init__方法,就会创建一个类。
    
    type()创建类格式:
    
    type(object, bases(继承的基类),  dict)
    
    object: object(所有基类) or name (类名:你需要创建的名字),类的名字,是个字符串
    
    base:是他的所有的父类 (元组的形式)、基类
    
    dict:名称空间,是一个字典;
    创建类的三要素:类名、基类、类的名称空间
    通过type 直接产生的类,不用class关键字
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    
    # 名称空间是一个字典
    # 创建类 People = type(类名基类类的名称空间)
    Person = type('Person', (object, ), {'school': 'hnnu','__init__': __init__,'sex':'boy'})
    
    # 创建对象
    p = Person('randy',12)
    print(p.say(p))

    通过元类来控制类的产生

    # 自定义元类马? ilil

    # Mymeta就是一个元类,因为它继承了type
    class Mymeta(type): def __init__(self, name, base, dict): print(name) # 类名 print(base) # 基类 print(dict) # 名称空间 """ 通过class 创建的类继承,自定义的元类,在Person中定义第一个参数表示类的名称,第二个参数表示继承的基类,而类中的代码dict则是,产生的名称空间。 """ class Ren(object, metaclass=Mymeta): school = 'hlxy' def __init__(self, name): self.name = name def score(self): print('score is 100') p = Ren('sb'

    例子1

    class Mymeta(type):
        def __init__(self, name, base, dic):
            # 练习一 加限制, 限制类名必须以sb开头
            print(name)
            if not name.startswith('heihei'):
                raise Exception('类名没有以heihei开头!!!!')
    
    class heihei_Ren(object, metaclass=Mymeta):
        school = 'hei'
        def __init__(self, name):
            self.name = name
            print(2)
    
        def score(self):
            print('分数为10000')
    
    p1 = heihei_Ren('Jac')

    例子2

    class Mymeta(type):
    
        def __init__(self, name, base, dic):
            print(self.__dict__)  # 产生的名称空间是类
            print(dic)
            doc = self.__dict__['__doc__']
            print("元类")
            if not doc:
                raise Exception("必须有注释")
    
            print(doc)
    
    
    class Person(object, metaclass=Mymeta):
        """
        我已经注释了
        """
        school = 'hnnu'
    
        def __init__(self, name):
            print("自己")
            self.name = name
    
        def score(self):
            print("分数是: 100")
    
    
    # 继承元类,首先会先进入元类中的__init__在返回来执行p1实例,然后再执行p1实例里面的__init__
    p1 = Person('ran')

    通过控制类产生的模板

    class Mymeta(type):
        def __init__(self, name, base, dic):
            if name == 'Person':
                raise Exception("名称错误")
    
    
    class Person1(metaclass=Mymeta):
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    
    p = Person1('laowang', 19)

    通过元类控制类得调用过程(控制创建类对象的过程)

    想要让obj这个对象变成一个可调用的对象,需要在该对象的类中定义一个方法,__call__方法,该方法会在调用对象的时候,自动触发
    我们之前说类实例化第一个调用的是__init__,但__init__其实不是实例化一个类的时候第一个被调用的方法。 
    
    当时候Person(name,age)这样表达式来实例化一个类的时候,最先被调用的方法其实是__new__方法。
    __new__方法接受的参数虽然和__init__一样,但__init__是在实例创建之后调用的,而__new__正是创建实例的方法。

    把对象属性都变成私有属性

    class Mymeta(type):
        def __call__(self, *args, **kwargs):
            print("__call__ 第一")
            # 产生空对象
            obj = object.__new__(self)
            # 调用子类__init__
            obj.__init__(*args, **kwargs)
    
            # 名称空间创建完成之后进行处理
            # 会进入self==> person类中__init__然后在回来
            obj.__dict__ = {f"_{self.__name__}__{k}": v for k, v in obj.__dict__.items()}
    
            # print("123456", obj.__dict__)
            # print("__call__ ", obj.__dict__)
    
            return obj
    
    
    class Person(object, metaclass=Mymeta):
        def __init__(self, name):
            print("___init__ 第二")
            self.name = name
    
        def score(self):
            print('分数是100')
    
    
    p = Person(name='randy')
    print(p.__dict__)
    # print(p._Person__name)

    自定义元类后继承顺序

    结合python继承得实现原理+元类重新看属性得查找是什么样子
    
    在学完元类之后,就发现每一个定义的clss都是一个对象(包括object类本身也是元类type得一个实例,可以用type(object))查看,我们也学习过继承的实现原理。
    class Mymeta(type):  # 只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
        n = 444
    
        def __call__(self, *args,**kwargs):  #self=<class '__main__.OldboyTeacher'>
            obj = self.__new__(self)
            self.__init__(obj, *args, **kwargs)
            return obj
    
    
    class Bar(object):
        n = 333
    
    
    class Foo(Bar):
        n = 222
    
    
    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)
    
    
    print(
        OldboyTeacher.n
    )  # 自下而上依次注释各个类中的n=xxx,然后重新运行程序,发现n的查找顺序为OldboyTeacher->Foo->Bar->object->Mymeta->type
    查找顺序:
    
    1、先在对象层:Oldboy——Foo——Bar——object
    
    2、然后元类层:Mymeta——type
    
    上述总结: 分析下元类Mymeta中__call__的self.__new__的查找

    C3算法

    总结

    继承元类,首先回进入元类中的__init__在返回来执行自己的__init__

    控制类产生模板

    #  控制类产生模板
    class Mymeta(type):
        def __init__(self, name, base, dic):
            if self.name == Person:
                raise Exception("名称错误")
    
    
    class Person(metaclass=Mymeta):
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    
    p = Person('laowang', 19)

    控制对象的产生

    class Mymeta(type):
        def __call__(self, *args, **kwargs):
    
            # 第一步产生空对象
            obj=object.__new__(self)
    # 第二部初始化空对象,把初始值放到对象中 obj.__init__(*args, **kwargs)
    # 第三步返回对象 return obj class Person(metaclass=Mymeta): def __init__(self,name): self.name=name def __call__(self, *args, **kwargs): print('xxx') p=Person('jackson6666') print(p.name)
    class Mymeta(type):
    def __call__(self, *args, **kwargs):

    # 第一步产生空对象

    obj=object.__new__(self)
    # 第二部初始化空对象,把初始值放到对象中
    obj.__init__(*args, **kwargs)
    # 第三步返回对象
    return obj

    class Person(metaclass=Mymeta):
    def __init__(self,name):
    self.name=name
    def __call__(self, *args, **kwargs):
    print('xxx')

    p=Person('jackson6666')
    print(p.name)
  • 相关阅读:
    Java基础小结
    Struts2
    Ajax
    IIS 调优、支持同时10万个请求
    sqlserver2014 数据完整备份、日志备份
    windows server 2016添加开机启动项
    FileZilla服务器
    Windows server 2016 设置多用户登陆
    centos7 调整XFS格式的磁盘容量大小
    IIS 500.19 0x8007000d 0x80070032 0x80070021 提示“执行此操作时出错”
  • 原文地址:https://www.cnblogs.com/jackson669/p/13022293.html
Copyright © 2020-2023  润新知