Python-特殊方法(迭代器,生成器,内建方法,运算符重载)

Python是一门独特的语言,力求简洁,它甚至不像某些语言(如Java)提供接口语法,Python语言采用的是“约定”规则,它提供了大量具有特殊意义的方法,这些方法有些可以直接使用,有些需要开发者重写。掌握这些方法是使用Python面向对象编程的基础。

目录

1.常见的特殊方法

1.1 重写__repr__方法

1.2.析构方法__del__ Python的垃圾回收机制

1.3.__dir__方法

1.4.__dict__属性

1.5 getattr、__setattr__等

2. 与反射相关的属性和方法

2.1 动态操作属性

2.2 __call__属性

2.3 与序列相关的特殊方法(len, key-vaue)

3. 实现迭代器

4.扩展列表、元组和字典

5.生成器 yield

5.1 创建生成器

5.2 send()函数

5.3 close()与throw():

6.运算符重载的特殊方法

6.1与数值运算符相关的特殊方法

6.2与比较运算符相关的特殊方法

6.3 与单目运算符相关的特殊方法

6.4与类型转换相关的特殊方法

6.5 与常见的内建函数相关的特殊方法

扑克牌比大小


1.常见的特殊方法

1.1 重写__repr__方法

__repr__()是Python类中的一个特殊方法,由于object类已经提供了该方法,而所有得到Python类都是object的子类,因此所有Python对象都具有__repr__()方法

 __repr__()是一个非常特殊的方法,它是一个自我描述的方法,通常用于实现需要直接打印该对象的时候。

class Apple:
    def __init__(self, color, weight):
        self.color = color
        self.weight = weight

    #重写__repr__()方法,用于实现Apple对象得到自我描述
    def __repr__(self):
        return "Apple[color=" +self.color +\
        ", weight=" +str(self.weight) +"]"
ap = Apple('红色', 345)
print(ap)

1.2.析构方法__del__ Python的垃圾回收机制

>当程序不再需要一个Python对象时,系统必须把该对象所占用的内存空间释放出来,这个过程称为垃圾回收(GC)。

    >Python会自动回收所有对象所占用的内存空间,因此开发者无需关心对象垃圾回收的过程。

    >Python采用自动引用计数(ARC)方式来回收对象所占用的空间,当程序中有一个变量引用该Python对象时,Python会自动保证该对象引用计数为1,

    同理,当有2个变量引用该Python对象时,引用计数为2, ...依次磊对,如果一个对象的引用计数变为0,Python就会自动回收该对象。

    >需要说明的是,并不是对一个变量执行del操作,该变量所引用的对象就会被回收,只有当对象的引用计数变为0时,该对象才会被诶诶回收。因此如果一个对象有多个额变量引用它,那么del其中一个变量是不会回收该对象的。

    >如果父类提供了__deel__()方法,则系统同重写__del__()方法是,必须显示调用父类的__del__()方法,这样才能保证合理的回收父类实例的部分属性

class Item:
    def __init__(self, name, price):
        self.name = name
        self.price = price
    #定义析构函数
    def __del__(self):
        print('del 删除该对象')
#创建Item对象并将之赋值给xx
im = Item('mouse', 98)
xx = im #增加引用计数
del im #此时未删除
print('---程序结束---')
del(xx)
#此时才删除
'''
输出:
---程序结束---
del 删除该对象
'''

1.3.__dir__方法

对象的__dir__()方法用于列出该对象内部的所有属性(包括方法)名,该方法会返回所包含的所有属性(方法)名的序列。

程序对某个对象执行dir(object)函数时,实际上就是讲该对象的__dir__()方法返回值进行排序然后包装成列表

class Car:
    def __init__(self, brand, price):
        self.brand = brand
        self.price = price
    def info():
        pass
car = Car('BENZ', 30)
print(car.__dir__()) #返回属性方法列表
print(dir(car))

1.4.__dict__属性

    __dict__属性用于查看对象内部存储的所有属性名和属性值组成的字典,通常程序直接使用该属性即可

1.5 getattr、__setattr__

__ getattribute__(self,name):当程序访问对象的name属性时被自动调用
__ getattr__(self,name):当程序访问对象的name属性且该属性不存在时被自动调用
__ setattr__(self,name,value):当程序对对象的name属性赋值时被自动调用
__ delattr__(self,name):当程序删除对象的name属性时被自动调用

