• 面向对象之元类


    在Python中, 一切皆对象,  对象是类的实例化。那么类又是由什么实例化得到的呢?

    元类的介绍

    class People(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def say(self):
            print('%s:%s' % (self.name, self.age))
    
    obj = People('featherwit', 18)
    
    print(type(obj))  # <class 'People'>
    print(type(People))  # <class 'type'>

    如果一切皆为对象,那么类本质也是一个对象,既然所有的对象都是调用类得到的,那么必然也是调用了一个类得到的,这个类称为元类。

    所以调用关系为:

    class关键字创建类的流程

    我们用class关键字定义的所有的类以及内置的类都是由元类type实例化得到的

    class关键字创建类的流程主要步骤为:

    1. 拿到类名: class_name = "People"
    2. 拿到基类: class_bases = (object, )
    3. 执行类体代码拿到类的名称空间: class_dic = {...}
    4. 调用元类: People = type(class_name, class_bases, class_dic)

    exec的用法:

    exec:三个参数

    参数一:包含一系列python代码的字符串

    参数二:全局作用域(字典形式),如果不指定,默认为globals()

    参数三:局部作用域(字典形式),如果不指定,默认为locals()

    #可以把exec命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中

    自定义元类控制类的创建

    一个类没有声明自己的元类,默认他的元类就是type,除了使用内置元类type,我们也可以通过继承type来自定义元类,然后使用metaclass关键字参数为一个类指定元类

    class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
        pass
    
    class People(metaclass=Mymeta):
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def say(self):
            print('%s:%s' % (self.name, self.age))

    自定义元类可以控制类的产生过程,类的产生过程其实就是元类的调用过程,即

    People = Mymeta(People, (object, ), {...})
    
    # 步骤:
    # 1. 先造一个空对象 -> People, 调用类内的__new__方法
    # 2. 调用Mymeta这个类内的__init__方法, 完成初始化操作
    # 3. 返回初始化好的对象 -> 调用元类的__call__方法
    class Mymeta(type):  # 只有继承了type的类才是元类
    
        def __init__(self, class_name, class_bases, class_dic):
            # print(self)  # <class '__main__.People'>
            # print(class_name)  # People
            # print(class_bases)  # ()
            # print(class_dic)  # {'__module__': '__main__', '__qualname__': 'People', '__init__': <function People.__init__ at 0x7fe8f96bfe60>, 'say': <function People.say at 0x7fe8f96bfef0>}
    
            if not class_name.istitle():
                raise NameError('类名的首字母必须大写')
    
        def __new__(cls, *args, **kwargs):
            # 造Mymeta的对象
            # return type.__new__(cls, *args, **kwargs)
            return super().__new__(cls, *args, **kwargs)

    自定义元类控制类的调用

    class Foo:
        def __call__(self, *args, **kwargs):
            print(self)
            print(args)
            print(kwargs)
    
    obj=Foo()
    #1、要想让obj这个对象变成一个可调用的对象,需要在该对象的类中定义一个方法__call__方法,该方法会在调用对象时自动触发
    #2、调用obj的返回值就是__call__方法的返回值
    res=obj(1,2,3,x=1,y=2)

    调用一个对象,就是触发对象所在类中的__call__方法的执行,如果把类也当做一个对象,那么类这个对象的类中也必然存在一个__call__方法

    # 如果想让一个对象可以加括号调用, 需要在该对象的类中添加一个方法__call__
    class Mymeta(type):
    
        def __call__(self, *args, **kwargs):
            # 1. Mymeta.__call__函数内会先调用People内的__new__
            people_obj = self.__new__(self)
            # 2. Mymeta.__call__函数会调用People内的__init__
            self.__init__(people_obj, *args, **kwargs)
            # 3. Mymeta.__call__函数内会返回一个初始化好的对象
            return people_obj
    
    
    class People(metaclass=Mymeta):
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def say(self):
            print('%s:%s' % (self.name, self.age))
    
        def __new__(cls, *args, **kwargs):
            # 产生真正的对象
            return object.__new__(cls)
    默认的, 产生类的时候会做三件事情:
    # People = Mymeta(People, (object, ), {...}) -> type.__call__
    # 1. type.__call__函数内会先调用Mymeta内的__new__
    # 2. type.__call__函数会调用Mymeta内的__init__
    # 3. type.__call__函数内会返回一个初始化好的对象
    
    默认的, 调用类的时候会做三件事情
    # obj = People('featherwit', 18) -> Mymeta.__call__()
    # 1. Mymeta.__call__函数内会先调用People内的__new__
    # 2. Mymeta.__call__函数会调用People内的__init__
    # 3. Mymeta.__call__函数内会返回一个初始化好的对象

    元类的使用案例

    实现单例模式

    # 1. __new__()方法实现单例
    class Singleton(object):
        def __new__(cls, *args, **kwargs):
            if not hasattr(cls,"_instance"):
                cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
            return cls._instance
    
    
    s1 = Singleton()
    s2 = Singleton()
    
    print(s1 is s2)
    
    # 2. 元类实现单例
    class Singleton(type):
        def __init__(self, *args, **kwargs):
            self.__instance = None
            super(Singleton,self).__init__(*args, **kwargs)
    
        def __call__(self, *args, **kwargs):
            if self.__instance is None:
                self.__instance = super(Singleton,self).__call__(*args, **kwargs)
            return self.__instance
    
    
    class Foo(metaclass=Singleton):
        pass
  • 相关阅读:
    python 产生token及token验证
    Django中间件
    docker学习笔记16:Dockerfile 指令 ADD 和 COPY介绍
    Docker 容器镜像删除
    linux查找nginx所在目录
    nginx启动访问
    nginx安装【linux下安装】
    QPS计算
    Jmeter压测问题_Non HTTP response code: org.apache.http.conn.ConnectTimeoutException
    Jmeter压测问题_Non HTTP response code: java.net.ConnectException
  • 原文地址:https://www.cnblogs.com/featherwit/p/13340408.html
Copyright © 2020-2023  润新知