昨天遇到一个Python问题,今天好奇试了一下

>>> a = {1:23,'ab':56}

>>> b = {2:22,'ab':57}

>>> a > b

False

>>> a < b

True

>>> b = {1:22,'ab':57}

>>> a > b

True

>>> a < b

False

好吧。。。真无聊,什么都要比一比,提供这种不科学不明了的默认实现有意思么

既来之则安之,八一八好了,Python为dictionary对象提供了一套默认实现

x<y calls x.__lt__(y), x<=y callsx.__le__(y), x==y calls x.__eq__(y), x!=y and x<>y call x.__ne__(y), x>y calls x.__gt__(y), and x>=y calls x.__ge__(y)

而且

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.

自己写个类的话,真麻烦。。。

不过还好

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

functools.total_ordering

(

cls

)

Given a class defining one or more rich comparison ordering methods, this class decorator supplies the rest. This simplifies the effort involved in specifying all of the possible rich comparison operations:

The class must define one of __lt__()__le__()__gt__(), or __ge__(). In addition, the class should supply an __eq__() method.

For example:
@total_ordering
class Student:
def __eq__(self, other):
return ((self.lastname.lower(), self.firstname.lower()) ==
(other.lastname.lower(), other.firstname.lower()))
def __lt__(self, other):
return ((self.lastname.lower(), self.firstname.lower()) <
(other.lastname.lower(), other.firstname.lower()))
New in version 2.7.

在谷歌的过程中在译言发现了一篇有趣的文章,其他部分也值得一读

Python的神奇方法指南

3.1 神奇方法——比较
Python有一整套神奇方法被设计用来通过操作符实现对象间直观的比较,而非别扭的方法调用。它们同样提供了一套覆盖Python对象比较的默认行为(通过引用)。以下是这些方法的列表以及做法:

__cmp__(self, other)
__cmp__是神奇方法中最基础的一个。实际上它实现所有比较操作符行为(<,==,!=,等),但它有可能不按你想要的方法工作(例如,一个实例是否等于另一个这取决于比较的准则,以及一个实例是否大于其他的这也取决于其他的准则)。如果self < other,那__cmp__应当返回一个负整数;如果self == other,则返回0;如果self > other,则返回正整数。它通常是最好的定义,而不需要你一次就全定义好它们,但当你需要用类似的准则进行所有的比较时,__cmp__会是一个很好的方式,帮你节省重复性和提高明确度。

__eq__(self, other)
定义了相等操作符,==的行为。
__ne__(self, other)
定义了不相等操作符,!=的行为。
__lt__(self, other)
定义了小于操作符,<的行为。
__gt__(self, other)
定义了大于操作符,>的行为。
__le__(self, other)
定义了小于等于操作符,<=的行为。
__ge__(self, other)
定义了大于等于操作符,>=的行为。

举一个例子,设想对单词进行类定义。我们可能希望能够按内部对string的默认比较行为,即字典序(通过字母)来比较单词,也希望能够基于某些其他的准则,像是长度或音节数。在本例中,我们通过单词长度排序,以下给出实现:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Word(str):
    '''单词类,比较定义是基于单词长度的'''
                                            
    def __new__(cls, word):
        # 注意,我们使用了__new__,这是因为str是一个不可变类型,
        # 所以我们必须更早地初始化它(在创建时)
        if ' ' in word:
            print "单词内含有空格,截断到第一部分"
            word = word[:word.index(' ')] # 在出现第一个空格之前全是字符了现在
        return str.__new__(cls, word)
                                                
    def __gt__(self, other):
        return len(self) > len(other)
    def __lt__(self, other):
        return len(self) < len(other)
    def __ge__(self, other):
        return len(self) >= len(other)
    def __le__(self, other):
        return len(self) <= len(other)

 

 

现在,我们可以创建2个单词(通过Word('foo')和Word('bar'))并基于它们的长度进行比较了。注意,我们没有定义__eq__ 和 __ne__。这是因为这可能导致某些怪异的行为(特别是当比较Word('foo') == Word('bar')将会得到True的结果)。基于单词长度的相等比较会令人摸不清头脑,因此我们就沿用了str本身的相等比较的实现。

