第八章 python 类的特殊方法

python 类的特殊方法

  • 一、常用的特殊方法
      • 1. 初始化__ init __ 方法
      • 2. 重写__repr__方法
      • 3. 析构方法:__del __
      • 4. __dir__方法
      • 5. __dict__属性
      • 6. __ getattr __ 、__setattr__等
  • 二、与反射相关的属性和方法
      • 1. 动态操作属性(hasattr、getattr、setattr)
      • 2. __call__属性(调用属性)
  • 三、与序列相关的特殊方法
      • 1. 序列相关方法(_ len _ (self)、_ getitem _ (self, key)、_ contains _ (self, item)、_ setitem _ (self, key, value)、_ delitem _(self, key))
      • 2. 实现迭代器(_ iter _ (self)、_ reversed _(self))
      • 3. 扩展列表、元组和字典
  • 四、生成器
      • 1. 创建生成器(yield)
      • 2. 生成器的方法(send()方法)
  • 五、运算符重载的特殊方法
      • 1. 与数值运算符相关的特殊方法
      • 2. 与比较运算符相关的特殊方法
      • 3. 与单目运算符相关的特殊方法
      • 4. 与类型转换相关的特殊方法
      • 5. 与常见的内建函数相关的特殊方法

一、常用的特殊方法

1. 初始化__ init __ 方法

称为构造方法,用于构造该类的对象,python通过调用构造方法返回该类的对象(无须使用new),用于初始化python对象

2. 重写__repr__方法

语法格式:
类名[field1=值1, field2=值2,…]

代码如下:

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) + "]"
a = Apple("红色" , 5.68)
# 打印Apple对象
print(a)

3. 析构方法:__del __

与_init_()方法对应的是_del_()方法,_ init _ () 方法用于初始化Python对象,而_del_()
则用于销毁Python对象一在任何Python对象将要被系统回收之时,系统都会自动调用该对象的_del_()方法。

4. __dir__方法

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

5. __dict__属性

_dict_属性用于査看对象内部存储的所有属性名和属性值组成的字典,通常程序直接使用该属性即可。程序使用_dict_属性既可查看对象的所有内部状态,也可通过字典语法来访问或修改指定属性的值。例如如下程序。

代码如下:

class Item:
    def __init__ (self, name, price):
        self.name = name
        self.price = price
im = Item('鼠标', 28.9)
print(im.__dict__)  # ①
# 通过__dict__访问name属性
print(im.__dict__['name'])
# 通过__dict__访问price属性
print(im.__dict__['price'])
im.__dict__['name'] = '键盘'
im.__dict__['price'] = 32.8
print(im.name) # 键盘
print(im.price) # 32.8

6. __ getattr __ 、__setattr__等

当程序操作(包括访问、设置、删除)对象的属性时,Python系统同样会执行该对象特定的方法。
这些方法共涉及如下几个:
_ getattribute _(self, name):当程序访问对象的name属性时被自动调用。
_ getattr _(self, name):当程序访问对象的name属性且该属性不存在时被自动调用。
_ setattr _(self, name, value):当程序对对象的name属性赋值时被自动调用。
_ delattr _(self, name):当程序删除对象的name属性时被自动调用。

代码如下:

class Rectangle:
    def __init__ (self, width, height):
        self.width = width
        self.height = height
    def __setattr__(self, name, value):
        print('----设置%s属性----' % name)
        if name == 'size':
            self.width, self.height = value
        else:
            self.__dict__[name] = value
    def __getattr__(self, name):
        print('----读取%s属性----' % name)
        if name == 'size':
            return self.width, self.height
        else:
            raise AttributeError
    def __delattr__(self, name):
        print('----删除%s属性----' % name)
        if name == 'size':
            self.__dict__['width'] = 0
            self.__dict__['height'] = 0
           
rect = Rectangle(3, 4)
print(rect.size)
rect.size = 6, 8
print(rect.width)
del rect.size
print(rect.size)

>> ----设置width属性----
>> ----设置height属性----
>> ----读取size属性----
>> (3, 4)
>> ----设置size属性----
>> ----设置width属性----
>> ----设置height属性----
>> 6
>> ----删除size属性----
>> ----读取size属性----
>> (0, 0)

