• 面向对象的进阶(item系列,__new__,__hash__,__eq__)


     

     

     

    面向对象的进阶(item系列,__new__,__hash__,__eq__)

    一、item系列

    getitem、setitem、delitem(操作过程达到的结果其实就是增删改查)
    class Foo:
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def __getitem__(self, item):  # 与f['xx']形式对应
            if hasattr(self, item):
                return self.__dict__[item]
    
        def __setitem__(self, key, value):  # 与f['xx']='ss'形式对应
            self.__dict__[key] = value
    
        def __delitem__(self, key):  # 与del f['xx']形式对应
            del self.__dict__[key]
    
    f = Foo('egon',30,'')
    print(f['name'])
    #  f['name']---对象['xx']这种形式就会触发前面的__getitem__方法,将name就传给了item
    #  支持以这样的方式取得了对象的属性name,正常的是f.name取到属性
    
    f['hobby'] = ''
    # 新增加的key和value,触发__setitem__方法,将对应的属性和值放入原本的字典中
    print(f['hobby'], f.hobby)
    # 以f['hobby']这样的方式取到新增的属性,原本正常取值f.hobby
    
    # del f.hobby  # 正常的删除方式
    # print(f.hobby)  # 此时会报错,显示:AttributeError: 'Foo' object has no attribute 'hobby'
    
    del f['hobby']
    # 如果执行到这步,就会显示:AttributeError: __delitem__,显示没有这个方法
    # 这个删除方式就触发__delitem__方法,前面类里面就必须得有定义该方法
    print(f.__dict__)  # 字典里面就没有hobby的属性了

    运行结果:

    C:Users3-2PycharmProjectsuntitledvenvScriptspython.exe C:/Users/3-2/PycharmProjects/untitled/面向对象进阶.py
    egon
    男 男
    {'sex': '', 'age': 30, 'name': 'egon'}
    
    Process finished with exit code 0
    这种用中括号就可以直接调的方式,比如用字典,列表的实现过程,就是内部存在了item系列这个机制的原因
    这种用中括号就可以直接调的方式,比如用字典,列表的实现过程,就是内部存在了item系列这个机制的原因
    object原生支持__delattr__所以才可以直接del f.hobby而不报错,但是del f['hobby']得通过自己实现,
    所以当类方法里面没有__delitem__的时候就会报错
    二、__new__
    __init__:初始化方法
    __new__:构造方法,创建一个对象。self就是__new__构造出来的,即__new__方法是self产生的机制
    平时是不需要用到执行__new__方法的,以下例子只是简单说明它是怎么用的:
    class A:
        def __init__(self):
            self.x = 1
            print('in init function')
        def __new__(cls, *args, **kwargs):
            # 传入一个默认参数cls,执行__new__方法前还没有self,所以只能传一个类进来
            print('in new function')
            return object.__new__(A,*args,**kwargs)
            # object.__new__创造了一个新的对象,然后将这个对象传给self的位置,所以当执行self的时候就可以使用对象了
    
    a = A()  # 实例化,会先执行__new__方法,再执行 __init__方法

    运行结果:

    in new function
    in init function
    
    Process finished with exit code 0
    一个典型的设计模式(23种):单例模式
    单例模式:一个类始终只有一个实例;当第一次实例化这个类的时候就创建一个实例化的对象;当之后再来实例化的时候,
    就会用之前创建的对象
    # 实现单例模式的例子:

    class A: __instance = False # 私有的静态变量 不希望别人可以使用,必须得经过自己的设置 def __init__(self,name,age): self.name = name self.age = age def __new__(cls, *args, **kwargs): if cls.__instance: # 如果为真就执行下面代码,否则执行后面的代码 # 第二次进来的时候就符合这个了 return cls.__instance # 第二次进来就直接将之前创建的对象返回给self了 cls.__instance = object.__new__(A) # 因为第一次进来的时候就是__instance = False,所以执行这行代码代码 # 用object.__new__创建一个类A的新的对象,并且赋值给 cls.__instance return cls.__instance # 这里就是将新建的对象return回去 egon = A('egg',38) # 真正能实例化对象并且占用内存的是object里面的self,但是这里使用的对象始终是object.__new__创建的, # 因为自己就有对象了,就不会去使用object里面的了 # 反正能够实现单例化的原因是__new__方法的使用 egon.cloth = '小花袄' nezha = A('nazha',25) nezha.shoes = '小白鞋' print(nezha) print(egon) # 执行到这里根据运行结果显示内存地址是同一个,也就是说第二次实例化的时候是在对第一个实例化后的 # 对象进行操作的,而并没有再次创建另一个占内存的对象,如果第二次实例化传的参数和原对象一致, # 参数值就会进行覆盖,如果第二次实例化传的参数只是原属性的一部分,则相同的覆盖,原来的继续会 # 在表现在现有对象中 print(nezha.name) print(egon.name) # 执行到这里原来egon的名字已经被nezha覆盖了 print(nezha.cloth) # 执行到这里原来egon的cloth会继续穿在nezha上

    运行结果:

    <__main__.A object at 0x0000025C0C2293C8>
    <__main__.A object at 0x0000025C0C2293C8>
    nazha
    nazha
    小花袄

    三、__hash__

    # 在没有定义__hash__方法的时候,hash都是针对内存地址的,而不是针对对象属性,内存地址不一样,hash的结果也不一样 

    class A:
      def __init__(self,name,sex):
        self.name
    = name
    a
    = A('egn','')
    b
    = A('egon','nv')
    print(hash(a))
    print(hash(b))

    运行结果:

    154259419512
    154259419617
    # 定义了—__hash__方法后,属性不同hash值也会不同,属性相同hash值也会相同:
    class A:
        def __init__(self,name,sex):
            self.name = name
            self.sex = sex
        def __hash__(self):
            return hash(self.name+self.sex)
    
    a = A('egon','')
    b = A('egon','')
    c = A('egon','nv')
    print(hash(a))
    print(hash(b))
    print(hash(c))

    运行结果:

    8385798543724353936
    8385798543724353936
    -7270162062837990016

    四、__eq__

    没有__eq__方法的时候,两者比较是比较内存地址:
    class A:
        def __init__(self,name):
            self.name = name
    
    obj1 = A('egg')
    obj2 = A('egg')
    print(obj1 == obj2)
    # 没有定义__eq__方法的时候,比较时候默认比较内存地址,上面两个内存地址是不一样的

    运行结果:

    False
    # 定义__eq__方法时可以自己设定执行内容,‘==’触发的_eq_方法
    class A:
        def __init__(self,name):
            self.name = name
    
        def __eq__(self, other):
            if self.name == other.name:
                return True
            else:
                return False
    
    obj1 = A('egg')
    obj2 = A('egg')
    obj3 = A('EGG')
    print(obj1 == obj2)  # 等号触发的__eq__
    print(obj2 == obj3)  # 等号触发的__eq__
    

    运行结果:

    True
    False
    
    Process finished with exit code 0
  • 相关阅读:
    Basic GC Tuning
    程序员如何少走弯路,更好的提升技术。
    WPF 多线程
    IOC
    一句话概括WPF知识点
    WPF数据绑定 Binding
    WPF命令
    WPF依赖属性
    WPF路由事件
    WPF绘图和动画
  • 原文地址:https://www.cnblogs.com/wxm422562/p/12031164.html
Copyright © 2020-2023  润新知