现在可能是一个好时机来提醒你一下,你不必重载每一个比较相关的神奇方法来获得各种比较。标准库已经友好地为我们在模板functools中提供了一个装饰(decorator)类,定义了所有比较方法。你可以只重载__eq__和一个其他的方法(比如__gt__,__lt__,等)。这个特性只在Python2.7(后?)适用,但当你有机会的话应该尝试一下,它会为你省下大量的时间和麻烦。你可以通过在你自己的重载方法在加上@total_ordering来使用。

3.1 神奇方法——比较
Python有一整套神奇方法被设计用来通过操作符实现对象间直观的比较,而非别扭的方法调用。它们同样提供了一套覆盖Python对象比较的默认行为(通过引用)。以下是这些方法的列表以及做法:

__cmp__(self, other)
__cmp__是神奇方法中最基础的一个。实际上它实现所有比较操作符行为(<,==,!=,等),但它有可能不按你想要的方法工作(例如,一个实例是否等于另一个这取决于比较的准则,以及一个实例是否大于其他的这也取决于其他的准则)。如果self < other,那__cmp__应当返回一个负整数;如果self == other,则返回0;如果self > other,则返回正整数。它通常是最好的定义,而不需要你一次就全定义好它们,但当你需要用类似的准则进行所有的比较时,__cmp__会是一个很好的方式,帮你节省重复性和提高明确度。

__eq__(self, other)
定义了相等操作符,==的行为。
__ne__(self, other)
定义了不相等操作符,!=的行为。
__lt__(self, other)
定义了小于操作符,<的行为。
__gt__(self, other)
定义了大于操作符,>的行为。
__le__(self, other)
定义了小于等于操作符,<=的行为。
__ge__(self, other)
定义了大于等于操作符,>=的行为。

举一个例子,设想对单词进行类定义。我们可能希望能够按内部对string的默认比较行为,即字典序(通过字母)来比较单词,也希望能够基于某些其他的准则,像是长度或音节数。在本例中,我们通过单词长度排序,以下给出实现:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Word(str):
    '''单词类,比较定义是基于单词长度的'''
                                            
    def __new__(cls, word):
        # 注意,我们使用了__new__,这是因为str是一个不可变类型,
        # 所以我们必须更早地初始化它(在创建时)
        if ' ' in word:
            print "单词内含有空格,截断到第一部分"
            word = word[:word.index(' ')] # 在出现第一个空格之前全是字符了现在
        return str.__new__(cls, word)
                                                
    def __gt__(self, other):
        return len(self) > len(other)
    def __lt__(self, other):
        return len(self) < len(other)
    def __ge__(self, other):
        return len(self) >= len(other)
    def __le__(self, other):
        return len(self) <= len(other)

 

 

现在,我们可以创建2个单词(通过Word('foo')和Word('bar'))并基于它们的长度进行比较了。注意,我们没有定义__eq__ 和 __ne__。这是因为这可能导致某些怪异的行为(特别是当比较Word('foo') == Word('bar')将会得到True的结果)。基于单词长度的相等比较会令人摸不清头脑,因此我们就沿用了str本身的相等比较的实现。

现在可能是一个好时机来提醒你一下,你不必重载每一个比较相关的神奇方法来获得各种比较。标准库已经友好地为我们在模板functools中提供了一个装饰(decorator)类,定义了所有比较方法。你可以只重载__eq__和一个其他的方法(比如__gt__,__lt__,等)。这个特性只在Python2.7(后?)适用,但当你有机会的话应该尝试一下,它会为你省下大量的时间和麻烦。你可以通过在你自己的重载方法在加上@total_ordering来使用。