2. 与反射相关的属性和方法

2.1 动态操作属性

在动态检查对象是否包含某些属性相关的函数有如下几个:

hasattr(obj,name):检查obj对象是否包含名为name的属性或方法
getattr(object,name[,default]): 获取object对象中名为name 的属性的属性值
setattr(obj,name,value,/):将obj对象的name属性设为value

2.2 __call__属性

程序可通过判断该属性是否包含__call__属性来确定它是否可调用,即是否是方法。

2.3 与序列相关的特殊方法(len, key-vaue)

序列相关方法
序列最重要的特征就是可包含多个元素,因此和序列有关的特殊方法有如下一个:

__len __ (self):该方法的返回值决定序列中元素的个数
__getitem __(self,key):该方法获取指定索引对应的元素
__contains __(self,item):该方法判断序列是否包含指定元素
__setitem __(self,key,value):该方法设置指定索引对应的元素
__delitem __(self,key):该方法删除指定索引对应的元素
 

def check_key (key):
    '''
    该函数将会负责检查序列的索引,该索引必须是整数值,否则引发TypeError
    且程序要求索引必须为非负整数,否则引发IndexError
    '''
    if not isinstance(key, int): raise TypeError('索引值必须是整数')
    if key < 0: raise IndexError('索引值必须是非负整数')
    if key >= 26 ** 3: raise IndexError('索引值不能超过%d' % 26 ** 3)   
class StringSeq:
    def __init__(self):
        # 用于存储被修改的数据
        self.__changed = {}
        # 用于存储已删除元素的索引
        self.__deleted = []
    def __len__(self):
        return 26 ** 3
    def __getitem__(self, key):
        '''
        根据索引获取序列中元素
        '''
        check_key(key)
        # 如果在self.__changed中找到已经修改后的数据
        if key in self.__changed :
            return self.__changed[key]
        # 如果key在self.__deleted中,说明该元素已被删除
        if key in self.__deleted :
            return None
        # 否则根据计算规则返回序列元素
        three = key // (26 * 26)
        two = ( key - three * 26 * 26) // 26
        one = key % 26
        return chr(65 + three) + chr(65 + two) + chr(65 + one) 
    def __setitem__(self, key, value):
        '''
        根据索引修改序列中元素
        '''
        check_key(key)
        # 将修改的元素以key-value对的形式保存在__changed中
        self.__changed[key] = value
    def __delitem__(self, key):
        '''
        根据索引删除序列中元素
        '''
        check_key(key)
        # 如果__deleted列表中没有包含被删除key,添加被删除的key
        if key not in self.__deleted : self.__deleted.append(key)
        # 如果__changed中包含被删除key,删除它
        if key in self.__changed : del self.__changed[key]
# 创建序列
sq = StringSeq()
# 获取序列的长度,实际上就是返回__len__()方法的返回值
print(len(sq))
print(sq[26*26])
# 打印没修改之后的sq[1]
print(sq[1]) # 'AAB'
# 修改sq[1]元素
sq[1] = 'fkit'
# 打印修改之后的sq[1]
print(sq[1]) # 'fkit'
# 删除sq[1]
del sq[1]
print(sq[1]) # None
# 再次对sq[1]赋值
sq[1] = 'crazyit'
print(sq[1]) # crazyit

 

 

3. 实现迭代器

在使用过的for-in循环列表,元组和字典,这些对象都是可迭代的,因此他们都属于迭代器

如果开发者需要实现迭代器,只要实现如下两个方法即可

    >1.__iter__(self):该方法返回一个迭代器(iterator),迭代器必须包含一个__next__()方法,该方法返回迭代器的下一个元素。

    >2.__reversed__(self):该方法主要为内建的reversed()反转函数提供支持,当程序调用reversed()函数对指定迭代器进行反转时,实际上是有该方法实现的。

#下面程序将会定义一个代表斐波那契数列的迭代器 f(n+2) = f(n+1) + f(n)
class Fibs:
    def __init__(self, len):
        self.first = 0
        self.sec = 1
        self.__len = len
    #定义__dext__()
    def __next__(self):
        #如果__len__属性为0,结束迭代
        if self.__len == 0:
            raise StopIteration
        #完成计算数列
        '''
        org_first = self.first
        self.first = self.sec
        self.sec   = org_first +self.sec
        '''
        self.first, self.sec = self.sec, self.first + self.sec
        self.__len -= 1
        return self.first
    #定义__iter__()方法
    def __iter__(self):
        return self
