• 元类补充和单例的四种方式


    我的心情本来就不太好,不要再让傻逼来让自己变得更糟糕啦

    img

    关于元类控制类的生成以及控制类的调用的补充

    上一篇博客我们讲到了实例化类生成对象的控制,就是在类的init方法里面加上限制,在调用类名()的时候,其实我们会先调用它的元类的call方法,然后在call方法里,先生成一个空对象,然后空对象再调用这个类的init方法进行初始化。

    类的生成也是一样。我们通过class 类名()来进行类的创建,一旦解释器看到有class这个关键字,就马上调用元类,用自定义元类(类名,继承的父类,名称空间)来实例化一个类。同样道理,我们在自定义的元类里面的init方法写上限制,因为我们调用到了自定义元类(),所以他会去调用自定义元类的call方法,然后call方法里面生成了一个空的类对象,在调用init来进行初始化。

    但其实,这中间有一个环节,我们都错过了,那就是如何生成一个空对象,是的,没错,是__new__方法,但是其实在实例化对象的时候调用的new,和实例化类的时候调用的new的效果不一样,生成对象的时候new会生成一个空对象,全空,但是在生成类的时候new出来的空对象并不是空对象,而是一个完整的,属性都已经配置好的类对象了,我们来看一下两者的区别

    class Mymeta(type):
        def __call__(self):
            obj=object.__new__(self)
           return obj
    

    这里的空对象是由object来调用生成的,是一个空对象。

    class Mymeta(type):
        def __new__(cls,name,bases,dic):
            return type.__new__(cls,name,bases,dic)
    

    你这里写的new方法,是在实例化类的时候,type元类会调用,如果你没有写,type会直接调用type.__new__来返回类对象,事实上,只要调用了type的new,这个空对象就已经不是空对象了,他已经完全被初始化好了。

    单例模式

    设计模式一共有23种,我暂时只学了一种,也就是单例模式,什么是单例模式,就是当用户有进行输入数据进行获取对象的操作时,产生不同地址的对象,单用户不输入任何数据时,每次拿到的对象都是同一个。

    单例模式一共有四种方式实现。

    方式一:通过类的绑定方法

    class Sql():
        _instance=None
        def __init__(self,port,host):
            self.port=port
            self.host=host
        @classmethod
        def get_sigoleton(cls):
            import settings
            if not cls._instance:
                cls._instance = cls(settings.PORT, settings.HOST)
            return cls._instance
    
    

    每次调用get_sigoleton 拿到的对象都是同一个

    s1=Sql.get_sigoleton()

    s2=Sql.get_sigoleton()

    s3=Sql.get_sigoleton()

    方式二:通过装饰器来实现

    def get_sigoleton(cls):
        #cls就是Sql这个类
        import settings
        _instance=cls(settings.PORT, settings.HOST)
        # _instance=Sql(settings.PORT, settings.HOST)
    
        def wrapper(*args,**kwargs):
            if len(args)!=0 or len(kwargs)!=0:
                #表示传了参数,生成新对象
                res=cls(*args,**kwargs)
                return res
            else:
                return _instance
        return wrapper
    
    @get_sigoleton    #会把下面的Sql当中参数传入,相当于Sql=get_sigoleton(Sql)
    class Sql():
        def __init__(self,port,host):
            self.port=port
            self.host=host
    
    s1=Sql()
    s2=Sql()
    s3=Sql('33306','192.168.1.1')
    
    print(s1)
    print(s2)
    print(s3)
    
    

    <__main__.Sql object at 0x0000024B13944160>
    <__main__.Sql object at 0x0000024B13944160>
    <__main__.Sql object at 0x0000024B13944438>

    方式三:通过元类来实现

    class Mymeta(type):
        def __init__(self,name,bases,dic):
            #self 是Sql类
            import settings
            #把实例化好的对象,放到了类的名称空间
            self._instance=self(settings.PORT, settings.HOST)
        def __call__(self, *args, **kwargs):
            #self是谁?是Sql类
            if len(args)!=0 or len(kwargs)!=0:
                obj=object.__new__(self)
                obj.__init__(*args, **kwargs)
                return obj
            else:
                return self._instance
    
    class Sql(metaclass=Mymeta):    #相当于 Sql=Mymeta(name,bases,dic)   这个会调用 Mymeta的__init__  在里面已经向类的名称空间放了一个对象
        def __init__(self,port,host):
            self.port=port
            self.host=host
    
    print(Sql.__dict__)
    s1=Sql()
    #调用元类的__call__
    s2=Sql()
    s3=Sql('33306','192.168.1.1')
    print(s1)
    print(s2)
    print(s3)
    

    settings.py

    PORT=3306
    HOST='127.0.0.1'
    

    方法四:通过模块倒入(python的模块是天然的单例)

    def test():
        from sigonleton import s1
        print(s1.port)
        print(s1)
    def test2():
        from sigonleton import s1 as s2
        print(s2)
    
    test()
    test2()
    from sigonleton import s1
    from sigonleton import Sql
    s2=Sql(3306,'192.168.1.1')
    print(s1)
    print(s2)
    

    sigonleton.py

    import settings
    class Sql():
        def __init__(self,port,host):
            self.port=port
            self.host=host
    
    s1=Sql(settings.PORT,settings.HOST)
    

    其实写法有千千万种,不过以上四种是总的类型,虽然分成了四种类型,但是它们的本质都是一样的,都是先生成一个对象,然后把这个对象暂存起来,当用户没有任何输入的时候就返回这个对象,有输入的时候就返回新的对象。

    结束,最近没力气了,被磨平了棱角了,没心情,没力气放图,没精力说骚话了。

  • 相关阅读:
    JavaScript中的valueOf与toString方法
    CSS的历史与工作原理
    Javascript让你的网页标题飘动起来
    getElementsByClassName的原生实现
    JavaScript去除空格trim()的原生实现
    JavaScript截取中英文字符串
    Keras函数式API介绍
    R语言kohonen包主要函数介绍
    在Shell直接运行Python命令并显示
    GitHub Pages
  • 原文地址:https://www.cnblogs.com/chanyuli/p/11460981.html
Copyright © 2020-2023  润新知