Python漫谈-比较运算符和类的神奇方法的更多相关文章

  1. python语言中threading.Thread类的使用方法

    1. 编程语言里面的任务和线程是很重要的一个功能.在python里面,线程的创建有两种方式,其一使用Thread类创建 # 导入Python标准库中的Thread模块 from threading i ...

  2. Python的程序结构[2] -> 类/Class[2] -> 方法解析顺序 MRO

    方法解析顺序 / MRO (Method Resolution Order) 关于方法解析顺序(MRO)的详细内容可以参考文末链接,这里主要对 MRO 进行简要的总结说明以及一些练习示例. 经典类和新 ...

  3. python中的运算符的分类以及使用方法

    1.算数运算符 算数运算符的分类: +, –,  *,  **(幂运算),   /,  //(整除),  %(取余/取模) 算数运算符的优先级:  ()>  ** > *, /, % &g ...

  4. 【转】Python的神奇方法指南

    [转]Python的神奇方法指南 有关Python内编写类的各种技巧和方法(构建和初始化.重载操作符.类描述.属性访问控制.自定义序列.反射机制.可调用对象.上下文管理.构建描述符对象.Picklin ...

  5. Python学习笔记之面向对象编程(三)Python类的魔术方法

    python类中有一些方法前后都有两个下划线,这类函数统称为魔术方法.这些方法有特殊的用途,有的不需要我们自己定义,有的则通过一些简单的定义可以实现比较神奇的功能 我主要把它们分为三个部分,下文也是分 ...

  6. Python 的神奇方法指南

    简介 有关 Python 内编写类的各种技巧和方法(构建和初始化.重载操作符.类描述.属性访问控制.自定义序列.反射机制.可调用对象.上下文管理.构建描述符对象.Pickling). 你可以把它当作一 ...

  7. Python学习笔记总结(三)类

    一.类简单介绍 1.介绍 类是Python面向对象程序设计(OOP)的主要工具,类建立使用class语句,通过class定义的对象. 类和模块的差异,类是语句,模块是文件. 类和实例 实例:代表程序领 ...

  8. Python 正确重载运算符

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica } 有些事情让我不安,比如运算符重载.我决定不支持运算符重载,这完全是个人 ...

  9. 【转】Python中的运算符

    [转]Python中的运算符 说完常用的数据类型,再来说下运算符.运算符用于将各种类型的数据进行运算,让静态的数据跑起来. 编程语言中的运算大致分为以下几个大类: 算术运算, 用于加减乘除等数学运算 ...

随机推荐

  1. 转:Linux 安装 Mysql

    前段时间安装了Mysql,但是有些问题,就想把他卸载了,重新安装一个,但是没想到在Linux卸载软件是一个很痛苦的事情.   我的Mysql是用命令的方式安装的,就是上一篇文章用到的那个命令(sudo ...

  2. cisco LAN

    由于实验需要,需要搞个内部局域网(以前我们实验室是直接从学校拖了根线过来,然后直接用switch连).因此得先配个router,做个小局域网.由于从没接触过路由器,所以先去网上找了些资料,接着就打开c ...

  3. mysql 远程连接速度慢的解决方案

    PHP远程连接MYSQL速度慢,有时远程连接到MYSQL用时4-20秒不等,本地连接MYSQL正常,出现这种问题的主要原因是,默认安装的MYSQL开启了DNS的反向解析,在MY.INI(WINDOWS ...

  4. 嵌套 click 第二层 click会叠加 导致 触发 多次

    $("#appearHiddenDiv").click(function(){ $("#hiddenDiv").css({display:"block ...

  5. Linux配置防火墙 开启80端口

    vi /etc/sysconfig/iptables -A INPUT -m state –state NEW -m tcp -p tcp –dport 80 -j ACCEPT(允许80端口通过防火 ...

  6. [转]jQuery Pagination Ajax分页插件中文详解

    在做项目时需要用到在前端页面中需要实现分页显示的功能,类似于博客园下面的分页导航.从网上找了几个,觉得下面这个使用起来非常简单,也很方便.特在这里记录一下. 以下为文章原文. 中文项目地址:http: ...

  7. C++-高效的swap

    原始版本: template<typename T> void swap(T& a, T& b) { T tmp(a); a = b; b = tmp; } 此版本不重视效 ...

  8. 【个人使用.Net类库】(2)Log日志记录类

    开发接口程序时,要保证程序稳定运行就要时刻监控接口程序发送和接收的数据,这就需要一个日志记录的类将需要的信息记录在日志文件中,便于自己维护接口程序.(Web系统也是如此,只是对应的日志实现比这个要复杂 ...

  9. Rhel6-集群管理(luci&&ricci)配置文档

    理论基础: User → HA →     Lb    → web → sql → 分布式filesystem ->磁盘I/O 用户   高可用 负载均衡    应用   数据库      mf ...

  10. C++指针(部分有误需修改)

    一.取地址运算符&(内存地址) C++编译的程序占用的内存分为以下几个部分: 1.栈区:由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈.与其它分区不同 ...