fibs = Fibs(10)
print(next(fibs))
for it in fibs:
    print(it, end=' ')

4.扩展列表、元组和字典

只需要继承系统已有的列表或字典即可

下面程序简单师范开发一个新的字典类,这个字典可以根据value来获取key,由于字典中的value是可以重复的,因此该方法会返回指定value对应的全部key组成的列表

指定关键字创建字典

class Valuedict(dict):
    def __init__(self, *args,**kwargs):
        #调用父类的构造函数
        super().__init__(*args, **kwargs)
    #新增getkey()方法
    def getkeys(self, val):
        result = []
        for key, value in self.items():
            if value == val:
                result.append(key)
        return result


my_dict = Valuedict(语文=92, 数学=89, 英语=92)
print(my_dict.getkeys(92))
my_dict['编程'] = 92
print(my_dict.getkeys(92))

以列表作为参数创建字典

#以列表作为参数创建字典
score_list = [['语文',90], ['英语', 99], ['数学',100]]

class Listdict(dict):
    def __init__(self, list):
        #调用父类的构造函数
        super().__init__(list)
    #新增getkey()方法
    def getkeys(self, val):
        result = []
        for key, value in self.items():
            if value == val:
                result.append(key)
        return result

list_dict = Listdict(score_list)
list_dict['物理'] = 99
print(list_dict.getkeys(99))

5.生成器 yield

生成器可迭代器的功能十分相似,它也会提供__nextt__()方法,这意味着程序东阳可以调用内置的next()函数来获取生成器的下一个,也可以使用for循环来遍历生成器

    生成器与迭代器的区别在于:迭代器通常是先定义一个迭代器类,然后通过调用该函数来创建生成器。

    生成器是一种非常优秀得到语法,Python使用生成器可以让程序变得很优雅

    生成器时Python的一个特色功能,在其他语言中往往没有对应的机制,使用生成器至少有以下几个优势

    1> 当使用生成器来生成多个数据是,程序时按需获取的,它不会一开始就把所有数据都生成出来,而是内次调用next()获取下一个数据时,生成器才会执行一次,因此可以一定程度下减少代码执行的次数;

    2> 当函数需要返回多个数据时,如果不适用生成器,程序就需要使用列表或元组来手机函数返回的多个值,当函数返回的数据量较大时,这些列表或元组会带来一定的内存开销;如果使用生成器就不存在这个问题,生成器可以按需,逐个返回数据

    3> 使用生成器的代码更加简洁

5.1 创建生成器

    创建生成器需要两步:

    1> 定义一个包含yield语句的函数

    2> 调用第一步创建的函数来得到生成器

def yield_test(val, step):
    print('starting excute function----')
    cur = 0
    for i in range(val):
        #cur add
        cur += i * step
        yield cur
'''
$ 该函数与普通函数最大的区别在于yield cur这一行,如果将这一行代码改为print(cur),那这个函数就比较普通了,只是简单的遍历区间,
    并将徐建计时器乘以step后添加到cur,数列中的两个值之间的差值会逐步递增。
$ yield的语句作用有2点:
    1> 每次返回一个值 有点类似于return 与居家
    2> 冻结执行,程序每次执行到yield语句是就会被暂停
    在程序被yield语句冻结之后,当程序再次调用next()函数获取生成器的下一个值时,程序才会乡下执行。
    需要指出的是,调用包含yield语句的函数并不会立即执行,它只是返回一个生成器,只有当程序通过next()函数调用生成器或遍历生成器时,
    函数才会真正的执行。
    python 2.x 不适用next()函数获取生成器的下一个值,而是直接调用生成器的next()方法。因此在python 2.x中应该写成 t.next()
'''

yd_test = yield_test(10, 4)
''' 调用next()时yield_test函数才真正开始执行 '''
print(next(yd_test))    # 0
print(next(yd_test))    # 4
for i in yd_test:#yield_test(10, 4): 如果此处是首次返回,迭代器从0开始,否则从当前冻结处开始
    print(i, end=' ') # 12 24 40 60 84 112 144 180

