zoukankan      html  css  js  c++  java
  • 元类

    1 什么是元类:

    源自一句话:在python中,一切皆对象,而对象都是由类实例化得到的

    # class OldboyTeacher:
    #     def __init__(self,name,age,sex):
    #         self.name=name
    #         self.age=age
    #         self.sex=sex
    #
    #     def score(self):
    #         print('%s is scoring' %self.name)
    
    # tea1=OldboyTeacher('egon',18,'male')
    # # print(type(tea1))
    # print(type(OldboyTeacher))

    对象tea1是调用OldboyTeacher类得到的,如果说一切皆对象,那么OldboyTeacher也是一个对象,只要是对象

    # 都是调用一个类实例化得到的,即OldboyTeacher=元类(...),内置的元类是type

    # 关系:

       1. 调用元类---->自定义的类

       2. 调用自定义的类---->自定义的对象

     class关键字创建自定义类的底层的工作原理,分为四步

       1. 先拿到类名:'OldboyTeacher'

       2. 再拿到类的基类们:(object,)

       3. 然后拿到类的名称空间???(执行类体代码,将产生的名字放到类的名称空间也就是一个字典里,补充exec)

       4. 调用元类实例化得到自定义的类

    OldboyTeacher=type('OldboyTeacher',(object,),{...})
    # class OldboyTeacher: #OldboyTeacher=type(...)
    #     school = 'Oldboy'
    #     def __init__(self,name,age,sex):
    #         self.name=name
    #         self.age=age
    #         self.sex=sex
    #
    #     def score(self):
    #         print('%s is scoring' %self.name)
    # print(OldboyTeacher)

     自定义类的三个关键组成部分:

     1. 类名

     2. 类的基类们

     3. 类的名称空间

     不依赖class关键字创建一个自定义类

    # 1. 拿到类名
    class_name='OldboyTeacher'
    #2. 拿到类的基类们:(object,)
    class_bases=(object,)
    #3. 拿到类的名称空间
    class_dic={}
    class_body="""
    school = 'Oldboy'
    
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex
    
    def score(self):
        print('%s is scoring' %self.name)
    """
    exec(class_body,{},class_dic)
    print(class_dic)
    #4. 调用type得到自定义的类
    OldboyTeacher=type(class_name,class_bases,class_dic)
    
    print(OldboyTeacher)
    # print(OldboyTeacher.school)
    # print(OldboyTeacher.score)
    
    tea1=OldboyTeacher('egon',18,'male')
    print(tea1.__dict__)
    #总结:对象之所以可以调用,是因为对象的类中有一个函数__call__
    #推导:如果一切皆对象,那么OldboyTeacher也是一个对象,该对象之所可以调用,肯定是这个对象的类中也定义了一个函数__call__
    class Mymeta(type): #但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类
        def __call__(self, *args, **kwargs): #self=OldboyTeacher这个类,args=('egon',18,'male'),kwargs={}
            # 1. 先产生一个空对象
            tea_obj=self.__new__(self) #tea_obj是OldboyTeacher这个类的对象
            # 2. 执行__init__方法,完成对象的初始属性操作
            self.__init__(tea_obj,*args,**kwargs)
            # 3. 返回初始化好的那个对象
            return tea_obj
    
    class OldboyTeacher(object,metaclass=Mymeta): #OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...})
        school = 'Oldboy'
    
        #            tea_obj,'egon',18,'male'
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
    
        def score(self):
            print('%s is scoring' %self.name)
    
    tea1=OldboyTeacher('egon',18,'male') # 会触发OldboyTeacher的类(即元类)中的__call__

     实例化会

       1. 先产生一个空对象

       2. 执行__init__方法,完成对象的初始属性操作

       3. 返回初始化好的那个对象

    基于元类实现单例模式 

    #步骤五:基于元类实现单例模式
    # 单例:即单个实例,指的是同一个类实例化多次的结果指向同一个对象,用于节省内存空间
    # 如果我们从配置文件中读取配置来进行实例化,在配置相同的情况下,就没必要重复产生对象浪费内存了
    #settings.py文件内容如下
    HOST='1.1.1.1'
    PORT=3306
    
    #方式一:定义一个类方法实现单例模式
    import settings
    
    class Mysql:
        __instance=None
        def __init__(self,host,port):
            self.host=host
            self.port=port
    
        @classmethod
        def singleton(cls):
            if not cls.__instance:
                cls.__instance=cls(settings.HOST,settings.PORT)
            return cls.__instance
    
    
    obj1=Mysql('1.1.1.2',3306)
    obj2=Mysql('1.1.1.3',3307)
    print(obj1 is obj2) #False
    
    obj3=Mysql.singleton()
    obj4=Mysql.singleton()
    print(obj3 is obj4) #True
    
    
    
    #方式二:定制元类实现单例模式
    import settings
    
    class Mymeta(type):
        def __init__(self,name,bases,dic): #定义类Mysql时就触发
    
            # 事先先从配置文件中取配置来造一个Mysql的实例出来
            self.__instance = object.__new__(self)  # 产生对象
            self.__init__(self.__instance, settings.HOST, settings.PORT)  # 初始化对象
            # 上述两步可以合成下面一步
            # self.__instance=super().__call__(*args,**kwargs)
    
    
            super().__init__(name,bases,dic)
    
        def __call__(self, *args, **kwargs): #Mysql(...)时触发
            if args or kwargs: # args或kwargs内有值
                obj=object.__new__(self)
                self.__init__(obj,*args,**kwargs)
                return obj
    
            return self.__instance
    
    
    
    
    class Mysql(metaclass=Mymeta):
        def __init__(self,host,port):
            self.host=host
            self.port=port
    
    
    
    obj1=Mysql() # 没有传值则默认从配置文件中读配置来实例化,所有的实例应该指向一个内存地址
    obj2=Mysql()
    obj3=Mysql()
    
    print(obj1 is obj2 is obj3)
    
    obj4=Mysql('1.1.1.4',3307)
    
    
    
    #方式三:定义一个装饰器实现单例模式
    import settings
    
    def singleton(cls): #cls=Mysql
        _instance=cls(settings.HOST,settings.PORT)
    
        def wrapper(*args,**kwargs):
            if args or kwargs:
                obj=cls(*args,**kwargs)
                return obj
            return _instance
    
        return wrapper
    
    
    @singleton # Mysql=singleton(Mysql)
    class Mysql:
        def __init__(self,host,port):
            self.host=host
            self.port=port
    
    obj1=Mysql()
    obj2=Mysql()
    obj3=Mysql()
    print(obj1 is obj2 is obj3) #True
    
    obj4=Mysql('1.1.1.3',3307)
    obj5=Mysql('1.1.1.4',3308)
    print(obj3 is obj4) #False
    View Code
  • 相关阅读:
    Helpful SharePoint JavaScript functions
    JQuery操作SharePoint Web Services之查询列表数据
    强大的SPGridView
    如何在 MOSS 2007 启用 Session
    实现类似于sharepoint列表的分组统计功能
    MOSS自带SPDatePickerControl控件的使用
    Silverlight多线程技术Thread的应用
    Silverlight同步(Synchronous)调用WCF服务
    Moss2007 Customize the NewForm.aspx 自定义NewForm EditForm页面
    Multiple Attachment custom control in Sharepoint
  • 原文地址:https://www.cnblogs.com/xuecaichang/p/9544370.html
Copyright © 2011-2022 走看看