zoukankan      html  css  js  c++  java
  • part8-2 Python 类的特殊方法(算术、比较、单目运算符重载,类型转换的特殊方法,内建函数的特殊方法),类的特殊方法练习


    一、 运算符重载的特殊方法

    为自定义类提供特殊方法,让自定义类的对象也支持各种运算符的运算。

    1、 与数值运算相关的特殊方法
    与数值相关的算术运算符、位运算符等运算符都是由对应的方法提供支持。可以自行为自定义类提供下面这些方法。
    (1)、object.__add__(self, other):加法运算,为“+”运算提供支持。
    (2)、object.__sub__(self, other):减法运算,为“-”运算符提供支持。
    (3)、object.__mul__(self, other):乘法运算,为“*”运算符提供支持。
    (4)、object.__matmul__(self, other):矩阵乘法,为“@”运算符提供支持。
    (5)、object.__truediv__(self, other):除法运算,为“/”运算符提供支持。
    (6)、object.__floordiv__(self, other):整除运算,为“//”运算符提供支持。
    (7)、object.__mod__(self, other):求余运算,为“%”运算符提供支持。
    (8)、object.__divmod__(self, other):求余运算,为 divmod 运算符提供支持。
    (9)、object.__pow__(self, other[,modulo]):乘方运算,为“**”运算符提供支持。
    (10)、object.__lshift__(self, other):左移运算,为“<<”运算符提供支持。
    (11)、object.__rshift__(self, other):右移运算,为“>>”运算符提供支持。
    (12)、object.__and__(self, other):按位与运算,为“&”运算符提供支持。
    (13)、object.__xor__(self, other):按位异域运算,为“^”运算符提供支持。
    (14)、object.__or__(self, other):按位或运算,为“|” 运算符提供支持。

    只要为自定义类提供了这些方法,就可以直接用运算符来操作该类的实例,比如执行 x+y ,相当于调用 x.__add__(self,y),只要为 x 所属的类提供 __add__(self,other) 方法即可,如果自定义类没有提供对应的方法,程序会返回 NotImplemented。

    下面代码示例两个 Rectangle 类对象执行加法运算,只要为这个类提供 __add__(self, other) 方法即可,示例如下:
     1 class Rectangle:
     2     def __init__(self, width, height):
     3         self.width = width
     4         self.height = height
     5     # 定义 setsize() 函数
     6     def setsize(self, size):
     7         self.width, self.height = size
     8     # 定义 getsize() 函数
     9     def getsize(self):
    10         return self.width, self.height
    11     # 使用 property 定义属性
    12     size = property(getsize, setsize)
    13     # 定义__add__方法,该对象可执行“+”运算
    14     def __add__(self, other):
    15         # 要求参与 “+” 运算的另一个操作数必须是 Rectangle 对象
    16         if not isinstance(other, Rectangle):
    17             raise TypeError("加(+)运算要求目标是 Rectangle 类对象")
    18         # 返回的是 Rectangle 类对象
    19         return Rectangle(self.width + other.width, self.height + other.height)
    20     def __repr__(self):
    21         return "Rectange(width=%g, height=%g)" % (self.width, self.height)
    22 r1 = Rectangle(3, 6)
    23 r2 = Rectangle(5, 9)
    24 # 两个 Rectangle 对象执行加法运算
    25 r = r1 + r2
    26 print(r)        # 输出:Rectange(width=8, height=15)
    上面代码中为 Rectangle 类提供了 __add__ 方法,接下来 Rectangle 类的两个对象可以使用 “+” 执行加法运算,加法运算的结果仍是 Rectangle 类对象,这是由 __add__ 方法的返回值决定的。

    在对x、y 对象执行 x+y 运算时,首先使用 x 对象的 __add__ 方法进行计算;如果 x 对象没有提供 __add__ 方法,则会尝试调用y 对象的 __radd__ 方法进行计算,也就是上面这些与数值运算相关的特殊方法,还有一个带 r 的方法。这些方法如下所示:
    (1)、object.__radd__(self,other):当 y 提供该方法时,可执行 x + y。
    (2)、object.__rsub__(self,other):当 y 提供该方法时,可执行 x - y。
    (3)、object.__rmul__(self,other):当 y 提供该方法时,可执行 x * y。
    (4)、object.__rmatmul__(self,other):当 y 提供该方法时,可执行 x @ y。
    (5)、object.__rtruediv__(self,other):当 y 提供该方法时,可执行 x / y。
    (6)、object.__rfloordiv__(self,other):当 y 提供该方法时,可执行 x // y。
    (7)、object.__rmod__(self,other):当 y 提供该方法时,可执行 x % y。
    (8)、object.__rdivmod__(self,other):当 y 提供该方法时,可执行 x divmod y。
    (9)、object.__rpow__(self,other):当 y 提供该方法时,可执行 x ** y。
    (10)、object.__rlshift__(self,other):当 y 提供该方法时,可执行 x << y。
    (11)、object.__rrshift__(self,other):当 y 提供该方法时,可执行 x >> y。
    (12)、object.__rand__(self,other):当 y 提供该方法时,可执行 x & y。
    (13)、object.__rxor__(self,other):当 y 提供该方法时,可执行 x ^ y。
    (14)、object.__ror__(self,other):当 y 提供该方法时,可执行 x | y。

    也就是说,只要为自定义类提供了上面这些 __rxxx__() 方法时,该自定义类的对象就可以出现在对应运算符的右边。下面代码示例了为 Rectangle 类提供 __radd__() 方法,此时运算符左边的对象没有提供对应的运算方法时,同样可以执行运算。示例如下:
     1 class Rectangle:
     2     def __init__(self, width, height):
     3         self.width = width
     4         self.height = height
     5     # 定义 setsize() 函数
     6     def setsize(self, size):
     7         self.width, self.height = size
     8     # 定义 getsize() 函数
     9     def getsize(self):
    10         return self.width, self.height
    11     # 使用 property 定义属性
    12     size = property(getsize, setsize)
    13     # 定义__radd__方法,该对象可出现在“+”运算的右边
    14     def __radd__(self, other):
    15         # 要求参与 “+” 运算的另一个操作数必须是数值
    16         if not isinstance(other, int) or isinstance(other, float):
    17             raise TypeError("加(+)运算要求目标是数值")
    18         # 返回的是 Rectangle 类对象
    19         return Rectangle(self.width + other, self.height + other)
    20     def __repr__(self):
    21         return "Rectange(width=%g, height=%g)" % (self.width, self.height)
    22 r1 = Rectangle(3, 6)
    23 # 两个 Rectangle 对象执行加法运算
    24 r = 7 + r1
    25 print(r)        # 输出:Rectange(width=10, height=13)
    从上面代码最后一行的输出可知,为类提供了 __radd__方法,因此类的对象可出现在 “+” 运算符的右边,支持加法运算。

    此外,Python 还支持各种扩展后赋值运算符,这些运算符也是由特殊方法来提供支持,方法说明如下:
    (1)、object.__iadd__(self, other):为 “+=” 运算符提供支持。
    (2)、object.__isub__(self, other):为 “-=” 运算符提供支持。
    (3)、object.__imul__(self, other):为 “*=” 运算符提供支持。
    (4)、object.__imatmul__(self, other):为 “@=” 运算符提供支持。
    (5)、object.__itruediv__(self, other):为 “/=” 运算符提供支持。
    (6)、object.__ifloordiv__(self, other):为 “//=” 运算符提供支持。
    (7)、object.__imod__(self, other):为 “%=” 运算符提供支持。
    (8)、object.__ipow__(self, other[,modulo]):为 “**=” 运算符提供支持。
    (9)、object.__ilshift__(self, other):为 “<<=” 运算符提供支持。
    (10)、object.__irshift__(self, other):为 “>>=” 运算符提供支持。
    (11)、object.__iand__(self, other):为 “&=” 运算符提供支持。
    (12)、object.__ixor__(self, other):为 “^=” 运算符提供支持。
    (13)、object.__ior__(self, other):为 “|=” 运算符提供支持。

    下面代码为 Rectangle 类定义一个 __iadd__() 方法,使得该类的对象支持 “+=” 运算。示例如下:
     1 class Rectangle:
     2     def __init__(self, width, height):
     3         self.width = width
     4         self.height = height
     5     # 定义 setsize() 函数
     6     def setsize(self, size):
     7         self.width, self.height = size
     8     # 定义 getsize() 函数
     9     def getsize(self):
    10         return self.width, self.height
    11     # 使用 property 定义属性
    12     size = property(getsize, setsize)
    13     # 定义__iadd__方法,该对象可出现在“+”运算的右边
    14     def __iadd__(self, other):
    15         # 要求参与 “+” 运算的另一个操作数必须是数值
    16         if not isinstance(other, int) or isinstance(other, float):
    17             raise TypeError("加(+=)运算要求目标是数值")
    18         # 返回的是 Rectangle 类对象
    19         return Rectangle(self.width + other, self.height + other)
    20     def __repr__(self):
    21         return "Rectange(width=%g, height=%g)" % (self.width, self.height)
    22 r1 = Rectangle(3, 6)
    23 # r1 有 __iadd__ 方法,因此支持 “+=” 运算
    24 r1 += 7
    25 print(r1)        # 输出:Rectange(width=10, height=13)
    从输出可知,Rectangle 类的对象可以支持 “+=” 运算。

    2、 与比较运算符相关的特殊方法
    对于 >、<、>=、<=、== 和 != 等运算符也是由特殊方法提供支持的。如果为自定义类提供了这些特殊方法,该类的对象就可使用比较运算符来比较大小。与比较运算符相关的特殊方法有下面几个。
    (1)、object.__lt__(self, other):为 “<” 运算符提供支持。
    (2)、object.__le__(self, other):为 “<=” 运算符提供支持。
    (3)、object.__eq__(self, other):为 “==” 运算符提供支持。
    (4)、object.__ne__(self, other):为 “!=” 运算符提供支持。
    (5)、object.__gt__(self, other):为 “>” 运算符提供支持。
    (6)、object.__ge__(self, other):为 “>=” 运算符提供支持。

    上面这些比较运算符不需要每个都都实现,只需要实现其中三个方法即可。实现 __gt__() 方法后,可使用 “>” 和 “<” 两个运算符;
    实现 __eq__() 方法后,可使用 “==” 和 “!=” 两个运算符;实现 __ge__() 方法后,可使用 “>=” 和 “<=” 两个运算符。

    下面代码为 Rectangle 类提供这些特殊方法,使两个 Rectangle 类对象基于面积比较大小。示例如下:
     1 class Rectangle:
     2     def __init__(self, width, height):
     3         self.width = width
     4         self.height = height
     5     # 定义 setsize() 函数
     6     def setsize(self, size):
     7         self.width, self.height = size
     8     # 定义 getsize() 函数
     9     def getsize(self):
    10         return self.width, self.height
    11     # 使用 property 定义属性
    12     size = property(getsize, setsize)
    13     # 定义 __gt__ 方法,该对象可支持“>” 和 “<” 比较
    14     def __gt__(self, other):
    15         # 要求参与 “>” 比较的另一个操作数必须是 Rectangle 对象
    16         if not isinstance(other, Rectangle):
    17             raise TypeError('比较运算(>)要求目标是 Rectangle 类对象')
    18         return True if self.width * self.height > other.width * other.height else False
    19     # 定义 __eq__ 方法,该对象可支持 “==” 和 “!=” 比较
    20     def __eq__(self, other):
    21         # 要求参与 “==” 比较的另一个操作数必须是 Rectangle 类对象
    22         if not isinstance(other, Rectangle):
    23             raise TypeError("比较运算(==)要求目标是 Rectangle 类对象")
    24         return True if self.width * self.height == other.width * other.height else False
    25     # 定义 __ge__ 方法,该对象可支持 “>=” 和 “<=” 比较
    26     def __ge__(self, other):
    27         # 要求参与 “>=” 比较的另一个操作数必须是 Rectanlge 类对象
    28         if not isinstance(other, Rectangle):
    29             raise TypeError("比较运算(>=)要求目标是 Rectangle 类对象")
    30         return True if self.width * self.height >= other.width * other.height else False
    31     def __repr__(self):
    32         return "Rectange(width=%g, height=%g)" % (self.width, self.height)
    33 
    34 r1 = Rectangle(5, 6)
    35 r2 = Rectangle(3, 4)
    36 print(r1 > r2)          # 输出:True
    37 print(r1 >= r2)         # 输出:True
    38 print(r1 < r2)          # 输出:False
    39 print(r1 <= r2)         # 输出:False
    40 print(r1 == r2)         # 输出:False
    41 print(r1 != r2)         # 输出:True
    42 print('-'*20)
    43 r3 = Rectangle(3, 7)
    44 print(r2 > r3)          # 输出:False
    45 print(r2 >= r3)         # 输出:False
    46 print(r2 <= r3)         # 输出:True
    47 print(r2 < r3)          # 输出:True
    48 print(r2 == r3)         # 输出:False
    49 print(r2 != r3)         # 输出:True
    上面代码中,为 Rectangle 类定义了 __gt__()、__eq__()和 __ge__() 方法,接下来该类的对象可以使用各种比较运算符进行大小的比较。

    3、 与单目运算符相关的特殊方法
    单目运算符有:单目求正(+)、单目求负(-)、单目取反(~),这些运算也有对应的特殊方法。
    (1)、object.__neg__(self):为单目求负(-)运算符提供支持。
    (2)、object.__pos__(self):为单目求正(+)运算符提供支持。
    (3)、object.__invert__(self):为单目取反(~)运算符提供支持。

    下面代码为 Rectangle 类实现一个 __neg__() 方法,用于控制将矩形的宽、高交换。代码如下:
     1 class Rectangle:
     2     def __init__(self, width, height):
     3         self.width = width
     4         self.height = height
     5     # 定义 setsize() 函数
     6     def setsize(self, size):
     7         self.width, self.height = size
     8     # 定义 getsize() 函数
     9     def getsize(self):
    10         return self.width, self.height
    11     # 使用 property 定义属性
    12     size = property(getsize, setsize)
    13     # 定义 __neg__ 方法,该对象可执行求负(-)运算
    14     def __neg__(self):
    15         self.width, self.height = self.height, self.width
    16     def __repr__(self):
    17         return "Rectange(width=%g, height=%g)" % (self.width, self.height)
    18 r = Rectangle(3, 5)
    19 # 对 Rectangle 类的对象执行求负运算
    20 -r
    21 print(r)        # 输出:Rectange(width=5, height=3)
    上面代码为 Rectange 类实现了 __neg__ 方法,该类的对象即可执行求负运算,由于在 __neg__ 方法内部是交换矩形的宽和高,因此程序对 Rectangle 类对象执行求负运算其实交换矩形的宽和高。从输出可知矩形的宽和高已经交换。

    4、 与类型转换相关的特殊方法
    Python 提供的 str()、int()、float()、complex() 等函数(其实是这些类的构造器)可将其他类型的对象转换成字符串、整数、浮点数和复数,这些转换同样也是由特殊方法在底层提供支持。关于这些特殊方法说明如下:
    (1)、object.__str__(self):对应于调用内置的 str() 函数将该对象转换成字符串。
    (2)、object.__bytes__(self):对应于调用内置的 bytes() 函数将该对象转换成字节内容。该方法应返回 bytes 对象。
    (3)、object.__complex__(self):对应于调用内置的 complex() 函数将该对象转换成复数。该方法返回 complex 对象。
    (4)、object.__int__(self):对应于调用内置的 int() 函数将对象转换成整数。该方法返回 int 对象。
    (5)、object.__float__(self):对应于调用内置的 float() 函数将对象转换成浮点数。该方法返回 float 对象。

    要注意的是,__str__() 和 __repr__() 方法功能有些相似,都用于将对象转换成字符串。不同的是:__repr__ 表示“自我描述”的方法,在程序中调用 print() 函数输出对象时,Python 会自动调用该对象的 __repr__() 方法,而 __str__() 方法只有在显式调用 str() 时才会起作用。

    下面代码为 Rectangle 类实现一个 __int__() 方法,这样就可调用 int() 函数将 Rectangle 类对象转换成整数。示例如下:
     1 class Rectangle:
     2     def __init__(self, width, height):
     3         self.width = width
     4         self.height = height
     5     # 定义 setsize() 函数
     6     def setsize(self, size):
     7         self.width, self.height = size
     8     # 定义 getsize() 函数
     9     def getsize(self):
    10         return self.width, self.height
    11     # 使用 property 定义属性
    12     size = property(getsize, setsize)
    13     # 定义 __int__ 方法,这样可调用 int() 函数将该类对象转换成整数
    14     def __int__(self):
    15         return int(self.width * self.height)
    16     def __repr__(self):
    17         return "Rectange(width=%g, height=%g)" % (self.width, self.height)
    18 r = Rectangle(3, 5)
    19 print(int(r))           # 输出:15
    从上面代码的最一行输出可知,在类中实现的 __int__ 方法成功被调用,在这个方法中是计算的面积。

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

    调用内建函数处理对象时,也是由下面这些特殊方法来提供支持的。
    (1)、object.__format__(self, format_spec):对应于调用内置的 format() 函数将对象转换成格式化字符串。
    (2)、object.__hash__(self):对应于调用内置的 hash() 函数获取对象的 hash 值。
    (3)、object.__abs__(self):对应于调用内置的 abs() 函数返回值。
    (4)、object.__round__(self, ndigits):对应于调用内置的 round() 函数执行四舍五入取整。
    (5)、object.__trunc__(self):对应于调用内置的 trunc() 函数执行截断取整。
    (6)、object.__floor__(self):对应于调用内置的 floor() 函数执行向下取整
    (7)、object.__ceil__(self):对应于调用内置的 ceil() 函数执行向上取整。

    要注意的是,在自定义类中没有提供 __int__(self) 方法,但是提供了 __trunc__(self) 方法时,那么自定义类的对象在调用内置的 int() 函数转换成整数时,底层将由 __trunc__(self):方法提供支持。

    下面代码为 Rectangle 类实现一个 __round__() 方法,使其可调用 round() 函数对该类的对象执行四舍五入取整。示例如下:
     1 class Rectangle:
     2     def __init__(self, width, height):
     3         self.width = width
     4         self.height = height
     5     # 定义 setsize() 函数
     6     def setsize(self, size):
     7         self.width, self.height = size
     8     # 定义 getsize() 函数
     9     def getsize(self):
    10         return self.width, self.height
    11     # 使用 property 定义属性
    12     size = property(getsize, setsize)
    13     # 定义 __round__ 方法,使其可调用 round() 函数将对象执行四舍五入取整
    14     def __round__(self, n=None):
    15         self.width, self.height = round(self.width, n), round(self.height, n)
    16         return self
    17     def __repr__(self):
    18         return "Rectange(width=%g, height=%g)" % (self.width, self.height)
    19 
    20 r = Rectangle(3.14, 8.53)
    21 # 对 Rectangle 类对象执行四舍五入取整,__round__ 方法返回的是 self 对象,可用变量接收
    22 result = round(r, 1)
    23 print(r)                # 输出:Rectange(width=3.1, height=8.5)
    24 print(result)           # 输出:Rectange(width=3.1, height=8.5)
    从输出表明,在 Rectangle 类中定义 __round__() 方法后,该类的对象就可调用 round() 函数执行四舍五入取整。对于其他的特殊方法就不每个都去实现了。

    二、 小结
    Python 提供了大量有特殊意义的方法,这些方法有些可直接使用,有些需要重写,掌握这些方法是面向对象编程的基础。

    此外,序列和生成器也有与之相关的特殊方法;与运算符重载相关的特殊方法、与类型转换相关的特殊方法、与常见的内建函数相关的特殊方法等,要对这些方法加深理解。

    练习:

    1、自定义一个序列,该序列按顺序包含 52 张扑克牌,分别是黑桃、红心、梅花、方块的2~A。要求提供序列的各种操作方法。
     1 def check_key(key):
     2     if not isinstance(key, int): raise TypeError("索引值必须是整数")
     3     if key < 0: raise IndexError('索引值必须是非负数')
     4     if key >= 52: raise IndexError('索引值不能超过%d' % 52)
     5 
     6 class CardSeq:
     7     def __init__(self):
     8         self.flowers = ('', '', '', '')
     9         self.values = ('2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A')
    10         self.__changed = {}
    11         self.__deleted = []
    12     def __len__(self):
    13         return 52
    14     def __getitem__(self, item):
    15         check_key(item)
    16         # 如果在 self.__changed 中找到,就返回修改后的数据
    17         if item in self.__changed:
    18             return self.__changed[item]
    19         # 如果 item 在 self.__deleted 中找到,说明该元素已被删除
    20         if item in self.__deleted:
    21             return None
    22         # 否则根据计算返回序列元素
    23         flower = item // 13         # 花色通过对 13 整除获得
    24         value = item % 13           # 点数通过对 13 求余获得
    25         return self.flowers[flower] + self.values[value]
    26     def __setitem__(self, key, value):
    27         check_key(key)
    28         self.__changed[key] = value
    29     def __delitem__(self, key):
    30         check_key(key)
    31         # 如果 self.__deleted 列表中没有包含被删除的 key,添加被删除的 key
    32         if key not in self.__deleted: self.__deleted.append(key)
    33         # 如果 self.__changed 中包含被删除的 key,则需要删除它
    34         if key in self.__changed: del self.__changed[key]
    35 
    36 if __name__ == '__main__':
    37     cd = CardSeq()
    38     print(len(cd))          # 52
    39     print(cd[1])            # ♠3
    40     print(cd[9])            # ♠J
    41     # 修改 cd[1] 的元素
    42     cd[1] = '♣5'
    43     # 输出修改后的 cq[1]
    44     print(cd[1])            # ♣5
    45     # 删除 cd[1]
    46     del cd[1]
    47     print(cd[1])
    48     # 再次对 cd[1] 赋值      # None
    49     cd[1] = "♦A"
    50     print(cd[1])            # ♦A

    2、定义一个序列,该序列按顺序包含所有三位数(如100,101,102,...)。要求提供序列的各种操作方法。
    注意:序列的索引是从0开始,序列的第一个值是100。
     1 start = 100
     2 end = 999
     3 nums = end - start + 1      # 序列的总数
     4 def check_key(key):
     5     """检查要获取的序列索引是否符合要求"""
     6     if not isinstance(key, int): raise TypeError("索引值必须是整数")
     7     if key < 0: raise IndexError('索引值必须是非负数')
     8     if key >= nums: raise IndexError('索引值不能超过%d' % nums)
     9 def check_value(value):
    10     """检查要获取的序列值是否符合要求"""
    11     if not isinstance(value, int): raise TypeError("序列值必须是整数")
    12     if not (end >= value >= start): raise TypeError('序列值必须在%d和%d之间' % (start, end))
    13 
    14 class NumSeq:
    15     def __init__(self):
    16         self.__changed = {}
    17         self.__deleted = []
    18     def __len__(self):
    19         return nums
    20     def __getitem__(self, item):
    21         check_key(item)
    22         # 如果在 self.__changed 中找到已经修改后的数据,就返回修改后的数据
    23         if item in self.__changed:
    24             return self.__changed[item]
    25         # 如果 item 在 self.__deleted 中找到,说明该元素已经被删除,则返回 None
    26         if item in self.__deleted:
    27             return None
    28         # 起始值加索引的方式就是要在序列中获取的值
    29         return start + item
    30     def __setitem__(self, key, value):
    31         """根据索引(key)设置值(value)"""
    32         check_key(key)
    33         check_value(value)
    34         # 满足上面两个条件后设置值
    35         self.__changed[key] = value
    36     def __delitem__(self, key):
    37         """根据索引(key)删除值"""
    38         check_key(key)
    39         # 如果 self.__deleted 列表中没包含被删除的 key,添加被删除的 key
    40         if key not in self.__deleted: self.__deleted.append(key)
    41         # 如果 self.__changed 中包含被删除的 key,就删除它
    42         if key in self.__changed: del self.__changed[key]
    43 
    44 if __name__ == '__main__':
    45     nq = NumSeq()
    46     print(len(nq))          # 900
    47     print(nq[2])            # 102
    48     print(nq[1])            # 101
    49     # 修改 nq[1] 元素
    50     nq[1] = 111
    51     # 输出修改后的 nq[1]
    52     print(nq[1])            # 111
    53     # 删除 nq[1]
    54     del nq[1]
    55     print(nq[1])            # None
    56     # 再次对 nq[1] 赋值
    57     nq[1] = 666
    58     print(nq[1])            # 666

    3、 定义一个迭代器,该迭代器分别返回 1,1+2,1+2+3,...的累积和。
     1 class Sums:
     2     def __init__(self, length):
     3         self.current_index = 1
     4         self.current_value = 0
     5         self.__length = length
     6     # 定义迭代器所需的 __next__ 方法
     7     def __next__(self):
     8         if self.__length == 0:
     9             raise StopIteration
    10         # 完成数列计算
    11         self.current_value += self.current_index
    12         self.current_index += 1
    13         # 数列长度减1
    14         self.__length -= 1
    15         return self.current_value
    16     # 定义 __iter__ 方法,该方法返回迭代器
    17     def __iter__(self):
    18         return self
    19 
    20 sums = Sums(10)
    21 # 获取迭代器的下一个元素
    22 print(next(sums))       # 1
    23 for e in sums:
    24     print(e, end=" ")   # 3 6 10 15 21 28 36 45 55

    4、 定义一个生成器,该生成器可按顺序返回 52 张扑克牌,分别是黑桃、红心、梅花、方块的 2~A。
     1 def card_generator():
     2     nums = 52
     3     flowers = ('', '', '', '')
     4     values = ('2', '3', '4', '5', '6', '7', '8',
     5               '9', '10', 'J', 'Q', 'K', 'A')
     6     for i in range(nums):
     7         yield flowers[i // 13] + values[i % 13]
     8 
     9 if __name__ == '__main__':
    10     cg = card_generator()
    11     print(next(cg))         # ♠2,生成器冻结在 yield 处
    12     print(next(cg))         # ♠3,生成器再次冻结在 yield 处
    13     for e in cg:
    14         print(e, end=" ")

    5、定义一个生成器,可依次返回1,2,3,4,...,的阶乘。
    注意:需要先将阶乘计算后再返回。
     1 def factorial_generator(n):
     2     rvt_list = [1]
     3     for i in range(2, n + 1):
     4         rvt_list.append(rvt_list[-1] * i)
     5     print("----------", len(rvt_list))
     6     for i in range(n):
     7         yield rvt_list[i]
     8 
     9 if __name__ == '__main__':
    10     fg = factorial_generator(10)
    11     print(next(fg))     # 1,生成器被冻结在 yield 处
    12     print(next(fg))     # 2,生成器再次被冻结在 yield 处
    13     for e in fg:
    14         print(e, end=" ")

    6、定义一个生成器,可依次访问当前目录下的所有 Python 源文件(以.py 结尾的文件)。
     1 import os
     2 
     3 def files_generator():
     4     for filename in os.listdir(r'.'):
     5         if filename.endswith(".py"):
     6             yield filename
     7 
     8 if __name__ == '__main__':
     9     fg = files_generator()
    10     print(next(fg))
    11     print(next(fg))
    12     for e in fg:
    13         print(e, end=" ")

    7、 定义一个代表二维坐标系上某个点的 Point 类(有 x、y 两个属性),为 Point 类提供自定义的减法运算符支持,计算结果是两点之间的距离。
     1 class Point:
     2     def __init__(self, x, y):
     3         self.x = x
     4         self.y = y
     5     def __sub__(self, other):
     6         if not isinstance(other, Point): raise TypeError("要求另一个点必须是 Point 类对象")
     7         return ((self.x - other.x) ** 2 + (self.y - other.y) ** 2) ** 0.5
     8 
     9 if __name__ == "__main__":
    10     p1 = Point(3, 5)
    11     p2 = Point(10, 28)
    12     print(p1 - p2)      # 24.041630560342615
    13     print(p2 - p1)      # 24.041630560342615

    8、定义一个代表扑克牌的 Card 类(包括花色和点数),为 Card 类提供自定义的比较大小的运算符支持,大小比较标准是先比较点数,如果点数相等则比较花色,花色大小规则是:黑桃 > 红心 > 梅花 > 方块。
     1 flowers = ('', '', '', '')      # 按照从小到大顺序存放
     2 values = ('2', '3', '4', '5', '6', '7', '8',
     3           '9', '10', 'J', 'Q', 'K', 'A')
     4 class Card(object):
     5     def __init__(self, flower, value):
     6         self.flower = flower
     7         self.value = value
     8 
     9     def __gt__(self, other):
    10         if not isinstance(other, Card):
    11             raise TypeError('比较运算要求目标是 Card 类型')
    12         if values.index(self.value) > values.index(other.value):
    13             return True
    14         elif values.index(self.value)  == values.index(other.value) and 
    15             flowers.index(self.flower) > flowers.index(other.flower):
    16             return True
    17         else:
    18             return False
    19     def __eq__(self, other):
    20         if not isinstance(other, Card):
    21             raise TypeError('比较运算要求目标是 Card 类型')
    22         if values.index(self.value) == values.index(other.value) and 
    23             flowers.index(self.flower) == flowers.index(other.flower):
    24             return True
    25         else:
    26             return False
    27     def __ge__(self, other):
    28         if not isinstance(other, Card):
    29             raise TypeError('比较运算要求目标是 Card 类型')
    30         return self > other or self == other
    31     def __repr__(self):
    32         return '%s%s' % (self.flower, self.value)
    33 
    34 if __name__ == '__main__':
    35     cd1 = Card(flower="", value="A")
    36     cd2 = Card(flower='', value='K')
    37     cd3 = Card(flower='', value='K')
    38     cd4 = Card(flower='', value='J')
    39     cd5 = Card(flower='', value='K')
    40     cd6 = Card(flower='', value='K')
    41     print(cd1 > cd2)        # True
    42     print(cd1 < cd2)        # False
    43     print(cd2 < cd3)        # False
    44     print(cd2 > cd3)        # True
    45     print(cd3 == cd6)       # True
    46     print(cd3 < cd5)        # False
    47     print(cd3 > cd5)        # True
    48     print(cd3 >= cd6)       # True
    49     print(cd3 <= cd6)       # True
    50     print(cd2)              # ♠K
  • 相关阅读:
    eclipse maven项目 热部署
    二十三. Django ModelForm组件
    二十二 .Django生命周期
    二十二 .Django form上传+Ajax+FormData上传+Form组件上传+序列化+ifram伪造Ajax
    二十一. Django----ajax全部
    二十. Django ajax--请求数据 和模态对话框
    二十. Django分页 和自定义分页
    十九. Django-Cookie的CBV和FBV的用户验证装饰器
    十八 .Django session应用
    十七 .Django cookie应用
  • 原文地址:https://www.cnblogs.com/Micro0623/p/11813448.html
Copyright © 2011-2022 走看看