''' 可以调用list 或 tuple 将生成器的所有制转换成列表 '''
yd2 = yield_test(10, 2)
print(list(yd2))    #[0, 2, 6, 12, 20, 30, 42, 56, 72, 90]
yd3 = yield_test(10, 3)
print(tuple(yd3))   #(0, 3, 9, 18, 30, 45, 63, 84, 108, 135)

Python主要提供了一下两种方式来创建生成器:

    1> 使用for循环的生成器推导式

    2> 调用带yield语句的生成器函数

5.2 send()函数

    当生成器运行起来以后,开发者还可以为生成器提供值,通过这种方式让生成器与外部程序动态地交换数据。为了实现生成器与外部程序动态地交换数据,需要借助生成器的snend()方法,该方法的功能与前面实例中所使用的的next()功能十分相似,他们都用于获取生成器所生成的下一个值,并将生成器冻结在yield处,但send()方法可以接受一个参数,该残花会被发送给生成器。

    在生成器函数内部,程序可以通过yield表达式来获取send()方法所发送的值——这意味着此时程序应该使用一个变量来接受yield语句的值。

    如果程序依然使用next()函数爱获取生成器所生成的下一个值,那么yield语句将返回None,i即没有接收到值。

    总结起来就是:

    1.外部程序通过send()方法发送数据;

    2.生成器函数使用yield语句接收数据

    需要说明,只有等到生成器被"冻结"之后,外部程序才能使用send()方法向生成器发数据。获取生成器第一次所生成的值,应该使用next()函数;

    如果程序非要使用send()方法获取生成器第一次所生成的数值,也不能向生成器法师报告数据,只能向该方法传入None参数。

下面程序示范了向生成器发送数据,该程序或一次生成每个整数的平方值,但外部程序介意向生成器发送数据,当生成器接受到外部数据之后会生成对应的平方值

def square_gen():
    out_val =None
    i= 0
    while True:
        #使用yield语句生成值 使用out_val接受 send()方法发送的参数
        #如果程序使用send()方法获取下一个值,out_val会获取send()方法的参数值
        out_val = (yield out_val ** 2) if out_val is not None else (yield i **2) ##获取send的值的关键 左边有变量的yield语句,会获取send的值以后不会冻结
        ''' 上一行同下面代码段一样的效果
        out_val = yield out_val
        
        if out_val is not None:
            yield out_val ** 2
        else:
            yield i **2
        '''
        i += 1
        print('do i++, i= %d, out_val =' %(i), end = ' ')
        print(out_val)

print('创建生成器----')
sg = square_gen()
print('第1次调用生成器send(None)---- ')
print(sg.send(None))
print('get next_1 ---')
print(next(sg))
print('第2次调用生成器send(9)----')
#调用send 方法获取生成器的下一个值 参数9
print(sg.send(9))
# 再次调用 next()获取下一个值
print('get next_2 ---')
print(next(sg))

该程序与前面简单的生成器程序的区别就在于 out_val = 开始这一行,这行代码在yield语句(yield语句被放在if表达式中,

整个表达式就只会返回一个yield语句)的左边放了一个变量,该变量就是用于接收生成器send()方法所发送的值。

1>程序第一次使用生成器得到send()方法来获取生成器的下一个值,因此只能为send()方法传入None作为参数。程序执行到yield这一行,由于此时out_val为None,因此程序执行yield i**2,生成器返回0,程序被"冻结"——注意,当程序被"冻结"时,程序还未对out_val变量赋值,因此看到第一次获取生成器的值为0,此时i为初始值0;通过执行该过程不难看出,生成器无法获取第一次调用send()方法发送的参数值,因此Python要求生成器第一次调用send()方法是只能发送None参数;

2>接下来程序调用next(sg)获取生成器的下一个值,程序从"冻结"处(对out_val赋值)向下执行,由于此处调用next()函数获取生成器的下一个值,此时out_val 被赋值为None,然后向下执行 i++ = 1, 再次进入yield语句 ,out_val为None,所以程序执行yield i**2(此时i为1,生成器返回1),程序再次被"冻结";

3>接下来调用sg.send(9)获取生成器的下一个值,程序从"冻结"处(对out_val赋值)乡下执行。由于此处调用send(9)方法获取生成器生成的下一个值,此时out_val为9,然后向下执行 i++ =2,重新进入yield语句,out_val 不为None,所以程序执行yield out_val **2(生成器返回81),程序再次被冻结。

4>程序再次调用next()函数获取生成器的下一个值,此时out_val被赋值为None,然后向下执行 i++ =3,再次进入yield循环,

