zoukankan      html  css  js  c++  java
  • 元类与单例解析

    一、eval、exec内置函数

    1、eval函数

    eval内置函数的使用场景:
    ①执行字符串会得到相应的执行结果
    ②一般用于类型转换得到dict、list、tuple等

    2、exec函数

    exec应用场景 用来辅助了解元类的概念

    ①执行字符串没有执行结果(没有返回值)

    ②将执行的字符串中产生的名字形成对应的局部名称空间

    解析exec函数
    exec函数帮我们运行字符串中的代码,把字符串中产生的名字放到名称空间里
    
    自己定义全局作用域中的名字和字典,自己定义局部作用域的名字和字典
    将所要执行的代码放到字符串中,在字符串中写好操作全局作用域的和局部作用域的
    
    字符串内放一堆代码,exec来运行字符串中的代码的时候产生的名字都会放到名称空间里,
    放到自己定义的全局或者是局部的名称空间里,如果声明是global,就会放到global的字典里
    exec(字符串,global_dic, local_dic)
    code = """
    global x
    x=0
    y=2
    """
    global_dic = {'x': 100000}
    local_dic = {}
    exec(code, global_dic, local_dic)
    print(global_dic)
    print(local_dic)   # {'y': 2}
    
    
    code
    = """ x=1 y=2 def f1(self,a,b): pass """ local_dic = {} exec(code, {}, local_dic) print(local_dic) # {'x': 1, 'y': 2, 'f1': <function f1 at 0x00000000027A8C80>}

    二、类的名称空间的控制

    class A:
        pass
    
    print(A.__dict__)
    
    a = A()
    print(a, type(a))   #  <__main__.A object at 0x00000000021E7400> <class '__main__.A'>
    
    print(A, type(A))   # <class '__main__.A'> <class 'type'>
    
    print(type)        # <class 'type'>
    print(type(type))   # <class 'type'>
    
    
    python中万物皆对象,所有用来创建对象的类,本身也是对象,类是type类的对象
    type类叫做元类,是所有元类的基类
    元类:制造类的类 --类的类
    控制类的产生
    控制类的对象的产生
    
    
    s = '''
    my_a = 10
    my_b = 20
    def __init__(self):
        pass
    @classmethod
    def print_msg(cls, msg):
        print(msg)
    '''
    dic = {}
    exec(s, {}, dic)
    
    C = type('C', (object, ), dic)
    print(C, type(C), C.__bases__)   # <class '__main__.C'> <class 'type'> (<class 'object'>,)
    print(C.__dict__)
    c1 = C()
    print(c1.my_a)     # 10
    C.print_msg('12345')
    
    
    class D:
        my_a = 10
        my_b = 20
    
        def __init__(self):
            pass
        @classmethod
        def print_msg(cls, msg):
            print(msg)
    
    c1 = C()
    print(c1.my_a)     # 10
    C.print_msg('12345')   # 12345

    三、元类

    1、定义:

    python中万物皆对象,所有用来创建对象的类,本身也是对象,类是type类的对象

    type类叫做元类,是所有元类的基类

    元类:制造类的类 --类的类  

          控制类的产生 

          控制类的对象的产生

    2、__init__、__call__、__new__的用法

    ①__init__:实例化的时候会自动触发__init__的执行

    ②__call__:调用类的时候会自动触发

    class Zoo:
        def __init__(self):
            print('1')       # 对象实例化时候触发
        def __str__(self):   # 打印对象的时候产生
            return 'abc'
        def __del__(self):   # 删除对象的时候触发
            pass
        def __call__(self, *args, **kwargs):   # 调用类的时候触发
            print('2')
    obj = Zoo()   # 1
    print(obj)    # abc
    obj()         # 2     # 调用对象

    ③__new__:

    class CountError(Exception):
        pass
    
    
    class MyMeta(type):
    
        # 自定义元类,重写init方法的目的:
        # 1.该方法是从type中继承来的,所以参数同type的init
        # 2.最终的工作(如果开辟空间,如果操作内存)还是要借助type
        # 3.在交给type最终完成工作之前,可以对类的创建加以限制 *****
        def __init__(cls, class_name: str, bases, namespace):
            print(cls)   # <class '__main__.Student'>
            print(class_name)  # Student
            print(bases)   # (<class 'object'>,)
            print(namespace)   # {'__module__': '__main__', '__qualname__': 'Student', '__init__': <function Student.__init__ at 0x0000000001EA89D8>}
            # 需求:由给元类控制的类的类名必须首字母大写
            if not class_name.istitle():
                raise NameError('名字首字母必须大写')
            # 需求:定义类是必须明确父类
            if len(bases) == 0:
                raise CountError('父类必须明确')
    
            # super(MyMeta, cls).__init__(class_name, bases, namespace)
            super().__init__(class_name, bases, namespace)
    
    
        # 自定义元类,重写call方法的目的:
        # 1.被该元类控制的类生成对象,会调用元类的call方法
        # 2.在call中的返回值就是创建的对象
        # 3.在call中
        #       通过object开辟空间产生对象
        #       用被控制的类回调到自己的init方法完成名称空间的赋值
        #       将修饰好的对象反馈给外界
        def __call__(cls, *args, **kwargs):
            print('call fn run')               # call fn run
            obj = object.__new__(cls)
            # 需求:所有通过该元类控制的类产生的对象都有meta_name该属性
            obj.meta_name = cls.__name__
            # obj.name = args[0]
            # 调回当前被控制的类自身的init方法,完成名称空间的赋值
            cls.__init__(obj, *args, **kwargs)
            return obj
    
    
    
    # Student = MyMeta(class_name, bases, namespace)
    class Student(object, metaclass=MyMeta):
        def __init__(self, name, age):
            print('init fn run')       # init fn run
            self.name = name
            self.age = age
            pass
    
    # stu = Student()
    
    # class Teacher(Student, metaclass=MyMeta):
    #     pass
    
    
    stu = Student('Bob', 18)
    print(stu, stu.name, stu.age)   # <__main__.Student object at 0x0000000001EB7FD0> Bob 18
    stu = Student('Tom', 20)
    print(stu.meta_name)            # Student

    3、自定义元类控制类的创建

    需求:类名的首字母必须大写;类中必须写好文档注释

    ①需求:类名首字母必须大写
    class Mymeta(type):
        def __init__(self, class_name, class_bases, class_dic):
            if not class_name.istitle():
                raise TypeError('类名必须大写')
            super().__init__(class_name, class_bases, class_dic)   # 重用父类的方法
    
    class Foo(object, metaclass=Mymeta):
        pass
    
    
    ②需求: 类中必须有文档注释
    class Mymeta(type): def __init__(self, class_name, class_bases, class_dic): if not class_dic.get('__doc__'): raise TypeError('类中必须写好文档注释') super().__init__(class_name, class_bases, class_dic) class Zoo(metaclass=Mymeta): """ 文档注释 """ pass

    四、单例

    1、定义:一个类只能产生一个实例

    2、为什么要有单例:

    ①该类需要对象的产生

    ②对象一旦产生,在任何位置再实例化对象,只能得到第一次实例化出来的对象

    3、单例实现的四种方法:

    ①方法1
    class Songs():
        __instance = None
        @classmethod
        def getInstance(cls):
            # 对象没有创建返回,有直接返回
            if cls.__instance == None:
                cls.__instance = cls()
            return cls.__instance
    
    # 约定别用 类名() 来实例化对象,用类方法来获取唯一对象
    s1 = Songs()
    s2 = Songs()
    
    print(s1)         # <__main__.Songs object at 0x0000000001E776D8>
    print(s2)         # <__main__.Songs object at 0x0000000001E77710>
    print(s1 is s2)   # False
    
    s1 = Songs.getInstance()
    s2 = Songs.getInstance()
    
    print(s1)          # <__main__.Songs object at 0x00000000027A76D8>
    print(s2)          # <__main__.Songs object at 0x00000000027A76D8>
    print(s1 is s2)    # True
    
    
    ②方法2
    class Songs:
        __instance = None
        def __new__(cls, song_name, *args, **kwargs):
            if cls.__instance == None:
                cls.__instance = object.__new__(cls)
                cls.__instance.song_name = song_name
            return cls.__instance
    
        def change_song(self, song_name):
            self.song_name = song_name
    
    s1 = Songs('菊花爆满山')
    s2 = Songs('感觉身体被掏空')
    print(s1.song_name, s2.song_name)  # 菊花爆满山  菊花爆满山
    s2.change_song('感觉身体被掏空')
    print(s1.song_name, s2.song_name)  # 感觉身体被掏空 感觉身体被掏空
    
    
    ③方法3:采用装饰器
    def outer(cls):
        _instance = None
        def inner(*args, **kwargs):
            nonlocal _instance
            if _instance == None:
                _instance = cls(*args, **kwargs)
            return _instance
        return inner
    
    @outer  # Songs = outer(Songs)
    class Songs:
        pass
    
    s1 = Songs()
    s2 = Songs()
    print(s1)   # <__main__.Songs object at 0x0000000001EB7748>
    print(s2)   # <__main__.Songs object at 0x0000000001EB7748>
    print(s1 is s2)   # True
    
    
    ④方法4
    class SingleMeta(type):
        __instance = None
        def __call__(cls, *args, **kwargs):
            if SingleMeta.__instance == None:
                SingleMeta.__instance = object.__new__(cls)
                cls.__init__(SingleMeta.__instance, *args, **kwargs)
            return SingleMeta.__instance
    
    class Songs(metaclass=SingleMeta):
        def __init__(self):
            pass
        pass
    
    s1 = Songs()
    s2 = Songs()
    print(s1)         # <__main__.Songs object at 0x0000000001E775C0>
    print(s2)         # <__main__.Songs object at 0x0000000001E775C0>
    print(s1 is s2)   # True
  • 相关阅读:
    qt一直编译
    JavaWeb-国际化之Locale
    JavaWeb-文件下载
    JavaWeb-文件上传案例
    JavaWeb-使用fileload组件
    JavaWeb—文件上传基础
    JavaWeb-其他Listener监听器(3)
    JavaWeb-其他Listener监听器(2)
    JavaWeb-其他的servlet监听器(1)
    JavaWeb——通过Listener理解域对象生命周期
  • 原文地址:https://www.cnblogs.com/zhangguosheng1121/p/10780231.html
Copyright © 2011-2022 走看看