之前学了__dir__,那么其他的dunder的方法到底有什么用
首先看创建和初始化和销毁,实例化用的是__new__这个方法,初始化在获得实例之后,需要调用初始化方法__init__,调用之后相当于在做出厂配置,拿到实例之后就可以开始使用,实例化和初始化,在创建实例的时候一并做了
修改成这样,竟然实例化成功了
new方法注释掉就不行了
到底有没有实例化成功,打印看一下,提示 nonetype对象没有__dict__方法
代表这里是个none
就是因为这里,因为这个函数没有返回值
init是不能有返回值的,只能return none,否则直接抛出异常
空的元组,空的字典,都打印出来了
没有看到波浪线说明这个函数根本没有调用
需要拿到实例,返回实例,才能做出厂配置,init,实例是类型加括号调用出来的
执行一下,显示递归了recursionerror
实例化不停的new,所有绝对不能这么写,只要实例化必须先调用new求父类即可,找到object来帮助实例化
为什么后面要加cls,要看看new里面究竟是什么
是个静态方法,第一参数需要把类型送进去
这样就成功了
new方法是用来做实例化的,new方法要是些了,一定要return,如果return none就肯定不会调用init
绝对不允许下面这么用,属于自己调用自己
string对象没有字典
应该返回一个本类型的实例,abc相当于str类型的实例,如果不返回本类型的实例,init就不会理你
必须返回一个基类构成的实例,就会调用它的init方法
如果返回不是本类型的实例,就不理你
new方法里面必须返回本类的实例,但是要调基类的构造方法,说到底是调用object的构造方法,其实就是staticmethod
这个new方法写或者不写就是staticmethod,所以一般不定义,知道做什么即可
通过这个知道谁先执行谁后执行,new方法调用,返回一个这个类型的实例,然后调用实例的初始化函数,初始化函数不允许return值
然后把你得到的实例,交给这个变量
用到地方不多
hash
hash值是一个门牌号码
如果给一个字符串,会对这个字符串进行求值,得到这个hash值,把数据存到对于hash值的房间中去
这里的门牌号必须是整型的,所以给了abc不行
先求了hash值,再求hash,这样还是一样的
hash计算,只要小小的变化,就会产生巨大的变化
但凡不是整型,每一次的值都是在变化,是为了本次以后无法猜测,引入了随机数
但是MD5之类的可以选择是否加入随机数
现在这么改
初始化两次,恒定是1
第三个{}set集合是按照什么来去重的
现在发现只有hash是去不了重的,作为key来讲必须是可hash,hash值相同代表这两个对象应该进统同一个房间(并不代表两个人是同一个人),去重跟不去重跟hash有关系,但是一定要先进一个房间才能去重
去重跟另外的方法有关系,eq
只剩下一个了,因为return true 恒等
两人首先进同一房间,才决定要不要去重,首先需要key相同
key如果不相同,计算的hash值由很大不同
hash算法,每次送的值一样,本次求的值是不变的,就是幂等性,x如果不一样,算出来的就天差地别,散列值散的很大,
不太的hash算法,hash冲突是不一样的,不同的x求得同样的hash值,可能较小
当数据规模超出hash空间能描述的范围,再往里面塞数据,一定会出现hash冲突,不同的x可能算出同样的门牌号码,看到里面是数据如果相同,就会进行去重
每一种hash算法,hash冲突是一定会出现的
**如果是1,tom,jerry的返回值的hash值就肯定是1 **
调用eq方法,查看两个值是否相同,相同的由两种判断,一种是is(跟内存地址有关),一种是==,跟==有关,
放到set里面去,就hash冲突了,就需要看看内容是否相同,调用eq方法,但是恒等true,怎么比这两个都算相等,则去除其中一个
只要是hash算法就肯定会有hash冲突,因为你hash的时候,了能你的数据范围比hash范围还大
hash1跟hash1,就存在去重的可能性了
恒定相等,这样就留下来了tom,为什么是2,是因为后面的值把前面的覆盖掉了,前面的字典就是这么用的
hash是算门牌号码,set和字典,就要看你是否可hash,一定需要hash,可hash才能放到set里,列表就放不进去,试试tom,jerry是否可hash
Person现在就不是可hash的类型
hash这个方法还需要提供一下,实例没有看起来是不行的
没提过来测试一下,person的__dict__,这是就是不可hash的原因
把eq注释掉,就又可以hash了
如果有了__eq__,就假定你是有hash的,没写hash,就认为hash=none
如果没有提供hash函数,对于实例求hash是用的内存的地址来做的,
同一个类型地址算的,就是一样的
按照道理,任何对象都是可以hash的,因为在object上,实现了__hash__函数,它是用对象的内存地址参与计算,算出来的,如果两个不同的对象,一般内存地址是不一样的,算出的值是不一样的,hash只要不冲突,不进入一个房间,就随便你放,一旦是一个房间就 要看是否相等
一旦提供了__eq__方法,这个时候就会给你的类添加一个hash=none,这就跟list,也就是直接告诉你hash是不被允许的
如果想让一个类彻底不能hash,直接写__hash__=none,就可以了
set和字典的去重的区别需要记一下,hash是算出一个散列值,一般来讲微小的变化,会引起散列值巨大的变化
这两个tom,jerry能否去重掉,就看hash有没有冲突,首先看is是否相同,如果相同,就没必要比后面内容,比较内容就受到__eq__方法的控制,eq决定是否相同,如果相同则,对于set来讲,则去重,eq方法单独使用会为当前类添加___hash__=none,导致本来这个东西可以hash的,但是因为__hash__=none,此对象就不可hash
eq的作用就是比较是否相同
这时候任何一个person实例都会冲突,因为都等于1
恒定false,就永远去不了重
先比较is,is不相同开始比较==,内存地址一样就没必要比较==
shutil,库的时候,也说了比较文件是否相同
** eq__对应操作符==,所以也习惯称为操作符重载,返回布尔值
self =tom,other=jerry**
hash值相等,只能说明hash冲突,不能说明两个对象是否相等
一般来说。hash方法是为了作为set或者dict的key,所以去重要同时一个__eq__方法
是否可以hash可以这么判断
把这个注释掉,因为有__eq__在就说明已经不可hash了
**因为list类,后面有__hash=none,当然不可以hash了**
拿到两个坐标实例,要不要放在集合中去,拿进去之后,要不要去重
或相当于+,and相当于乘法
如果光给__eq__方法,hash就是none
如果这样写就是递归
两个点,一致,算出来的hash值就是一致的
最终剩余1个点
常用的容器就是set和字典,就要考虑是不是可以hash还有去重的问题
这些都是不同的项目用不同的东西