如果程序需要在读取、设置属性之前进行某种拦截处理(比如检査数据是否合法之类的),也可通过重写_setattr_ ()或_getattribute_方法来实现。

代码如下:

class User:
    def __init__ (self, name, age):
        self.name = name
        self.age = age
    # 重写__setattr__()方法对设置的属性值进行检查
    def __setattr__ (self, name, value):
        # 如果正在设置name属性
        if name == 'name':
            if 2 < len(value) <= 8:
                self.__dict__['name'] = value
            else:
                raise ValueError('name的长度必须在2~8之间')
            
        elif name == 'age':
            if 10 < value < 60:
                self.__dict__['age'] = value
            else:
                raise ValueError('age值必须在10~60之间')
            
u = User('fkit', 24)
print(u.name)
print(u.age)
#u.name = 'fk' # 引发异常
u.age = 2  # 引发异常

二、与反射相关的属性和方法

1. 动态操作属性(hasattr、getattr、setattr)

在动态检査对象是否包含某些属性(包括方法)相关的函数有如下几个。

判断:hasattr(obj, name):检査/判断obj对象是否包含名为name的属性或方法。

获取:getattr(object, name[, default]):获取object对象中名为name的属性的属性值。

改变/添加:setattr(obj, name, value, /):将 obj 对象的 name 属性设为 value,改变/添加python对象的属性照顾。

代码如下:

class Comment:
    def __init__ (self, detail, view_times):
        self.detail = detail
        self.view_times = view_times
    def info ():
        print("一条简单的评论,内容是%s" % self.detail)
        
c = Comment('疯狂Python讲义很不错', 20)
# 判断是否包含指定的属性或方法
print(hasattr(c, 'detail')) # True
print(hasattr(c, 'view_times')) # True
print(hasattr(c, 'info')) # True
# 获取指定属性的属性值
print(getattr(c, 'detail')) # '疯狂Python讲义很不错'
print(getattr(c, 'view_times')) # 20
# 由于info是方法,故下面代码会提示:name 'info' is not defined
#print(getattr(c, info, '默认值'))
# 为指定属性设置属性值
setattr(c, 'detail', '天气不错')
setattr(c, 'view_times', 32)
# 输出重新设置后的属性值
print(c.detail)
print(c.view_times)

# 设置不存在的属性,即为对象添加属性
setattr(c, 'test', '新增的测试属性')
print(c.test) # 新增的测试属性

def bar ():
    print('一个简单的bar方法')
# 将c的info方法设为bar函数    
setattr(c, 'info', bar)
c.info() # 方法调用方法,info()方法调用bar()函数

# 将c的info设置为字符串'fkit'
setattr(c, 'info', 'fkit')
c.info() # 方法设置为字符串,报错TypeError

2. __call__属性(调用属性)

程序可用hasattr()函数判断指定属性(或方法)是否存在,但到底是属性还是方法,则需要进一步判断它是否可调用。程序可通过判断该属性(或方法)是否包含_call_属性来确定它是否可调用。

代码如下:

class User:
    def __init__(self, name, passwd):
        self.name = name
        self.passwd = passwd
    def validLogin (self):
        print('验证%s的登录' % self.name)        
u = User('crazyit', 'leegang')
# 判断u.name是否包含__call__方法,即判断是否可调用
print(hasattr(u.name, '__call__')) # False
# 判断u.passwd是否包含__call__方法,即判断是否可调用
print(hasattr(u.passwd, '__call__')) # False
# 判断u.validLogin是否包含__call__方法,即判断是否可调用
print(hasattr(u.validLogin, '__call__')) # True

# 定义Role类
class Role:
    def __init__ (self, name):
        self.name = name
    # 定义__call__方法
    def __call__(self):
        print('执行Role对象')
r = Role('管理员')
# 直接调用Role对象,就是调用该对象的__call__方法
r() # r() = r__call__()

def foo ():
    print('--foo函数--')
# 下面示范了2种方式调用foo()函数,效果完全相同
foo()
foo.__call__()

三、与序列相关的特殊方法