所以程序执行yield **2(i此时为3),得到9,程序再次被冻结

程序输出过程:

创建生成器----

第1次调用生成器send(None)----

0

get next_1 ---

do i++, i= 1

1

第2次调用生成器send(9)----

====9

do i++, i= 2

81

get next_2 ---

do i++, i= 3

9

5.3 close()与throw():

1> close():该方法用于停止生辰器

2> throw():该方法用于在生成器内部 (yield语句内)引发一个异常

def x_square_gen():
    out_val =None
    i= 0
    while True:
        #使用yield语句生成值 使用out_val接受 send()方法发送的参数
        #如果程序使用send()方法获取下一个值,out_val会获取send()方法的参数值
        out_val = yield out_val #获取send的值的关键 左边有变量的yield语句,会获取send的值以后不会冻结

        if out_val is not None:
            yield out_val ** 2
        else:
            yield i **2
        #out_val = (yield out_val ** 2) if out_val is not None else (yield i **2)
        i += 1
        print('do i++, i= %d' %(i))

x_sq = x_square_gen()
x_sq.throw(ValueError) #在yield语句内引发一个异常如下
'''
Traceback (most recent call last):
  File ".\chapter8.py", line 326, in 
    x_sq.throw(ValueError) #在yield语句内引发一个异常
  File ".\chapter8.py", line 225, in square_gen
    out_val = (yield out_val ** 2) if out_val is not None else (yield i **2) ##获取send的值的关键 左边有变量的yield语句,会获取send的值以后不会冻结    
ValueError
'''
x_sq.close()
#print(next(x_sq)) # 引发异常如下
'''
Traceback (most recent call last):
  File ".\chapter8.py", line 337, in 
    print(next(x_sq)) # 异常
StopIteration
'''


6.运算符重载的特殊方法

6.1与数值运算符相关的特殊方法

与数值运算相关的运算符包括算术运算符、位运算符等,开发人员可以为自定义类共如下方法来为对应的运算符进行重载:

● object.__add__(self, other):加法运算,为“+”运算符提供支持。

● object.__sub__(self, other):减法运算,为“-”运算符提供支持。

● object.__mul__(self, other):乘法运算,为“*”运算符提供支持。

● object.__matmul__(self, other):矩阵乘法,为"@"运算符提供支持。

● object.__truediv__(self, other):除法运算,为"/"运算符提供支持。

● object.__floordiv__(self, other):整除运算,为"//"运算符提供支持。

● object.__mod__(self, other):求余运算,为“%”运算符提供支持。

● object.__divmod__(self, other):求余运算,为divmod运算符提供支持。

● object.__pow__(self, other):乘方运算,为“**”运算符提供支持。

● object.__lshift__(self, other):左移运算,为"<<"运算符提供支持。

● object.__rshift__(self, other):右移运算,为“>>”运算符提供支持。

● object.__and__(self, other):按位与运算,为“&”运算符提供支持。

● object.__xor__(self, other):按位异或运算,为“^”运算符提供支持。

● object.__or__(self, other):按位或运算,为"|"运算符提供支持。

以上方法还有一个带r的版本,如__radd__()方法,Python会首先尝试使用x的__add__方法进行计算,如果x没有提供__add__方法,Python还会尝试调用y的__radd__方法进行计算。简单的说,如果自定义类提供了__rxxx__方法,那么该自定义类的对象就可以出现在对应运算符的右边。
此外,Python还支持各种扩展后的赋值运算符

object.__iadd __(self, other):为“+=”运算符提供支持
object.__isub __(self, other):为“-=”运算符提供支持
object.__imul __(self, other):为“*=”运算符提供支持
object.__imatmul __(self, other):为“@=”运算符提供支持
object.__itruediv __(self, other):为“/=”运算符提供支持
object.__ifloordiv __(self, other):整除运算,为“//=”运算符提供支持
object.__imod __(self, other):为“%=”运算符提供支持
object.__ipow __(self, other[,modulo]):为“**=”运算符提供支持
object.__ilshift __(self, other):为“<<=”运算符提供支持
object.__irshift __(self, other):为“>>=”运算符提供支持
object.__iand __(self, other):为“&=”运算符提供支持
object.__ixor __(self, other):为“^=”运算符提供支持
object.__ior __(self, other):为“|=”运算符提供支持

