乱写__eq__会发生啥?请看代码..


>>> class A:
... def __eq__(self, other):  # 不论发生什么,只要有==做比较,就返回True
... return True
...
>>> a = A()
>>> b = A()
>>> a == b
True
>>> a != b # 这个地方为什么会返回False?
False
>>> a > b
Traceback (most recent call last):
File "<ipython-input-7-1e61210fe837>", line 1, in <module>
a > b
TypeError: unorderable types: A() > A() >>> x = [1,2,3,b,4,5]
>>> x.index(b) # 咦?
0
>>> x.index(2)
1
>>> x.index(4) # 诶?
3
>>> x.index(5) # 艾玛,啥情况?
3
>>> x.index(6) # 妈呀!
3
>>> x.index(a) # 23333
0
 

当时初次看到这个就被这神奇的现象吸引了,发现新大陆了的感觉。以为发现了BUG。。。问我隔壁的小哥,也说不明白。但可以确定的是,如果我没有重写这个__eq__函数的话,下面的操作都是正常的,找不到的就找不到,能找到的就返回正确的index。所以肯定是我__eq__函数写差了,源码看不到也不好搜索,于是跑去看文档。文档这里写道:

object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)

These are the so-called “rich comparison” methods. The correspondence between operator symbols and method names is as follows: x<y calls x.__lt__(y), x<=y calls x.__le__(y), x==y calls x.__eq__(y), x!=y calls x.__ne__(y), x>y calls x.__gt__(y), and x>=y calls x.__ge__(y).

A rich comparison method may return the singleton NotImplemented if it does not implement the operation for a given pair of arguments. By convention, False and True are returned for a successful comparison. However, these methods can return any value, so if the comparison operator is used in a Boolean context (e.g., in the condition of an if statement), Python will call bool() on the value to determine if the result is true or false.

There are no implied relationships among the comparison operators. The truth of x==y does not imply that x!=y is false. Accordingly, when defining __eq__(), one should also define __ne__() so that the operators will behave as expected. See the paragraph on __hash__() for some important notes on creating hashable objects which support custom comparison operations and are usable as dictionary keys.

There are no swapped-argument versions of these methods (to be used when the left argument does not support the operation but the right argument does); rather, __lt__() and __gt__() are each other’s reflection, __le__() and __ge__() are each other’s reflection, and __eq__() and __ne__() are their own reflection.

Arguments to rich comparison methods are never coerced.

To automatically generate ordering operations from a single root operation, see functools.total_ordering().

1.这些比较函数都称为rich comparison,正常情况下,它们回返回真或假。实际上这些函数都可以返回任意类型的值,如果这些比较被运用在布尔环境中的时候,比方说if 语句的条件中时,python 会调用bool()函数来确认当前的返回值是真还是假。(划横线的地方不会翻译=。=)

