zoukankan      html  css  js  c++  java
  • day 30 元类更深认识,单例

    元类更深认识

    #type只传一个参数有什么用?
    打印对象的类型

    #class 底层原理,通过type类来实例化得到类
    def __init__(self,name):
    self.name=name
    Person=type('Person',(object,),{'x':1,'__init__':__init__})
    p=Person('lqz')
    print(Person.__dict__)
    print(p.__dict__)
    print(p.x)
    等同于
    class Person(object):
    x=1
    def __init__(self, name):
    self.name = name
    p=Person('lqz')
    print(Person.__dict__)
    print(p.__dict__)
    print(p.x)


    #exec 执行字符串的代码,当成python解释器

    ss='''
    x=1
    print(x)
    '''
    g={}
    l={}
    exec(ss,g,l)
    print(l)


    #自定义元类:继承type
    class Mymeta(type):
    def __init__(self,name,bases,dic):
    #self 是Person 这个类(对象)
    #在这个位置,其实self也就说Person这个类,内部已经有东西了,名称空间已经有东西了 就是dic
    #所以在这个地方,可以通过dic来判断名称空间
    #也可以直接通过self.__dict__/self.属性 来判断
    a=dic.get('name')
    if not a :
    raise Exception('没有name属性,不能创建')
    # def __call__(self, *args, **kwargs):
    # pass

    class Person(metaclass=Mymeta): #等同于Person=Mymeta('Person',(object,),{...}) Mymeta类实例化,会把三个参数传到Mymeta的__init__方法中
    def __init__(self,name):
    self.name=name
    raise Exception('就不让你创建')


    p=Person('lqz') #自动触发Person类__init__的执行
    总结:可以通过自定义元类,重写__init__方法来控制类的产生


    #通过元类控制类的调用过程,实例化产生对象的过程

    class Mymeta(type):
    def __call__(self, *args, **kwargs):
    #该方法必须返回一个对象(类对象),这个地方返回什么 p=Person('lqz') p就是什么
    #返回一个真正的Person类的对象
    #第一步:产生一个空对象
    object.__new__(self) 传一个参数,传类,就会产生一个该类的空对象
    #obj是Person类的空对象
    obj=object.__new__(self)
    print(self.__new__ is object.__new__) # True

    #第二步:初始化该对象,把初始值放到对象中
    obj是Person类的空对象 obj.__init__ 调用自己的绑定方法,也就说Person类中写的__init__方法
    obj.__init__(*args, **kwargs)
    #还可以类来调用
    Person.__init__(obj,*args, **kwargs)
    self.__init__(obj,*args, **kwargs)
    print(obj.name)
    #第三步:把该对象返回
    return obj

    class Person(metaclass=Mymeta):
    # class Person():
    def __init__(self,name):
    self.name=name
    def __call__(self, *args, **kwargs):
    print('xxx')


    p=Person('lqz')
    print(p.name)
    print(p)
    # 原来的理解Person('lqz') 会调用Person类的__init__的方法
    # 这个位置会调用元类的__call__方法,所以在__call__方法中调用了Person __init__方法,来完成对象的初始化
    p()会调类中的__call__方法


    模板:控制对象的产生
    class Mymeta(type):
    def __call__(self, *args, **kwargs):
    obj=object.__new__(self)
    obj.__init__(*args, **kwargs)
    return obj

    class Person(metaclass=Mymeta):
    def __init__(self,name):
    self.name=name
    def __call__(self, *args, **kwargs):
    print('xxx')

    p=Person('lqz')




    加深部分
    object.__new__

    class Person():
    def __init__(self,name,age):
    print('__init__')
    self.name=name
    self.age=age
    def __new__(cls, *args, **kwargs):
    print('__new__')
    #生成一个Person类的空对象
    return object.__new__(cls)

    p=Person('lqz',19)
    print(p)

    object.__new__ 传哪个类就得到哪个类的空对象
    p=object.__new__(Person)
    print(p)

    __new__和__init__的区别
    __new__ 创建空对象
    __init__ 初始化空对象

    object.__new__(Person) :生成Person类的对象 空的
    type.__new__(cls,name,bases,dic) :生了cls这个类对象,里面有东西
    元类中
    __init__:控制类的产生,在__new__之后
    __call__:对着对象的产生
    __new__:控制类产生最根上,其实本质最根上也不是它,是type的__call__,但是我们控制不了了
    #
    class Mymeta(type):
    def __init__(self,name,bases,dic):
    #self 是Person类,Person类中有名称空间之类的了
    # print('xxxxxxx')
    # print(name)
    # print(bases)
    # print(dic)
    # self.name='xxxxxxx'
    def __new__(cls, name,bases,dic):
    # print(name)
    # print(bases)
    # print(dic)
    #产生空对象(空类),在这里面生成的并不是空类,是有数据的类了
    #如何完成类的初始化,并且把name,bases,dic这些东西放入
    # return type.__new__(cls,name,bases,dic)
    dic2={'attr':{}}
    for k,v in dic.items():
    #加入这一句,类名称空间中带__的就不会放到attr中
    if not k.startswith('__'):
    dic2['attr'][k]=v
    print('-------',dic2)
    return type.__new__(cls,name,bases,dic2)


    class Person(metaclass=Mymeta): # Person=Mymeta(name,bases,dic) 调用type的__call__,--》内部调用了Mymeta.__new__,--》又调Mymeta的__init__
    school='oldboy'
    age=10
    def __init__(self,name,age):
    self.name=name
    self.age=age


    print(Person.__dict__)
    print(Person.attr['school'])
    # p=Person('nick'

    单例
    设计模式 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()

    print(s1)
    print(s2)
    print(s3)
    s4=Sql('33306','192.168.1.1')
    print(s4)

    第二种方法:通过装饰器
    当用户输入端口和地址,实例化产生新对象
    当用户不输入端口和地址,每次拿到的对象,都是同一个
    def get_sigoleton(cls):
    #cls就是Sql这个类
    import settings
    _instance=cls(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

    # def get_sigoleton(cls):
    # _instance=None
    # def wrapper(*args,**kwargs):
    # if len(args)!=0 or len(kwargs)!=0:
    # #表示传了参数,生成新对象
    # res=cls(*args,**kwargs)
    # return res
    # else:
    # import settings
    # nonlocal _instance
    # if not _instance:
    # _instance=cls(settings.PORT, settings.HOST)
    # return _instance
    # return wrapper

    @get_sigoleton #会把下面的Sql当中参数传入,相当于:Sql=get_sigoleton(Sql)
    class Sql():
    def __init__(self,port,host):
    self.port=port
    self.host=host
    # Sql=get_sigoleton(Sql)
    s1=Sql()
    s2=Sql()
    s3=Sql('33306','192.168.1.1')
    s4=Sql('33306','192.168.1.1')
    print(s1)
    print(s2)
    print(s3)


    第三种,通过元类
    当用户输入端口和地址,实例化产生新对象
    当用户不输入端口和地址,每次拿到的对象,都是同一个

    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)



    第四种方法,通过模块导入(python的模块是天然的单例)

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

    s1=Sql(settings.PORT,settings.HOST)


    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)
  • 相关阅读:
    python 获取当前时间
    PHP基础
    python 编码
    系统分区表 MBR GPT
    python mysql like查询的写法
    JSP JavaBean
    jsp MVC
    python 正则例子
    Java版A星算法
    linux 部署subversion独立服务器
  • 原文地址:https://www.cnblogs.com/wwei4332/p/11460427.html
Copyright © 2011-2022 走看看