Python函数的重写

本文详细介绍了Python中如何重写函数,包括对象转字符串函数、内建函数、数值转换函数、布尔测试函数、迭代器、属性管理函数、异常处理和运算符重载等,以使自定义类的行为更接近内建对象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

函数重写

在自定义类内添加相应的方法,让自定义类创建的实例能像内建对象一样进行内建函数操作

对象转字符串函数:

repr(obj)     返回一个能代表此对象的表达式字符串,通常
         eval(repr(obj)) == obj  (这个字符串通常是给python解释执行器运行用的)

str(obj)  通过给定的对象返回一个字符串(这个字符串通常是给人阅读的)

对象转字符串函数的重写方法:

repr(obj) 函数的重写方法:
      def __repr__(self):

str(obj) 函数的重写方法:
      def __str__(self):

  说明:
    1. str(obj) 函数先查找, obj.__str__()方法,调用此方法并返回结果
    2. 如果没有obj.__str__()方法时,则返回obj.__repr__()方法的结果并返回
    3. 如果obj.__repr__方法不存在,则调用object类的__repr__实例方法显示<__main__.XXXX object at 0xAABBCCDD>格式的字符串

示例:

# 此示例示意通过重写 repr 和 str方法改变转为字符串的规则
class MyNumber:
    def __init__(self, value):
        '构造函数,初始化MyNumber对象'
        self.data = value

    def __str__(self):
        '''转换为普通人识别的字符串'''
        # print("__str__方法被调用!")
        return "自定义数字类型对象: %d" % self.data

    def __repr__(self):
        '''转换为eval能够识别的字符串'''
        return 'MyNumber(%d)' % self.data


n1 = MyNumber(100)
n2 = MyNumber(200)
print('repr(n1) ====>', repr(n1))
print('str(n2)  ====>', str(n2))

