【转】实习小记-python 内置函数__eq__函数引发的探索
【转】实习小记-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__函数引发的探索的更多相关文章
- python 练习题:请利用Python内置的hex()函数把一个整数转换成十六进制表示的字符串
# -*- coding: utf-8 -*- # 请利用Python内置的hex()函数把一个整数转换成十六进制表示的字符串 n1 = 255 n2 = 1000 print(hex(n1)) pr ...
- Python内置高阶函数map()
map()函数map()是 Python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回. 例如,对于lis ...
- 匿名函数python内置高阶函数以及递归
匿名函数 python定义一个函数通常使用def关键词,后面跟函数名,然后是注释.代码块等. def func(): '''注释''' print('from func') 这样就在全局命名空间定义了 ...
- Python - 内置函数 选例
概览参见 https://www.runoob.com/python/python-built-in-functions.html 官方文档 https://docs.python.org/3/li ...
- Python内置函数二 (递归函数,匿名函数,二分法)
匿名函数 lambda() 语法: lambad 参数 : 返回值 def func(a,b): return a * b print(func(2,5)) a = lambda a ,b : a* ...
- 熟记这些python内置函数,你离大佬就不远了
python内置了很多函数,方便我们在写程序的时候调用,在ython 2.7 的所有内置函数共有80个.熟练记住和使用这些内置函数,将大大提高写Python代码的速度和代码的优雅程度. 以下代码示例用 ...
- python内置函数
python内置函数 官方文档:点击 在这里我只列举一些常见的内置函数用法 1.abs()[求数字的绝对值] >>> abs(-13) 13 2.all() 判断所有集合元素都为真的 ...
- 【转】python 内置函数总结(大部分)
[转]python 内置函数总结(大部分) python 内置函数大讲堂 python全栈开发,内置函数 1. 内置函数 python的内置函数截止到python版本3.6.2,现在python一共为 ...
- python内置函数,匿名函数
一.匿名函数 匿名函数:为了解决那些功能很简单的需求而设计的一句话函数 def calc(n): return n**n print(calc(10)) #换成匿名函数 calc = lambda n ...
随机推荐
- TCP详解——连接建立与断开
一.报文结构介绍 在开始讲TCP连接过程时,还是先看看TCP报文的格式如图1所示.IP数据报此时由IP头部+TCP头部+TCP数据组成.不带选项的TCP头部是20字节长,而带选项的,TCP头部最长可达 ...
- 安装saltstack使用的shell
sed -i 's/^#//g' /etc/yum.repos.d/centos6.8.repo sed -i 's/enabled=0/enabled=1/g' /etc/yum.repos.d ...
- JQuery1.72中二个Bug,formhtml()方法与clone()方法的二个Bug进行重写
//扩展方法$.formhtml,解决firefox中html()方法得不到修改input值后的html代码(function ($) { var oldHTML = $.fn.html; ...
- HDU 1021(斐波那契数与因子3 **)
题意是说在给定的一种满足每一项等于前两项之和的数列中,判断第 n 项的数字是否为 3 的倍数. 斐波那契数在到第四十多位的时候就会超出 int 存储范围,但是题目问的是是否为 3 的倍数,也就是模 3 ...
- 伯克利SocketAPI(一) socket的C语言接口/最简单的服务器和对应的客户端C语言实现
1. 头文件 2. API函数 3. 最简单的服务器和对应的客户端C语言实现 3.1 server #include <sys/types.h> #include <sys/sock ...
- Oracle的to_char()函数使用
(1)用作日期转换: to_char(date,'格式'); select to_date('2005-01-01 ','yyyy-MM-dd') from dual; select to_char( ...
- ArcGIS坐标系转换出错:Error 999999执行函数出错 invalid extent for output coordinate system
本文主要介绍在用ArcGIS做坐标系转换过程中可能会遇到的一个问题,并分析其原因和解决方案. 如下图,对一份数据做坐标系转换: 过了一会儿,转换失败了.错误消息如下: “消息”中提示,“执行函数出错 ...
- jsp查询修改
也是只帖代码....不讲解. 1.search.jsp <%@ page language="java" import="java.util.*" pag ...
- Android允许在UI线程中使用网络访问
StrictMode.ThreadPolicy policy=new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode ...
- FastJson用法
namespace test { class Program { static void Main(string[] args) { var zoo1 = new zoo(); zoo1.animal ...