1. 序列相关方法(_ len _ (self)、_ getitem _ (self, key)、_ contains _ (self, item)、_ setitem _ (self, key, value)、_ delitem _(self, key))

  • 元素个数:_ len _(self):该方法的返回值决定序列中元素的个数。
  • 获取元素:_ getitem _ (self, key):该方法获取指定索引对应的元素。该方法的key应该是整数值或slice对象,否则该方法会引发KeyError异常。
  • 判断元素:_ contains _(self, item):该方法判断序列是否包含指定元素。
  • 设置/修改元素:_ setitem _(self, key, value):该方法设置指定索引对应的元素。该方法的key应该是整数值或slice对象,否则该方法会引发KeyError异常。
  • 删除元素:_ 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

2. 实现迭代器(_ iter _ (self)、_ reversed _(self))

需要实现迭代器,只要实现如下两个方法即可。

  • _ iter _(self):该方法返回一个迭代器(iterator),迭代器必须包含一个 _ next _()方法,该方法返回迭代器的下一个元素。

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

代码如下:

class Fibs:
    def __init__(self, len):
        self.first = 0
        self.sec = 1
        self.__len = len
    # 定义迭代器所需的__next__方法
    def __next__(self):
        # 如果__len__属性为0,结束迭代
        if self.__len == 0:
            raise StopIteration
        # 完成数列计算:
        self.first, self.sec = self.sec, self.first + self.sec
        # 数列长度减1
        self.__len -= 1
        return self.first
    # 定义__iter__方法,该方法返回迭代器
    def __iter__(self):
        return self
# 创建Fibs对象
fibs = Fibs(10)
# 获取迭代器的下一个元素
print(next(fibs))
# 使用for-in循环遍历迭代器
for el in fibs:
    print(el, end=' ')
# 将列表转换为迭代器
my_iter = iter([2, 'fkit', 4])
# 依次获取迭代器的下一个元素
print(my_iter.__next__()) # 2
print(my_iter.__next__()) # fkit

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

如果程序明确需要一个特殊的列表、元组或字典类,我们有两种选择。

  • 自己实现序列、迭代器等各种方法,自己来实现这个特殊的类。
  • 扩展系统已有的列表、元组或字典。

代码如下:

# 定义ValueDict类,继承dict类
class ValueDict(dict):
    # 定义构造函数
    def __init__(self, *args, **kwargs):
        # 调用父类的构造函数
        super().__init__(*args, **kwargs)
    # 新增getkeys方法
    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)
# 获取92对应的所有key
print(my_dict.getkeys(92)) # ['语文', '英语']
my_dict['编程'] = 92
print(my_dict.getkeys(92)) # ['语文', '英语', '编程']

四、生成器

生成器和迭代器的功能非常相似,它也会提供_next_()方法,这意味着程序同样可调用内置的next。函数来获取生成器的下一个值,也可使用fbr循环来遍历生成器。
生成器与迭代器的区别在于:迭代器通常是先定义一个迭代器类,然后通过创建实例来创建迭代器;而生成器则是先定义一个包含yield语句的函数,然后通过调用该函数来创建生成器。

1. 创建生成器(yield)

创建生成器需要两步操作。
①定义一个包含yield语句的函数。
②调用第①步创建的函数得到生成器。

差值递增数列

def test(val, step):
    print("--------函数开始执行------")
    cur = 0
    # 遍历0~val
    for i in range(val):
        # cur添加i*step
        cur += i * step
        yield cur
#        print(cur, end=' ')
# 执行函数,返回生成器
t = test(10, 2)
print('=================')
# 获取生成器的第一个值
print(next(t)) # 0,生成器“冻结”在yield处
print(next(t)) # 2,生成器再次“冻结”在yield处

for ele in t:
    print(ele, end=' ')

# 再次创建生成器
t = test(10, 1)
# 将生成器转换成列表
print(list(t))
# 再次创建生成器
t = test(10, 3)
# 将生成器转换成列表
print(tuple(t))