2.这些函数的定义之间并没有引申的含义,比如说如果a==b是真,并不代表a!=b一定是假。所以我们在定义__eq__函数的时候也应该同时定义__ne__函数以确保我们能够得到我们想要的结果。如果我们想了解可哈希对象的比较的信息,我们最好去看看__hash__()的文档。这里就不展开了,具体文章在这里(实习小记-python中可哈希对象是个啥?what is hashable object in python?

3.这些函数并没有可替换参数之说(像是左边的参数不支持这个函数,而右边的参数支持。)这里要说的是,__lt__()函数和__gt__()函数他们两个的取值是一定相反的;__le__()和__ge__()也一定是取相反的;但是__eq__()函数和__ne__()函数是各自独立定义的。相互之间并没有关系。这也就是2里面提到的。

4.比较这类操作的参数是不会类型转换的。(如果a,b做比较,a是浮点,b是整数,比较结束后b不会变成浮点类型?)

5.如果我们希望能够在一些情况下自动排序,那么请参考functools.total_ordering()

读到这里我们在回到之前的代码中看看,到底发生了什么

>>> class A:
... def __eq__(self, other):  # 不论发生什么,只要有==做比较,就返回True
... return True
...
>>> a = A()
>>> b = A()
>>> a == b
True
>>> a != b # 这个地方为什么会返回False?
False
>>> a > b
Traceback (most recent call last):
File "<ipython-input-7-1e61210fe837>", line 1, in <module>
a > b
TypeError: unorderable types: A() > A() >>> x = [1,2,3,b,4,5]
>>> x.index(b) # 首先拿x中的1与b做比较,应该是==的比较,由于b.__eq__()无论什么情况下都返回True。所以python以为第一个元素就是b,于是返回index 0
0
>>> x.index(2)
1
>>> x.index(4) # 这里拿4做比较,x中的元素安顺序比较,1,2,3为False,但当比较到b时由于b的坑爹属性返回True,以为找到了,返回index 3
3
>>> x.index(5) # 同上
3
>>> x.index(6) # 同上
3
>>> x.index(a) # 和第一次相比的原因是一样的。
0

那么问题来了,如果我们需要一种类,该类的实例做比较的时候比较类中属性,属性相等返回True,在列表中查找时也能正确查找,应该如何写呢?请看下面代码:


>>> class A:
... def __init__(self, x):
... self.x = x
... def __eq__(self, other):
... try:
... return self.x == other.x
... except AttributeError:
... return False
... def __ne__(self, other):
... try:
... return self.x != other.x
... except AttributeError: # 发现两者不可比,返回类型错误
... raise TypeError('this two argument is not comparable!')
...
>>> a = A(1)
>>> b = A(1)
>>> c = A(2)
>>> a == b
True
>>> a != b
False
>>> a == c
False
>>> a != c # 相同类型做比较,确实不相同
True
>>> a == 1 # 不同类型做比较,返回False
False
>>> a != 1 # 判断不同类型是否不等,报类型错误
Traceback (most recent call last):
File "<ipython-input-52-30ec16ffc1a6>", line 1, in <module>
a != 1
File "<ipython-input-43-70049527ba59>", line 13, in __ne__
raise TypeError('this two argument is not comparable!')
TypeError: this two argument is not comparable! >>> list = [1,2,3,b,4,5]
>>> list.index(3)
2
>>> list.index(b) # 成功找到!
3
>>> list.index(a) # 实例不同,但是self.x相等,属于同一个。
3
>>> a in list
True
>>> b in list
True

实习小记-python 内置函数__eq__函数引发的探索的更多相关文章

  1. python 练习题:请利用Python内置的hex()函数把一个整数转换成十六进制表示的字符串

    # -*- coding: utf-8 -*- # 请利用Python内置的hex()函数把一个整数转换成十六进制表示的字符串 n1 = 255 n2 = 1000 print(hex(n1)) pr ...

  2. Python内置高阶函数map()

    map()函数map()是 Python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回. 例如,对于lis ...

  3. 匿名函数python内置高阶函数以及递归

    匿名函数 python定义一个函数通常使用def关键词,后面跟函数名,然后是注释.代码块等. def func(): '''注释''' print('from func') 这样就在全局命名空间定义了 ...

  4. Python - 内置函数 选例

    概览参见  https://www.runoob.com/python/python-built-in-functions.html 官方文档 https://docs.python.org/3/li ...

  5. Python内置函数二 (递归函数,匿名函数,二分法)

    匿名函数 lambda() 语法: lambad  参数 : 返回值 def func(a,b): return a * b print(func(2,5)) a = lambda a ,b : a* ...

  6. 熟记这些python内置函数,你离大佬就不远了

    python内置了很多函数,方便我们在写程序的时候调用,在ython 2.7 的所有内置函数共有80个.熟练记住和使用这些内置函数,将大大提高写Python代码的速度和代码的优雅程度. 以下代码示例用 ...

  7. 【转】实习小记-python 内置函数__eq__函数引发的探索

    [转]实习小记-python 内置函数__eq__函数引发的探索 乱写__eq__会发生啥?请看代码.. >>> class A: ... def __eq__(self, othe ...

  8. python内置函数

    python内置函数 官方文档:点击 在这里我只列举一些常见的内置函数用法 1.abs()[求数字的绝对值] >>> abs(-13) 13 2.all() 判断所有集合元素都为真的 ...

  9. 【转】python 内置函数总结(大部分)

    [转]python 内置函数总结(大部分) python 内置函数大讲堂 python全栈开发,内置函数 1. 内置函数 python的内置函数截止到python版本3.6.2,现在python一共为 ...

  10. python内置函数,匿名函数

    一.匿名函数 匿名函数:为了解决那些功能很简单的需求而设计的一句话函数 def calc(n): return n**n print(calc(10)) #换成匿名函数 calc = lambda n ...

随机推荐

  1. XPM转换与查看工具

    X PixMap (XPM)是一种基于ASCII编码的图像格式,在X Window系统中的应用十分广泛.她最初由位于法国Sophia Antipolis的Bull研究中心的Daniel Dardail ...

  2. [Xamarin.Android] 使用Component套件

    [Xamarin.Android] 使用Component套件 前言 在Xamarin中,可以将自己开发的项目包装成为Component套件发布至Xamarin Component Store,来提供 ...

  3. Android 多语言

    Android 多语言 在res文件上右击创建新的values文件 在strings文件中设置多语言 3.在layout文件中使用 @strings/key 引用相应资源

  4. Atitit.工作流系统的本质是dsl 图形化的dsl  4gl

    Atitit.工作流系统的本质是dsl 图形化的dsl  4gl 1. 工作流系统的本质是dsl 图形化的dsl  4gl1 2. 为什么每个项目系统都需要工作流1 3. 工作流dsl与java .n ...

  5. 彻底退出所有的Acticity

    有时候点击回退键退出应用,会出现有些Activity不能完全退出的情况,那么可以使用前面这个方法: 在需要退出的Activity的onCreate()方法中加入 ExitApplication.get ...

  6. ios 删除系统从相册压缩的视频

    iOS的沙盒机制,应用只能访问自己应用目录下的文件.iOS不像android,没有SD卡概念,不能直接访问图像.视频等内容.iOS应用产生的内容,如图像.文件.缓存内容等都必须存储在自己的沙盒内.默认 ...

  7. 集成ZBar时容易遇到的问题以及解决方法

    1.添加入几个必备的框架: libiconv.tbd QuartzCore.framework CoreVideo.framework CoreMedia.framework AVFoundation ...

  8. 21分钟 MySQL 入门教程

    目录 一.MySQL的相关概念介绍 二.Windows下MySQL的配置 配置步骤 MySQL服务的启动.停止与卸载 三.MySQL脚本的基本组成 四.MySQL中的数据类型 五.使用MySQL数据库 ...

  9. html 关于内部是float元素的外部div高度为0的解决方法!

    最近编写一个页面的时候遇见一个问题,外部div是block的,而内部元素是float的,大家应该都知道float的元素是没有实际高度的,就算你设置了float元素的高度他也不会撑开外部block元素的 ...

  10. TCP & UDP 的区别

    一.概念 ① TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议. “面向连接”就是在正式通信前必须要与对方建立起连 ...