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

乱写__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内置函数

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

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

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

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

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

随机推荐

  1. Linux系统上安装nodejs

    1 官网下载地址:https://nodejs.org/en/download/ 2 下载的node-v10.15.2-linux-x64.tar.xz  上传到Linux系统后  因为安装的是纯净版 ...

  2. Shell 同步时间脚本

    Linux系统同步时间脚本 Linux操作系统,如果时间和网络时间差距太大的话.可能会导致程序,进程启动不了.所以linux系统时间同步显得尤为重要,本文在借鉴网上众多资料后,以centos_6.X系 ...

  3. Event Recommendation Engine Challenge分步解析第四步

    一.请知晓 本文是基于: Event Recommendation Engine Challenge分步解析第一步 Event Recommendation Engine Challenge分步解析第 ...

  4. Mybatis笔记二:接口式编程

    目录 旧方法的弊端 接口式编程 接口式编程的好处 接口式编程的增删改查 旧方法的弊端 在Mybatis笔记一中,我们使用命名空间+id的方式实现了Mybatis的执行,不过这里的命名空间是我们随便写的 ...

  5. MySQL数据类型1

    1.float.double.decimal类型用法详解 三者的区别介绍 float:浮点型,含字节数为4,32bit,数值范围为-3.4E38~3.4E38(7个有效位) double:双精度实型, ...

  6. CSS-Naming-Conventions--BEM

    BEM BEM : Block Element Modifier There are only two hard problems in Computer Sciences:cache invalid ...

  7. 那些年我们没能bypass的xss filter[from wooyun]

    原文链接:http://zone.wooyun.org/content/6899 小弟初学xss才10天.不过个人很喜欢收集xss payload.在这里把自己平时挖xss时会用到的payloads列 ...

  8. Ant和Maven

    Ant和Maven都是基于Java的构建(build)工具.理论上来说,有些类似于(Unix)C中的make ,但没有make的缺陷.Ant是软件构建工具,Maven的定位是软件项目管理和理解工具. ...

  9. threading.local学习

    多线程抢占问题 import time import threading obj = 5 def task(arg): global obj obj = arg time.sleep(1) print ...

  10. ElasticSearch - Shard数调优(ElasticSearch性能)

    序言 资料 https://blog.csdn.net/waneyongfu/article/details/78215972