>> =================
>> --------函数开始执行------
>> 0
>> 2
>> 6 12 20 30 42 56 72 90 --------函数开始执行------
>> [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
>> --------函数开始执行------
>> (0, 3, 9, 18, 30, 45, 63, 84, 108, 135)

yield cur语句的作用有两点。

  • 每次返回一个值,有点类似于return语句。
  • 冻结执行,程序每次执行到yield语句时就会被暂停。

在程序被yield语句冻结之后,当程序再次调用next()函数获取生成器的下一个值时,程序才会继续向下执行。
需要指出的是,调用包含yield语句的函数并不会立即执行,它只是返回一个生成器。只有当程序通过next。函数调用生成器或遍历生成器时,函数才会真正执行。

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

  • 使用fbr循环的生成器推导式。
  • 调用带yield语句的生成器函数。

生成器是Python的一个特色功能,在其他语言中往往没有对应的机制,因此很多Python开发者对生成器机制不甚了解。但实际上生成器是一种非常优秀的机制,以我们实际开发的经验来看,使用生成器至少有以下几个优势。

  • 当使用生成器来生成多个数据时,程序是按需获取数据的,它不会一开始就把所有数据都生成出来,而是每次调用next()获取下一个数据时,生成器才会执行一次,因此可以减少代码的执行次数。比如前面介绍的示例,程序不会一开始就把生成器函数中的循环都执行完成,而是每次调用next。时才执行一次循环体。
  • 当函数需要返回多个数据时,如果不使用生成器,程序就需要使用列表或元组来收集函数返回的多个值,当函数要返回的数据量较大时,这些列表、元组会带来一定的内存开销;
    如果使用生成器就不存在这个问题,生成器可以按需、逐个返回数据。
  • 使用生成器的代码更加简洁。

2. 生成器的方法(send()方法)

外部程序通过send。方法发送数据。
生成器函数使用yield语句接收收据。

代码如下:

def square_gen(val):
    i = 0
    out_val = None
    while True:
        # 使用yield语句生成值,使用out_val接收send()方法发送的参数值
        out_val = (yield out_val ** 2) if out_val is not None else (yield i ** 2)
        # 如果程序使用send()方法获取下一个值,out_val会获取send()方法的参数
        if out_val is not None : print("====%d" % out_val)
        i += 1

sg = square_gen(5)
# 第一次调用send()方法获取值,只能传入None作为参数
print(sg.send(None))  # 0
print(next(sg))  # 1
print('--------------')
# 调用send()方法获取生成器的下一个值,参数9会被发送给生成器
print(sg.send(9))  # 81
# 再次调用next()函数获取生成器的下一个值
print(next(sg))  # 9

# 让生成器引发异常
#sg.throw(ValueError)

# 关闭生成器
sg.close()
print(next(sg)) # StopIteration

生成器还提供了如下两个常用方法。

  • close():该方法用于停止生成器。
  • throw():该方法用于在生成器内部(yield语句内)引发一个异常。

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

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[, modulo]):乘方运算,为”** ”运算符提供支持。
object._ lshift_(self, other):左移运算,为“<<”运算符提供支持。
object._ rshift_(self, other):右移运算,为“>>”运算符提供支持。
object._ and_(self, other):按位与运算,为“&”运算符提供支持。
object._ xor_(self, other):按位异或运算,为"^“运算符提供支持。
object._ or_(self, other):按位或运算,为”|"运算符提供支持。

代码如下:

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    # 定义setSize()函数
    def setSize (self , size):
        self.width, self.height = size
    # 定义getSize()函数
    def getSize (self):
        return self.width, self.height
    # 使用property定义属性
    size = property(getSize, setSize)
    # 定义__add__方法,该对象可执行+运算
    def __add__(self, other):
        # 要求参与+运算的另一个运算数必须是Rectangle
        if not isinstance(other, Rectangle):
            raise TypeError('+运算要求目标是Rectangle')
        return Rectangle(self.width + other.width, self.height + other.height)
    def __repr__(self):
        return 'Rectangle(width=%g, height=%g)' % (self.width, self.height)
r1 = Rectangle(4, 5)
r2 = Rectangle(3, 4)
# 对两个Rectangle执行加法运算
r = r1 + r2
print(r) # Rectangle(width=7, height=9)

