昨天遇到一个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. [转]Windows的窗口刷新机制

    1.Windows的窗口刷新管理 窗口句柄(HWND)都是由操作系统内核管理的,系统内部有一个z-order序列,记录着当前窗口从屏幕底部(假象的从屏幕到眼睛的方向),到屏幕最高层的一个窗口句柄的排序 ...

  2. CentOS 常用命令大全(2)

    系统 # uname -a               # 查看内核/操作系统/CPU信息 # head -n 1 /etc/issue   # 查看操作系统版本 # cat /proc/cpuinf ...

  3. Linux 下配置多机实时同步

    没钱的时候,用此方案做网站内容的负载均衡.异地备份,经济实惠又方便(仅针对网站文件做实时同步,如果数据库,则考虑mysql的多主架构) 一.机器配置及机房IP A机,位于杭州,IP: 115.33.2 ...

  4. mybatis中的mapper.xml

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-/ ...

  5. ViewPager滑动页面的实现方法

    package com.lixu.pagerview; import java.util.ArrayList; import android.app.Activity; import android. ...

  6. 启动项目报错Error: listen EADDRINUSE

    我在使用elasticsearch的kibana插件时候,有一次启动,遇到这个错误: Error: listen EADDRINUSE 它的意思是,端口5601被其他进程占用. 故而,需要kill掉那 ...

  7. Catalan数

    先看2个问题: 问题一: n个元素进栈(栈无穷大),进栈顺序为1,2,3,....n,那么有多少种出栈顺序? 先从简单的入手:n=1,当然只有1种:n=2,可以是1,2  也可以是2,1:那么有2种: ...

  8. sqlite多表关联update

    sqlite数据库的update多表关联更新语句,和其他数据库有点小不一样 比如:在sql server中: 用table1的 id 和 table2的 pid,关联table1 和 table2 , ...

  9. web安全测试-AppScan

    安全测试应该是测试中非常重要的一部分,但他常常最容易被忽视掉. 尽管国内经常出现各种安全事件,但没有真正的引起人们的注意.不管是开发还是测试都不太关注产品的安全.当然,这也不能怪我们苦B的“民工兄弟” ...

  10. SharePoint 2013 Nintex Workflow 工作流帮助(五)

    博客地址 http://blog.csdn.net/foxdave 工作流动作 4. Assign To-Do Task(User interaction分组) 直观理解,指派待办任务给一个或多个用户 ...