• python基础语法18 类的内置方法(魔法方法),单例模式


    类的内置方法(魔法方法):

      凡是在类内部定义,以__开头__结尾的方法,都是类的内置方法,也称之为魔法方法。

      类的内置方法,会在某种条件满足下自动触发。

    内置方法如下:
      __new__: 在__init__触发前,自动触发。 调用该类时,内部会通过__new__产生一个新的对象。
      __init__: 在调用类时自动触发。 通过产生的对象自动调用__init__()

    class Demo(object):
        # 条件: __new__: 在__init__触发前,自动触发。
        def __new__(cls, *args, **kwargs):
            print('此处是__new__方法的执行')
            # python内部通过object调用内部的__new__实现产生一个空的对象  ---> 内存地址
            return object.__new__(cls,*args,**kwargs)
    
        # 条件: __init__: 在调用类时自动触发。
        def __init__(self):
            print('此处是__init__方法的执行')
    
    demo_obj=Demo()
    '''result:
    此处是__new__方法的执行
    此处是__init__方法的执行
    '''

    __getattr__: 在 “对象.属性” 获取属性时,若 “属性没有” 时触发。

    class Demo(object):
        # __getattr__: 在 “对象.属性” 获取属性时,若 “属性没有” 时触发。
        def __getattr__(self, item):
            print('此处是__getattr__方法的执行')
            print(item)
         # return 想要返回的值
    return '别闹,没有该属性' demo_obj=Demo() print(demo_obj.x) ''' 此处是__getattr__方法的执行 x 别闹,没有该属性 ''' demo_obj.x=3 print(demo_obj.x) # 3
    条件: __getattribute__: 在 “对象.属性” 获取属性时,无论 "属性有没有" 都会触发。
    注意: 只要__getattr__ 与 __getattribute__ 同时存在类的内部,只会触发__getattribute__。
    class Demo(object):
        # 条件: __getattribute__: 在 “对象.属性” 获取属性时,无论 "属性有没有" 都会触发。
        def __getattribute__(self, item):
            print('此处是__getattribute__方法的执行')
            print(item,'<-----打印属性名字')
            # return self.__dict__[item]    # 注意: 此处不能通过 对象.属性,否则会产生递归调用,程序崩溃
            # return getattr(self.item)   # getattr: 内部调用了 ----> __getattribute__, 也会递归
    
    # 注意: 只要__getattr__ 与 __getattribute__ 同时存在类的内部,只会触发__getattribute__。
    demo_obj=Demo()
    print(demo_obj.x)
    '''
    此处是__getattribute__方法的执行
    x <-----打印属性名字
    None
    '''
    demo_obj.x=3
    print(demo_obj.x)   # 3
    '''
    此处是__getattribute__方法的执行
    x <-----打印属性名字
    None
    '''

    条件: 当 “对象.属性 = 属性值” , 添加或修改属性时触发

    class Demo(object):
        # 条件: 当 “对象.属性 = 属性值” , 添加或修改属性时触发
        def __setattr__(self, key, value):  # key---> 对象.属性名  value ---》 属性值
            print('# key---> 对象.属性名  value ---》 属性值')
            print(key,value)
            #self.key=value  #产生递归
    
            self.__dict__[key]=value    # 此处是对 对象的名称空间 ---》 字典进行操作
    
    demo_obj=Demo()
    # print(demo_obj.x)
    
    demo_obj.x=3
    '''
    # key---> 对象.属性名  value ---》 属性值
    x 3
    '''
    print(demo_obj.x)   # 3

    条件: 在调用对象 “对象 + ()” 时触发。

    class Demo(object):
        # 条件: 在调用对象 “对象 + ()” 时触发。
        def __call__(self, *args, **kwargs):
            print('此处是__call__方法的执行')
            #调用对象时返回的值
            return [1,2,3,4,5]
    
    demo_obj=Demo()
    res=demo_obj()  # 此处是__call__方法的执行
    print(res)  # [1, 2, 3, 4, 5]

    条件: 在打印对象时触发。

    class Demo: 
       # 条件: 在打印对象时触发。
        #注意:该方法必须要有一个"字符串"返回值
        def __str__(self):
            print('此处是__str__方法的执行')
            return '111'
    
    demo_obj=Demo()
    print(demo_obj)
    '''
    此处是__str__方法的执行
    111
    '''

    在对象通过 “对象[key]” 获取属性时触发。

    class Demo:
        # 在对象通过 “对象[key]” 获取属性时触发。
        def __getitem__(self, item):
            print('此处是__getitem__方法的执行')
            print(item)
            return self.__dict__[item]
    
    demo_obj=Demo()
    demo_obj.x=10
    res=demo_obj['x']
    '''
    此处是__getitem__方法的执行
    x
    '''
    print(res)  # 10

    在对象通过 “对象[key]=value值” 设置属性时触发。

    class Demo:
        # 在对象通过 “对象[key]=value值” 设置属性时触发。
        def __setitem__(self, key, value):
            print('此处是__setitem__方法的执行')
            print(key,value)
            self.__dict__[key] = value
    
    demo_obj=Demo()
    demo_obj['y']=300
    '''
    此处是__setitem__方法的执行
    y 300
    '''
    print(demo_obj.y)  # 10

    单例模式:

      指的是在确定 "类中的属性与方法" 不变时,需要反复调用该类,
      产生不同的对象,会产生不同的内存地址,造成资源的浪费。

      让所有类在实例化时,指向同一个内存地址,称之为单例模式。 ----> 无论产生多个对象,都会指向 单个 实例。

      - 单例的优点:
        节省内存空间。

    #反面案例
    class
    Foo: def __init__(self,x,y): self.x=x self.y=y foo_obj1=Foo(10,20) print(foo_obj1) # <__main__.Foo object at 0x0000000001D85CF8> foo_obj2=Foo(10,20) print(foo_obj2) # <__main__.Foo object at 0x00000000021BCC88>

    单例模式: (面试让你手撸,一定要背下来。)
    1.通过classmethod
    2.通过装饰器实现
    3.通过__new__实现
    4.通过导入模块时实现
    5.通过元类实现。

    classmethod实现

    class MySQL:
        # 一个默认值,用于判断对象是否存在, 对象不存在证明值是None
        # __instance是类的属性,可以由类来调用
        __instance = None  # ---》 若已有对象会返回给它 ---》 obj
        # __instance = obj
    
        def __init__(self,host,port):
                self.host=host
                self.port=port
    
        @classmethod
        def singleton(cls,host,port):   # 单例方法 ---》 类方法
    
            # 判断__instance中若没有值,证明没有对象
            if not cls.__instance:
                # 产生一个对象并返回
                obj=cls(host,port)
                # None ---> obj
                cls.__instance=obj
    
            # 若__instance中有值,证明对象已经存在,则直接返回该对象
            return cls.__instance
        def start_mysql(self):
            print('启动mysql')
        def close(self):
            print('关闭mysql')
    obj1=MySQL.singleton('180.101.49.12',443)
    print(obj1) # <__main__.MySQL object at 0x000000000255D160>
    obj2=MySQL.singleton('180.101.49.12',443)
    print(obj2) # <__main__.MySQL object at 0x000000000255D160>

    或者:

    class Borg:
        def __new__(cls, *args, **kwargs):
            if not hasattr(cls,'_instance'):
                ob = super(Borg,cls)
                cls._instance = ob.__new__(cls,*args,**kwargs)
            return cls._instance
    
            # if not hasattr(cls,'_instance'):
            #     # 造一个空对象
            #     cls._instance = object.__new__(cls)
            # return cls._instance
    
    class MyClass(Borg):
        def __init__(self):
            self.a = 1
    
    obj1 = MyClass()
    obj2 = MyClass()
    print(obj1)
    print(obj2)
    View Code

     __new__实现

    # __new__创造单例模式
    class Singleton:
        __instance = None
        @classmethod    # 此处可以不加此装饰器,__new__默认为类方法
        def __new__(cls, *args, **kwargs):
            if not cls.__instance:
                # 造一个空对象
                cls.__instance = object.__new__(cls)
            return cls.__instance
    
    obj1= Singleton()
    obj2= Singleton()
    obj3= Singleton()
    print(obj1) # <__main__.Singleton object at 0x000000000255D048>
    print(obj2) # <__main__.Singleton object at 0x000000000255D048>
    print(obj3) # <__main__.Singleton object at 0x000000000255D048>

    装饰器实现

    def singleton(cls):
        _instance = {}  #此处必须为可变类型
        def inner(*args,**kwargs):
            if cls not in _instance:
                _instance[cls] = cls(*args,**kwargs)
            return _instance[cls]
        return inner
    
    @singleton
    class Father:
        pass
    
    print(Father()) # <__main__.Father object at 0x0000000001DA5D68>
    print(Father()) # <__main__.Father object at 0x0000000001DA5D68>

    为什么不能用_instance=None赋值说明

    def singleton(cls):    
        _instance = None  #此处必须为可变类型
        def inner(*args,**kwargs):
            if not _instance: # 报错,因为_instance优先指向内置空间的对象,也就是下面的_instance,没有就报错,无解!此处必须用字典等方法
                _instance = cls(*args,**kwargs) 
            return _instance
        return inner
    
    @singleton
    class Father:
        pass
    
    print(Father()) 
    print(Father()) 

    模块导入

    # 以下为singleton模块
    class SingletonCls:
        pass
    obj = SingletonCls()
    
    # 以下为测试程序
    from singleton模块 import obj
    print(obj)
    print(obj)
  • 相关阅读:
    Adobe PS
    深入学习二叉树(04)平衡二叉树
    深入学习二叉树(03)二叉查找树
    C 知识点
    实战【docker 镜像制作与使用】
    从0到1了解 CI/CD
    单例模式的几种实现方式,使用场景以及优缺点
    设计模式之策略模式浅谈以及简单例子
    WPF几种渐变色
    Linq学习以及简单用法
  • 原文地址:https://www.cnblogs.com/ludingchao/p/11959022.html
Copyright © 2020-2023  润新知