当程序执行x + y运算时,Python首先会尝试使用X的_add_方法进行计算;如果x没有提
供_3£1<1_方法,Python还会尝试调用y M_radd_^法进行计算。这意味着上面介绍的各种数值运算相关方法,还有一个带r的版本。
object._ radd_(self other):当 y 提供该方法时,可执行 x + y。
object._ rsub_(self, other):当 y 提供该方法时,可执行 x - y。
object._ rmul_(self, other):当 y 提供该方法时,可执行 x * y。
object._ rmatmul_(self, other):当 y 提供该方法时,可执行 x @ y。
object._ rtruediv_(self, other):当 y 提供该方法时,可执行 x / y。
object._ rfloordiv_(self, other):当 y 提供该方法时,可执行 x // y。
object._ rmod_(self, other):当 y 提供该方法时,可执行 x % y。
object._ rdivmod_(self, other):当 y 提供该方法时,可执行 x divmod y。
object._ rpow_(self, other):当 y 提供该方法时,可执行 x ** y。
object._ rlshift_(self, other):当 y 提供该方法时,可执行 x << y。
object._ rrshift_(self, other):当 y 提供该方法时,可执行 x >> y。
object._ rand_(self, other):当 y 提供该方法时,可执行 x & y。
object._ rxor_(self, other):当 y 提供该方法时,可执行 x ^y。
object._ ror_(self, other):当y提供该方法时,可执行x | y。

简单来说,如果自定义类提供了上面列出的_rxxx_()方法,那么该自定义类的对象就可以出现在对应运算符的右边。

代码如下:

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    # 定义setSize()函数
    def setSize (self , size):
        self.width, self.height = size
    # 定义getSize()函数
    def getSize (self):
        return self.width, self.height
    # 使用property定义属性
    size = property(getSize, setSize)
    # 定义__radd__方法,该对象可出现在+的右边
    def __radd__(self, other):
        # 要求参与+运算的另一个运算数必须是数值
        if not (isinstance(other, int) or isinstance(other, float)):
            raise TypeError('+运算要求目标是数值')
        return Rectangle(self.width + other, self.height + other)
    def __repr__(self):
        return 'Rectangle(width=%g, height=%g)' % (self.width, self.height)
r1 = Rectangle(4, 5)
# r1有__radd__方法,因此它可以出现在+运算符的右边
r = 3 + r1
print(r) # Rectangle(width=7, height=8)

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):为”|="运算符提供支持。

代码如下:

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    # 定义setSize()函数
    def setSize (self , size):
        self.width, self.height = size
    # 定义getSize()函数
    def getSize (self):
        return self.width, self.height
    # 使用property定义属性
    size = property(getSize, setSize)
    # 定义__iadd__方法,该对象可支持+=运算
    def __iadd__(self, other):
        # 要求参与+=运算的另一个运算数必须是数值
        if not (isinstance(other, int) or isinstance(other, float)):
            raise TypeError('+=运算要求目标是数值')
        return Rectangle(self.width + other, self.height + other)
    def __repr__(self):
        return 'Rectangle(width=%g, height=%g)' % (self.width, self.height)
r = Rectangle(4, 5)
# r有__iadd__方法,因此它支持+=运算
r += 2
print(r) # Rectangle(width=6, height=7)

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

object._ It_(selfi other):为“<”运算符提供支持。
object._ le_(sel£ other):为“<=”运算符提供支持。
object._ eq_(sel£ other):为“==”运算符提供支持。
object._ ne_(selC other):为“!=”运算符提供支持。
object._ gt_(self, other):为“>”运算符提供支持。
object._ ge_(sel£ other):为“>="运算符提供支持。

代码如下:

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    # 定义setSize()函数
    def setSize (self , size):
        self.width, self.height = size
    # 定义getSize()函数
    def getSize (self):
        return self.width, self.height
    # 使用property定义属性
    size = property(getSize, setSize)
    # 定义__gt__方法,该对象可支持>和<比较
    def __gt__(self, other):
        # 要求参与>运算的另一个运算数必须是Rectangle
        if not isinstance(other, Rectangle):
            raise TypeError('>运算要求目标是Rectangle')
        return True if self.width * self.height > other.width * other.height else False
    # 定义__eq__方法,该对象可支持==和!=比较
    def __eq__(self, other):
        # 要求参与==运算的另一个运算数必须是Rectangle
        if not isinstance(other, Rectangle):
            raise TypeError('==运算要求目标是Rectangle')
        return True if self.width * self.height == other.width * other.height else False
    # 定义__ge__方法,该对象可支持>=和<=比较
    def __ge__(self, other):
        # 要求参与>=运算的另一个运算数必须是Rectangle
        if not isinstance(other, Rectangle):
            raise TypeError('>=运算要求目标是Rectangle')
        return True if self.width * self.height >= other.width * other.height else False 
    def __repr__(self):
        return 'Rectangle(width=%g, height=%g)' % (self.width, self.height)
