• 面向对象高级C(元类补充及单例模式)


    元类有关知识点补充

    
    #类的名称空间
    
    类的名称空间不能用类似字典的方法修改,例如School类里面有name属性xxx,那么我用School.__dict__[‘name’] = ‘yyy’就会报错“TypeError: 'mappingproxy' object does not support item assignment”原因是类的名称空间和对象的名称空间不一样,后者是一个`a plain dict`,就是普通的字典,而后者是一个`mappingproxy`,不可映射类型,是不含__setattr__方法的 
    
    #class底层原理的实现
    Person = type('Person', (object,), {})
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
    p = type('Person', (object, ), {'x': 1, '__init__': __init__})
    p1 = p('ljy', 19)
    
    class Person:
        x = 1
        def __init__(self, name, age):
            self.name = name
            self.age = age
    p = Person
    q = p('ljy', 18)
    print(p.__dict__)
    print(q.__dict__)
    
    
    # exec : 执行字符串的代码,当成python解释器
    
    ss = '''
    global x  #全局变量要加在最前面
    x = 1
    y = 2
    z = 3
    
    
    print(y)
    
    '''
    g = {}
    l = dict()
    exec(
        ss, g, l
    )
    
    print(print(1))  #会打印出1,和None,因为print的返回值是None
    
    print(l) # 先把y=2打印出来,然后再打印局部变量的字典
    print(g) #打印全部变量的字典,里面包含x:2,在字典的末尾
    
    # 自定义元类,继承type
    
    class Mymeta(type):
        def __init__(self, name, bases, dic):
            #self 是Person这个类(对象)
            #在这个位置,其实self也就是Person这个类,
            #内部已经有东西了,名称空间里面的东西在__new__
            #可以通过过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,), {...})
    Mymete类实例化,会把三个参数传到Mymeta的__init__方法中
    '''
    
    class PersonException(metaclass=Mymeta):
            name = 'lae'#加上这句话,类的名称空间里面就有name属性了
        def __init__(self,name,age):
            self.name = name
            self.age = age
    #通过元类控制类的调用过程,实例化产生对象的过程
    p1 = PersonException(18)
    #因为类中没有name属性,所以会抛异常‘没有name属性,不能创建’
    
    class Person():
        def __init__(self, name):
            self.name = name
            raise Exception('就不让你创建')
    
    p = Person('nick')
    # 自动触发Person类__init__的执行,
    # 抛异常:就不让你创建
    # 总结:可以通过自定义元类,重写__init__方法来控制类的产生
    
    
    class Mymeta(type):
        def __init__(self, name, bases, dic):
            if 'name' not in dic.keys():
                raise Exception('没有name属性,不能创建')
            else:
                self.__dict__['name'] = 'nick'
                '''
                会报错TypeError: 'mappingproxy'
                object does not support item assignment
                也就是类的名称空间是一个字典,但是不能对里面的值进行修改
                (错误详情见下一篇博客整理)
                '''
    
    class Person(metaclass=Mymeta):
        name = 'ljy'
        def __init__(self, name, age):
            self.name = name
            self.age = age
    p = Person('ljy', 19)
    print(p.name)
    print(Person.name)
    
    
    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,说明
            # self.__new__就是object.__new__
    
            #第二步:初始化该对象,把初始值放到对象中
            #obj是Person类的空对象,obj.__init__ 调
            # 用自己的绑定方法,也就是说Person类中写的
            # __init__方法
            obj.__init__(*args, **kwargs)
            #还可以类来调用
            Person.__init__(obj, *args, **kwargs)
            self.__init__(obj, *args, **kwargs)
            print(obj.name) #打印出来lqz
            #第三步:把该对象返回
            return obj
    class Person(metaclass=Mymeta):
        def __init__(self, name):
            self.name = name
        def __call__(self, *args, **kwargs):
            print('XXXX')
    p = Person('lqz')
    print(p.name)
    print(p)
    

    单例模式

    一共有23中设计模式,单例模式是指整个过程中只有一个实例,所有生成的实例都指向同一快内存空间

    PORT = '192.384.28.2'
    HOST = 2728
    #方式一:通过类的绑定方法
    #当用户不输入端口和地址,每次拿到的对象都是同一个。
    class Sql:
        _instance = None
    	def __init__(self, port, host):
            self.port = port
            self.host = host
    	@classmethod
        def singleton(cls):
            if not cls._instance:
                cls._instance = cls(PORT, HOST)
            return cls._instance
    p1 = Sql.singleton()
    p2 = Sql.singleton()
    p3 = Sql('33306','192.168.1.1')#当用户输入端口和地址,实例化产生新对象
    print(p1)
    print(P2)
    print(p3)
    '''
    <__main__.Sql object at 0x00000225BDBABFD0>
    <__main__.Sql object at 0x00000225BDBABFD0>
    <__main__.Sql object at 0x00000225BDBABF98>
    '''
    
    ##方式二:通过装饰器
    #不传参,实例化对象内存地址相同
    def get_singleton(cls):
        _instance = None
        def inner(*args, **kwargs):
            if len(args)!=0 or len(kwargs)!=0:
                res = cls(*args, **kwargs)
                return res
            else:
                nonlocal _instance
                if not _instance:
                    _instance = cls(PORT, HOST)
                return _instance
        return inner
    
    @get_singleton
    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 0x00000185E9601978>
    <__main__.Sql object at 0x00000185E9601978>
    <__main__.Sql object at 0x00000185F04CE2B0>
    '''
    
    #方法三:用自定义元类
    #不传参,实例化对象内存地址相同
    class Mymeta(type):
    	def __init__(cls, name, bases, dic):
            cls._instance = cls(PORT, HOST)
        def __call__(cls, *args, **kwargs):
            if len(args)!=0 or len(kwargs)!=0:
                obj = object.__new__(cls)
                obj.__init__(*args, **kwargs)
                return obj
            else:
                return cls._instance
    class Sql(metaclass=Mymeta):
        def __init__(self, port, host):
            self.port = port
            self.host = host
    p1 = Sql()
    p2 = Sql()
    p3 = Sql(8001, '178.23.4.53')#传参,实例化对象地址不同
    print(p1)
    print(p2)
    print(p3)
    """
    <__main__.Sql object at 0x000002469196E320>
    <__main__.Sql object at 0x000002469196E320>
    <__main__.Sql object at 0x000002469196E438>
    
    """
    
    #方法四:导入模块
    #singleton.py
    class Sql():
        def __init__(self, port, host):
            self.port = port
    		self.host = host
            
    s1 = Sql(PORT, HOST)
            
    #test.py
    def test1():
        from singleton import s1
        print(s1)
    def test2():
        from singleton import s1
        print(s1)
    
    test1()
    test2()
    from singleton import s1
    from singleton import Sql
    s2 = Sql(477, '182.22.2.2')
    print(s1)
    print(s2)
    
    '''
    <sigonleton.Sql object at 0x000001B0456F53C8>
    <sigonleton.Sql object at 0x000001B0456F53C8>
    <sigonleton.Sql object at 0x000001B0456F53C8>
    <sigonleton.Sql object at 0x000001B045B3F080>
    
    '''
        
        
    
  • 相关阅读:
    【重大更新】Qlik Sense September 2018重磅发布(附下载)
    sharepoint多个NLB的web前段如何进行文件同步?
    通过组策略实现Firefox自动以当前域账号登录MOSS站点---(原创)
    EWS API 2.0读取日历信息-读取内容注意事项
    Dotfuscator混淆加密
    如何:在 SharePoint 中创建外部列表
    java学习笔记—HTTP协议(10)
    java学习笔记—Tomcat(9)
    java学习笔记DOM4J解析(7)
    php中mvc框架总结1(7)
  • 原文地址:https://www.cnblogs.com/michealjy/p/11469311.html
Copyright © 2020-2023  润新知