zoukankan      html  css  js  c++  java
  • 元类

    code='
    gloabl s
    s=1000
    a=10
    print(a)
    '
    global_dic={}
    local_dic={}
    exec(code,global_dic,local_dic)
    # print(global_dic)
    
    
    # print(globals())
    # print(local_dic)
    
    
    # 要求你把你一个字符串中出现的名字 存储到一个名称空间中
    # text = """
    # def func():
    #     print("func run")
    # """
    # l_dic = {}
    # exec(text,{},l_dic)
    # l_dic["func"]()


    什么是元类
    一切接对象

    类的类就是元类
    Person类是由type实例化产生的 默认情况下 所有类的元类都是type(object除外)


    # """
    # import abc  # 抽象类
    #
    # class Person(metaclass=type): # Person == type(..........)
    #     def __init__(self,name,gender):
    #         self.name = name
    #         self.gender = gender
    #
    #     def say_hi(self):
    #         print("hello im am %s  gender is %s" % (self.name,self.gender))
    #
    # p = Person("jerry","男神")
    # # p.say_hi()
    #
    # # 函数对象
    # # ls = [Person]
    # # print(ls[0])
    # #
    # # def f1(cls):
    # #     print(cls)
    # #
    # # f1(Person)
    #
    # print(type(p))
    # print(type(Person)) # Person类是有type实例化产生的
    一个类需要包含三个部分
    类名称 他的父类 名称空间
    
    
    # class_name = "myclass"
    # class_bases = (object,)
    # class_namespace = {}
    #
    # code = """
    # school = "oldboy"
    # def hello(self):
    #     print(self)
    # """
    #
    # exec(code,{},class_namespace)
    # print(class_namespace)
    从创建类的另一种方式
    自己来实例化type类
    # obj = type(class_name,class_bases,class_namespace)
    #限制一个类必须拥有类注释 否则不允许创建类
    class MyMeta(type):
        def __init__(self,cls_name,bases,namespace):
            if not self.__doc__:
                raise TypeError('必须包含类注释!!')
            super().__init__(cls_name,bases,namespace)#保证父类代码也走过了
    class Animal(metaclass=MyMeta):
        '''
        kjl
        '''
        pass
    
    
    print(Animal.__doc__)
    # print(Animal)
    
    #a继承b 都拥有func
    
    #ORM框架中 要通过检测类的信息来创建表
    添加注释例子
    
    
    type类中肯定有__init__方法
    class MyMetaClass(type):
        # 创建类时 就会自动执行元类中的init方法
        def __init__(self,class_name,bases,namespace):
            print("MyMetaClass init run")
    
    
    # 产生一个空的类对象 在调用MyMetaClass中的__init__方法
    class ClassA(metaclass=MyMetaClass): # ClassA = type("ClassA",(,),{})
    
        def __init__(self,name):
            self.name = name



    # 创建出一个CLassA的类对象

    class Test:
    def __init__(self):
    pass

    t = Test() #实例化
    # 1.创建一个对象的名称空间 空对象
    # 2.执行__init__方法来为对象赋初始值


    元类中init方法的执行:
    class A:
        pass
    
    # print(A)
    # print(type(A))
    
    namespace = {}
    namespace["name"] = "jack"
    
    
    cls = type("这是一个实例化Type产生的类",(object,),namespace)
    #
    # print(cls.name)
    # print(A)

    一个类是通过实例化type类产生的
    元类就是用于产生类的类


    # 自定义一个元类
    class MyMeta(type):
    #     # 创建B这个类对象的时候回自动执行
        def __init__(self,a,b,c):
            print('MyMeta init run')
            print(a)
            print(b)
            print(c)
            self.school='xxx'
        pass
    
    class B(metaclass=MyMeta):#B=MyMeta(B,'B',(object,),{....})
        pass
    
    print(B.school)

    # 必须保证类名大写开头
    # class Meta1(type):
    #     def __init__(self,clas_name,bases,namespace):
    #         if not clas_name.istitle():
    #             raise  TypeError("类名必须大写开头!")
    # # 命名方式  大驼峰
    # class person(metaclass=Meta1):
    #     pass


    __call__方法的执行时机:
    会在某个时间自动执行:调用对象时自动执行该函数

    class MyMeta(type):
        # 会在类对象 准备实例化产生对象时执行
        # 该函数可以控制实例化对象的过程
        def __call__(self, *args, **kwargs):
            print("Mymeta call run!")
            # print(self)
            # print(args)
            # print(kwargs)
    
            #无论你要添加什么功能  只要覆盖了__call__  就必须把下面两个步骤做了
            #1.需要创建一个对象
            obj = object.__new__(self)
            #2.调用对应init来初始化这个对象
            self.__init__(obj,*args,**kwargs)
            return obj
    
            # super().__call__(*args,**kwargs)
    
    class Student(metaclass=MyMeta):
        def __init__(self,name):
            self.name = name
        pass
    
    s = Student("bgon") # 是为了创建并实例化一个Student类的对象
    print(s)

    __init__创建类对象的时候执行 控制类的创建过程
    __call__实例化产生对象时执行 控制对象的创建过程




    单例模式:
    一种设计模式,MVVM MVC MTV
    常推荐书籍见设计模式

    要保证一个类只能有一个实例(单例)
    目的是为了节省内存开销
    如果两个对象的数据一模一样 就没有必要创建新对象 直接使用已有的即可
    场景:当一个类的所有实例数据都完全相同时,则应该设计为实例
    音乐播放器类 实例化产生播放器对象
    单例的实现方式:
    自定义元类 覆盖__call__ 添加判断逻辑 保证只能实例化一个对象
    class MySingleton(type):
        obj = None
        def __call__(self, *args, **kwargs):
            if not self.obj:
                # 创建空对象
                obj = object.__new__(self)
                # 调用初始化方法
                self.__init__(obj, *args, **kwargs)
                self.obj = obj
            return self.obj
    
    
    class Player(metaclass=MySingleton):
        # 默认为空
        obj = None
    
        def __init__(self):
            print("创建了一个播放器对象....")
    
        def play(self,path):
            self.stop()
            print("playing...",path)
    
        def stop(self):
            print("stop music")
    
        # 用于获取播放器对象
        @classmethod
        def get_player(cls):
            if not cls.obj:
                print("创建播放器...")
                cls.obj = cls()
            return  cls.obj
    
    
    
    # p = Player("给我一杯忘情水.mp3")
    # p.play()
    #
    #
    # p.stop()
    # p1 = Player("回首掏.mp3")
    # p1.play()
    
    # p = Player()
    # p.play("一杯忘情水.")
    #
    #
    p1 = Player.get_player()
    p1.play("爱你一万年1.")
    
    
    p2 = Player.get_player()
    p2.play("爱你一万年2.")
    
    
    
    # 上述代码 有bug  可以通过直接调用类 来产生新对象
    Player().play("我的滑板鞋!")
    播放器案例

    存在元类时的属性查找:
    # class Meta(type):
    #     s = 1000
    #
    #
    # class A:
    #     s = 1
    #     pass
    # class B(A,metaclass=Meta):
    #     # s = 2
    #     pass
    #
    # b = B()
    # # b.s = 3
    #
    # print(b.s)
    class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
        n=444
    
    class Bar(object):
        # n = 333
        pass
    class Foo(Bar):
        # n=222
        pass
    class Teacher(Foo,metaclass=Mymeta):
        # n=111
        pass
    print(Teacher.n)


    查找顺序:
    先自己 在父类 在元类
  • 相关阅读:
    使用requests爬虫简单获取知乎问题信息
    slam介绍
    move_base 控制机器人(2)
    move_base 控制机器人(1)
    Linux 常用命令-touch
    Linux 常用命令-rmdir
    Linux 常用命令-rm
    Linux 常用命令-mkdir
    Linux 目录结构
    Linux 常用命令-pwd
  • 原文地址:https://www.cnblogs.com/gengbinjia/p/10580362.html
Copyright © 2011-2022 走看看