r1 = Rectangle(4, 5)
r2 = Rectangle(3, 4)
print(r1 > r2) # True
print(r1 >= r2) # True
print(r1 < r2) # False
print(r1 <= r2) # False
print(r1 == r2) # False
print(r1 != r2) # True
print('------------------')
r3 = Rectangle(2, 6)
print(r2 >= r3) # True
print(r2 > r3) # False
print(r2 <= r3) # True
print(r2 < r3) # False
print(r2 == r3) # True
print(r2 != r3) # False

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

Python还提供了 + (单目求正)、-(单目求负)、~ (单目取反)等运算符;这些运算符也有对应的特殊方法。
object._ neg_(self):为单目求负(-)运算符提供支持。
object._ pos_(self):为单目求正(+)运算符提供支持。
object._ invert_(self):为单目取反(〜)运算符提供支持。

代码如下:

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    # 定义setSize()函数
    def setSize (self , size):
        self.width, self.height = size
    # 定义getSize()函数
    def getSize (self):
        return self.width, self.height
    # 使用property定义属性
    size = property(getSize, setSize)
    # 定义__neg__方法,该对象可执行求负(-)运算
    def __neg__(self):
        self.width, self.height = self.height, self.width
    def __repr__(self):
        return 'Rectangle(width=%g, height=%g)' % (self.width, self.height)
r = Rectangle(4, 5)
# 对Rectangle执行求负运算
-r
print(r) # Rectangle(width=5, height=4)

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

Python提供了 str()、int()、float。、complex。等函数(其实是这些类的构造器)将其他类型的对象转换成字符串、整数、浮点数和复数,这些转换同样也是由特殊方法在底层提供支持的。下面是这些特殊方法。

object._ str_(self):对应于调用内置的strQ函数将该对象转换成字符串。
object._ bytes_(self):对应于调用内置的bytes。函数将该对象转换成字节内容。该方法应
该返回bytes对象。
object._ complex_(self):对应于调用内置的complex()函数将该对象转换成复数。该方法
应该返回complex对象。
object._ int_(self):对应于调用内置的int()函数将对象转换成整数。该方法应该返回int
对象。
object._ float_(self):对应于调用内置的float。函数将对象转换成浮点数。该方法应该返回
float对象。

代码如下:

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    # 定义setSize()函数
    def setSize (self , size):
        self.width, self.height = size
    # 定义getSize()函数
    def getSize (self):
        return self.width, self.height
    # 使用property定义属性
    size = property(getSize, setSize)
    # 定义__int__方法,程序可调用int()函数将该对象转成整数
    def __int__(self):
        return int(self.width * self.height)
    def __repr__(self):
        return 'Rectangle(width=%g, height=%g)' % (self.width, self.height)
r = Rectangle(4, 5)
print(int(r)) # 20

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

Python还提供了一些常见的内建函数,当使用这些内建的函数处理对象时,实际上也是由以下特殊方法来提供支持的。

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()函数执行向上取整。

代码如下:

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    # 定义setSize()函数
    def setSize (self , size):
        self.width, self.height = size
    # 定义getSize()函数
    def getSize (self):
        return self.width, self.height
    # 使用property定义属性
    size = property(getSize, setSize)
    # 定义__round__方法,程序可调用round()函数将该对象执行四舍五入取整
    def __round__(self, ndigits=0):
        self.width, self.height = round(self.width, ndigits), round(self.height, ndigits)
        return self
    def __repr__(self):
        return 'Rectangle(width=%g, height=%g)' % (self.width, self.height)
r = Rectangle(4.13, 5.56)
# 对Rectangle对象执行四舍五入取整
result = round(r, 1)
print(r) # Rectangle(width=4.1, height=5.6)
print(result) # Rectangle(width=4.1, height=5.6)

你可能感兴趣的:(python)