6.2与比较运算符相关的特殊方法

object.__lt __(self, other):为“<”运算符提供支持
object.__le __(self, other):为“<=”运算符提供支持
object.__eq __(self, other):为“==”运算符提供支持
object.__ne __(self, other):为“!=”运算符提供支持
object.__gt __(self, other):为“>”运算符提供支持
object.__ge __(self, other):为“>=”运算符提供支持

虽然Python为每个比较运算符都提供了特殊方法,但实际上往往并不需要实现这么多的特殊方法,对于同一个类的实例比较大小而言,通常只要实现其中三个方法即可。因为在实现__gt__()方法之后,程序即可使用“>”和“<”两个运算符,在实现__eq__()方法之后,程序即可使用"=="和“!=”两个运算符;在实现__ge__()方法之后,程序即可使用">="和"<="两个运算符。

6.3 与单目运算符相关的特殊方法

object.__neg __(self):为单目求负(-)运算符提供支持
object.__pos __(self):为单目求正(+)运算符提供支持
object.__invert __(self):为单目取反(~)运算符提供支持

6.4与类型转换相关的特殊方法

object.__str __(self):对应于调用内置的str()函数将该对象转换成字符串
object.__bytes __(self):对应于调用内置的bytes()函数将该对象转换成字节内容,返回bytes对象
object.__complex __(self):对应于调用内置的complex()函数将该对象转换成复数,返回complex对象
object.__int __():对应于调用内置的int()函数对象转换成整数,返回int对象
object.__float __():对应于调用内置的float()函数对象转换成整数,返回float对象

6.5 与常见的内建函数相关的特殊方法

object.__format __(self,format_spec):对应于调用内置的format()函数将对象转换成格式化字符串
object.__hash __(self):对应于调用内置的hash()函数来获取该对象的hash码
object.__abs __(self):对应于调用内置的abs()函数返回绝对值
object.__round __(self[, ndigits]):对应于调用内置的round()函数执行四舍五入取整
object.__trunc __(self):对应于调用内置的trunc()函数执行截断取整
object.__floor __(self):对应于调用内置的floor()函数执行向下取整
object.__ceil __(self):对应于调用内置的ceil()函数执行向上取整
 

扑克牌比大小

自定义代表扑克牌的Card 类(包括花色和牌面值),为Card 类提供自定义的比较大小的运算符支持, 大小比较标准是先比较牌面值,如果牌面值相等则比较花色,花色大小规则为: 黑桃>红心>草花>方块。

 
​
flowers = ('♦', '♣', '♥', '♠')
values = ('2', '3', '4', '5',
          '6', '7', '8', '9',
          '10', 'J', 'Q', 'K', 'A')
​
​
class Card:
    # 定义构造函数
    def __init__(self, flower, value):
        self.flower = flower
        self.value = value
​
    def __gt__(self, other):
        if not isinstance(other, Card):
            raise TypeError('+运算要求目标是Card')
        if values.index(self.value) > values.index(other.value):
            return True
        elif values.index(self.value) == values.index(other.value) and \
            flowers.index(self.flower) > flowers.index(other.flower):
            return True
        else:
            return False
​
    def __eq__(self, other):
        if not isinstance(other, Card):
            raise TypeError('+运算要求目标是Card')
        if values.index(self.value) == values.index(other.value) and \
            flowers.index(self.flower) == flowers.index(other.flower):
            return True
        else:
            return False
​
    def __ge__(self, other):
        if not isinstance(other, Card):
            raise TypeError('+运算要求目标是Card')
        return self > other or self == other
​
    def __repr__(self):
        return '%s-%s' % (self.flower, self.value)
​
​
if __name__ == "__main__":
    cd1 = Card(flower="♠", value="A")
    cd2 = Card(flower="♠", value="K")
    cd3 = Card(flower="♥", value="K")
    cd4 = Card(flower="♥", value="J")
    cd5 = Card(flower="♥", value="K")
    print(cd1 > cd2)    # True
    print(cd1 < cd2)    # False
    print(cd2 < cd3)    # False
    print(cd2 > cd3)    # True
    print(cd3 == cd5)    # True
    print(cd3 < cd5)    # False
    print(cd3 > cd5)    # False
    print(cd3 >= cd5)    # True
    print(cd3 <= cd5)    # True
​

 

你可能感兴趣的:(Python)