• Python漫谈-比较运算符和类的神奇方法


    昨天遇到一个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来使用。

  • 相关阅读:
    发卡构型高分子的跨膜传输
    《一个数学家的叹息》读后
    匀速拉地毯最少需要多大的力
    桥环形高分子的标度理论——链滴图像
    试验1
    自定义控件EditText
    自定义控件TextView
    HTTP的应用httpclient 和线程
    http的应用httpurlconnection--------1
    学习笔记—Fragement +Actionbar
  • 原文地址:https://www.cnblogs.com/wei-li/p/3514950.html
Copyright © 2020-2023  润新知