其它内建函数的重写方法:

  __abs__       abs(obj)  函数
  __len__       len(obj)  函数(必须返回整数)
  __reversed__  reversed(obj) 函数(必须返回可迭代对象
  __round__     round(obj)  函数

示例:

# 此示例示意abs 函数的重写
class MyInteger:

    def __init__(self, v):
        self.data = v

    def __repr__(self):
        return 'MyInteger(%d)' % self.data

    def __abs__(self):
        v = abs(self.data)
        return MyInteger(v)  # 用v创建另一个MyInteger对象

    def __len__(self):
        return 10000

I1 = MyInteger(-10)
print('I1 =', I1)

I2 = abs(I1)
print("I2 =", I2)

print('len(I2)=', len(I2))  # 10000

数值转换函数的重写:

  __complex__  complex(obj) 函数
  __int__      int(obj) 函数
  __float__    float(obj) 函数
  __bool__     bool(obj) 函数     (见下面布尔测试函数重载)

示例:

# 此示例示意数据转换构造函数的重写方法
class MyNumber:

    def __init__(self, value):
        self.data = value

    def __repr__(self):
        return 'MyNumber(%d)' % self.data

    def __int__(self):
        'int函数的重载'
        return self.data

n1 = MyNumber(100)
x = int(n1)
print(n1)

print(bool(n1))  # True
n2 = MyNumber(0)
print(bool(n2))  # True

布尔测试函数重写:

格式:
    __bool__
作用:
    用于bool(obj) 函数取值
    用于if语句的真值表达式中
    用于while 语句的真值表达式中
说明:
    1. 当自定义的类内有 __bool__(self) 方法时,以此方法的返回值作为bool(obj) 的返回值
    2. 当不存在__bool__(self) 方法时,bool(x) 返回__len__(self) 方法的返回值是否为零来测试布尔值
    3. 当不存在__len__(self) 方法时,则直接返回True

示例:

# 此示例示意bool(x) 函数的重写
class MyList:
    '自定义类型的列表,用来保存数据,内部用一个列表来存储数据'

    def __init__(self, iterable=()):
        self.data = [x for x in iterable]

    def __repr__(self):
        return 'MyList(%s)' % self.data

    def __len__(self):
        '''返回长度'''
        print("__len__方法被调用")
        return len(self.data)

    def __bool__(self):
        print("__bool__方法调用")
        for x in self.data:
            if not x:
                return False
        return True
        # return False  # <<=== 所有对象都为False

myl = MyList([0, -1, 2, -3])
# myl = MyList()
print(myl)
print(bool(myl))
if myl:
    print("myl为真值")
else:
    print('myl为假值')

迭代器(高级):

什么是迭代器
      可以通过next(it)函数取值的对象就是迭代器

迭代器协议
      迭代器协议是指对象能够使用next函数获取下一项数据,在没有下一项数据时触发一个StopIteration异常来终止迭代的约定

迭代器协议实现方法:
      __next__(self) 方法来实现迭代器协议

语法形式:
  class MyIterator:
      def __next__(self):
          迭代器协议
          return 数据
什么是可迭代对象:
      是指能用iter(obj) 函数返回迭代器的对象(实例)
      可迭代对象内部需要定义__iter__(self) 方法来返回迭代器对象

对象的属性管理函数:

getattr(obj, name[,default])         从一个对象得到对象的属性;getattr(x,'y') 等同于x.y,当属性不存在时,如果给出default参数则返回defualt, 如果没有给出default,则产生一个AttributeError错误

hasattr(obj, name)                    用给定的name返回对象obj是否有此属性,此种做法可以避免在getattr(obj,name) 时引发错误

setattr(obj, name, value)            给对象obj的名为name的属性设置相应的值value; set(x, 'y', z) 等同于 x.y = z

delattr(obj, name)                      删除对象obj中的name属性,delattr(x, 'y') 等同于 del x.y

 

hasattr(object, name)
    判断一个对象里面是否有name属性或者name方法,返回BOOL值,有name特性返回True, 否则返回False。
需要注意的是name要用括号括起来

1 >>> class test():
 2 ...     name="xiaohua"
 3 ...     def run(self):
 4 ...             return "HelloWord"
 5 ...
 6 >>> t=test()
 7 >>> hasattr(t, "name") #判断对象有name属性
 8 True
 9 >>> hasattr(t, "run")  #判断对象有run方法
10 True

getattr(object, name[,default])
    获取对象object的属性或者方法,如果存在打印出来,如果不存在,打印出默认值,默认值可选。
需要注意的是,如果是返回的对象的方法,返回的是方法的内存地址,如果需要运行这个方法,
可以在后面添加一对括号。

1 >>> class test():
 2 ...     name="xiaohua"
 3 ...     def run(self):
 4 ...             return "HelloWord"
 5 ...
 6 >>> t=test()
 7 >>> getattr(t, "name") #获取name属性,存在就打印出来。
 8 'xiaohua'
 9 >>> getattr(t, "run")  #获取run方法,存在就打印出方法的内存地址。
10 <bound method test.run of <__main__.test instance at 0x0269C878>>
11 >>> getattr(t, "run")()  #获取run方法,后面加括号可以将这个方法运行。
12 'HelloWord'
13 >>> getattr(t, "age")  #获取一个不存在的属性。
14 Traceback (most recent call last):
15   File "<stdin>", line 1, in <module>
16 AttributeError: test instance has no attribute 'age'
17 >>> getattr(t, "age","18")  #若属性不存在,返回一个默认值。
18 '18'

setattr(object, name, values)
给对象的属性赋值,若属性不存在,先创建再赋值。

1 >>> class test():
 2 ...     name="xiaohua"
 3 ...     def run(self):
 4 ...             return "HelloWord"
 5 ...
 6 >>> t=test()
 7 >>> hasattr(t, "age")   #判断属性是否存在
 8 False
 9 >>> setattr(t, "age", "18")   #为属相赋值,并没有返回值
10 >>> hasattr(t, "age")    #属性存在了
11 True

异常(高级)

可以用于异常的语句:
    try-except  # 捕获异常,得到异常通知
    try-finally  # 做任何流程(正常流程/异常流程)都必须要执行的语句
    raise  # 发送异常通知
    assert  # 根据条件发送异常通知

with 语句
  语法:
        with 表达式1 [as 变量1], 表达式2 [as 变量2], ...:
            语句块
  作用:
      使用于对资源进行访问的场合,确保使用过程中不管是否发生异常都会执行必要的'清理操作',并释放资源
      (如:文件使用后自动关闭,线程中锁的自动获取和释放等)
  说明:
      执行表达式 as子句中的变量绑定生成的对象
      with语句并不改变异常的状态

示例:

#  此示例示意用with语句打开文件和自动关闭文件的操作
# try:
#     f = open('a.txt')
#     try:
#         for x in f:
#             print(x)
#             int('abc')  # 出错异常
#     finally:
#         f.close()
# except OSError:
#     print("打开文件失败")
# except ValueError:
#     print('操作文件过程中失败')


try:
    with open('a.txt') as f:
        for x in f:
            print(x)
            int("abc")  # 出现异常
except OSError:
    print("打开文件失败")
except ValueError:
    print('操作文件过程中失败')

环境管理器

类内有__enter__ 和 __exit__实例方法的类被称为环境管理器
能够用with进行管理的对象必须是环境管理器

说明:
     __enter__将在进入with语句时被调用并返回由as变量绑定的对象
     __exit__将在离开with语句时被调用,且可以用参数来判断在离开with语句时是否有异常发生并做出相应的处理

with语句的实际工作流程: 
1. 计算expression表达式,所得到的对象就称为环境管理器,它必须有__enter__和__exit__方法。 
2. 环境管理器的__enter__会首先被调用,如果存在as语句,它的返回值会赋给as后面的变量,否则直接丢弃。 
3. with_block中的代码块会执行。 
4. 最后执行__exit__(type, value, traceback)方法。 
- 如果with语句引发了异常,且该方法的返回值是假,那么异常就会被重新引发,否则异常会终止。正常情况下我们希望异常被重新引发,这样才能讲异常  传递到with代码块外面去,便于发现和处理。 
- 如果with语句没有引发异常,其中type, value, traceback参数都会以None值传递。

示例:

# 此示例示意 让一个自定义的类创建的对象能够使用with语句
class A:
    '''此类的对象可用于with语句进行管'''
    def __enter__(self):
        print("已经进入with语句,资源分配成功!")
        return self  # <<<--此处返回的对象将由 as 变量绑定

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("已经离开with语句,资源释放成功!")
        if exc_type is None:
            print("当离开with语句时没有发生异常")
        else:
            print('有异常发生,异常类型是:', exc_type,
                '异常值是:', exc_val)


with A() as a:
    print("这是with中的语句")
    raise ValueError("故意制造的异常")

运算符重载

什么是运算符重载
    让自定义的类生成的对象(实例)能够使用运算符进行操作

作用:
    1. 让自定义的类的实例能够运行运算符操作
    2. 让程序简洁易读
    3. 对自定义对象将运算符赋序新的运算规则
说明:
    运算符重载方法的参数已经有固定的含义,不建议改变原有的意义

算术运算符重载

       方法名               运算符和表达式   说明
 __add__(self, rhs)         self +  rhs    加法
 __sub__(self, rhs)         self -  rhs    减法
 __mul__(self, rhs)         self *  rhs    乘法
 __truediv__(self, rhs)     self /  rhs    除法
 __floordiv__(self, rhs)    self // rhs    地板除
 __mod__(self, rhs)         self %  rhs    取模(求余)
 __pow__(self, rhs)         self ** rhs    幂

  rhs(right hand side) 右手边

反向算术运算符的重载

当运算符的左侧为内建类型,右侧为自义类型的对象进行算术运算符运算时,会出现TypeError错误,
因无法修改内建类的代码来实现运算符重载,此时需要使用反向算术运算符重载

       方法名               运算符和表达式   说明
 __radd__(self, lhs)        lhs +  self    加法
 __rsub__(self, lhs)        lhs -  self    减法
 __rmul__(self, lhs)        lhs *  self    乘法
 __rtruediv__(self, lhs)    lhs /  self    除法
 __rfloordiv__(self, lhs)   lhs // self    地板除
 __rmod__(self, lhs)        lhs %  self    取模(求余)
 __rpow__(self, lhs)        lhs ** self    幂

  lhs(left hand side) 左手边

复合赋值算术运算符的重载

  以复合赋值算术运算符  x += y 为例,此运算会优先调用x.__iadd__(y) 方法,
  如果没有__iadd__方法时会将复合赋值运算拆解为 x = x + y,然后调用x = x.__add__(y) 方法
  如果再不存在 __add__方法则会触发TypeError异常

       方法名               运算符和表达式   说明
 __iadd__(self, lhs)        lhs +=  self    加法
 __isub__(self, lhs)        lhs -=  self    减法
 __imul__(self, lhs)        lhs *=  self    乘法
 __itruediv__(self, lhs)    lhs /=  self    除法
 __ifloordiv__(self, lhs)   lhs //= self    地板除
 __imod__(self, lhs)        lhs %=  self    取模(求余)
 __ipow__(self, lhs)        lhs **= self    幂

比较运算符的重载

       方法名               运算符和表达式   说明
 __lt__(self, rhs)        self <   rhs    小于
 __le__(self, rhs)        self <=  rhs    小于等于
 __gt__(self, rhs)        self >   rhs    大于
 __ge__(self, rhs)        self >=  rhs    大于等于
 __eq__(self, rhs)        self ==  rhs    等于
 __ne__(self, rhs)        self !=  rhs    不等于

位运算符重载

       方法名               运算符和表达式   说明
 __invert__(self)          ~ self      取反(一元运算符)
 __and__(self, rhs)        self &  rhs    位与
 __or__(self, rhs)         self |  rhs    位或
 __xor__(self, rhs)        self ^  rhs    位异或
 __lshift__(self, rhs)     self << rhs    左移
 __rshift__(self, rhs)     self >> rhs    右移

反向位运算符重载

       方法名               运算符和表达式   说明
 __rand__(self, lhs)        lhs &  self    位与
 __ror__(self, lhs)         lhs |  self    位或
 __rxor__(self, lhs)        lhs ^  self    位异或
 __rlshift__(self, lhs)     lhs << self    左移
 __rrshift__(self, lhs)     lhs >> self    右移

复合赋值位运算符重载

       方法名               运算符和表达式   说明
 __iand__(self, rhs)        self &=  rhs    位与
 __ior__(self, rhs)         self |=  rhs    位或
 __ixor__(self, rhs)        self ^=  rhs    位异或
 __ilshift__(self, rhs)     self <<= rhs    左移
 __irshift__(self, rhs)     self >>= rhs    右移

一元运算符重载

       方法名               运算符和表达式   说明
 __invert__(self)          ~ self      取反(一元运算符)
 __pos__(self)             + self      正号
 __neg__(self)             - self      负号

in / not in 运算符重载

重载方法:
  def __contains__(self, e):
      ....

索引和切片运算符的重载

  方法名                  运算符和表达式     说明
 __getitem__(self, i)      x = self[i]   索引/切片取值
 __setitem__(self, i, val) self[i] = val 索引/切片赋值
 __delitem__(self, i)      del self[i]   删除索引/切片

作用:
  让自定义的类的对象能够支持索引和切片操作

slice 函数:

  作用:
    用于创建一个slice切片对象,此对象存储切片的信息
  格式:
    slice(start=None, stop=None, step=None)
  slice对象的属性
    s.start 切片的起始值, 默认为None
    s.stop  切片的终止值, 默认为None
    s.step  切片的步长, 默认为None

特性属性 @property

实现其它语言所拥有的 getter(读) 和 setter(写) 的功能

  作用:

     Python内置的@property装饰器就是负责把一个方法变成属性调用的
    用来模拟一个属性
    通过@property 装饰器可以对模拟属性的取值和赋值加以控制

 

@property可以将python定义的函数“当做”属性访问,从而提供更加友好访问方式,但是有时候setter/deleter也是需要的。
1、只有@property表示只读。
2、同时有@property和@*.setter表示可读可写。

3、同时有@property和@*.setter和@*.deleter表示可读可写可删除。

示例:

class Student:

    def __init__(self, s):
        self.__score = s  # 私有属性,不让其它人任意修改成绩

    @property
    def score(self):
        '''取值实现getter方法'''
        print('正在取值')
        return self.__score

    @score.setter
    def score(self, v):
        '''实现设置者setter,对用户的赋值加以限制'''
        assert 0 <= v <= 100, '成绩不合法'
        self.__score = v

s = Student(59)
print(s.score)  # 希望有一个属能得到成绩
s.score = 80  # 通过s.score 来修改成功
print(s.score)  # 80
try:
    s.score = 102
    print(s.score)
except Exception as err:
    print(err)  # 成绩不合法

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值