人工智能(python)—— 函数的重载(重写)


函数重载 overwrite
        在自定义的类内添加相应的方法,让自定义的类生成的对象(实例)像内建对象一样进行函数操作。


一、对象转字符串函数

        repr(x) 返回一个能代表此对象的表达式字符串,通常:eval(repr(obj)) = obj
        str(obj)  通过给定对象,返回一个字符串(这个字符串通常是给人阅读的)
        换句话说
                repr(obj)    返回的字符串是给python用的
                str(obj)       返回的字符串是给人看的

repr()和str()的重载方法

        repr() 函数的重载方法
                 def __repr__(self):
                          ...
                          return 字符串
        str() 函数的重载方法
                def __str__(self):
                      ...
                      return 字符串

str(obj) 函数调用方法说明

        a、str(obj) 函数先查找obj.__str__() 方法,调用此方法并返回结果
        b、如果obj.__str__() 方法不存在,则调用obj.__repr__()方法并返回结果
        c、如果obj.__repr__方法不存在,则调用object类的__repr__实例方法显示<__main__.MyNumber object at xxx> 格式的字符串

示例

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

    def __str__(self):
        # print('正在调用__str__方法,转换为普通字符串')
        s = "自定义数据:%d" % self.data
        return s

    def __repr__(self):
        '''此方法供repr(obj)函数调用'''
        return 'MyNumber(%d)' % self.data

n1 = MyNumber(100)
print(str(n1))	# 此句等同于print(n1)
print(n1)
print(repr(n1))

二、内建函数重载

        __abs__              abs(obj) 函数调用
        __len__               len(obj) 函数调用
        __reversed__      reversed(obj) 函数调用
        __round__          round(obj)  函数调用

示例

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

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

    def __abs__(self):
        '''此方法用于制定abs(obj) 函数取值时返回的结果'''
        if self.data < 0:
            # 用-self.data 创建一个新的对象返回回去
            t = MyInteger(-self.data)
            return t
        return MyInteger(self.data)
    def __len__(self):
		'''len(obj) 函数规定只能返回整数值,
		因此此方法不能返回字符串等其他类型的值'''
        return 10

i1 = MyInteger(-100)

print(i1)  # 等同于print(str(i1)) 
n = abs(i1)
print(n)   # MyInteger(100)

print(len(i1))  # 等同于print(i1.__len__())

三、数值转换函数重载

        __complex__    complex(obj) 函数调用
        __int__             int(obj) 函数调用
        __float__          float(obj) 函数调用
        __bool__          bool(obj) 函数调用

四、布尔测试函数重载

        用于bool(obj) 函数取值
        用于if语句真值表达式中
        用于while语句的值表达式中

重载方法

        def __bool__(self):
                ...

说明

        a、当自定义类内有__bool__(self) 方法时,以此方法的返回值作为bool(obj) 的返回值
        b、当不存在__bool__ (self) 方法时,bool(x) 返回 __len__(self) 方法的返回值是否为零来测试布尔值
        c、当再不存在__len__(self)方法时,则直接返回True

示例

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):
        '''此方法用来制定一个bool(x) 返回的规则'''
        # 如果没有任何元素返回False
        print("__bool__方法被调用")
        if len(self.data) == 0:
            return False
        for x in self.data:
            if x:
                return True
        return False

myl = MyList([1, -2, 3, -4])
print(myl)
print(bool(myl))              # False
print(len(myl))

myl1 = MyList([0, 0.0, False, None])    
print(bool(myl1))             # False

myl2 = MyList([0, 1, 2])
print(bool(myl2))             # True

五、迭代器(高级)

1、迭代器

        可以通过next函数取值的对象就是迭代器

        迭代器协议

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

        迭代器的实现

                通过__next__(self) 方法用来实现迭代器协议

        重载方法

                class  MyIterator:
                        def  __next__(self):
                                迭代器协议

                                return  数据

2、可迭代对象

        是指能用iter(obj) 函数返回迭代器对象

        可迭代对象内部要定义__iter__(self) 方法来返回迭代器对象

        重写方法

                class MyIterable:
                       def __iter__(self):
                               语句块
                               return 迭代器

3、示例

        指定迭代器      

# 此示例示意用自定义的类MyRange实现可迭代对象
# 用自定义的类MyIterator 实现迭代器

class MyIterator:
    def __init__(self, start, stop, step):
        # self.start变量用来记录迭代器的起始位置和当前位置
        self.start = start
        self.stop = stop
        self.step = step
    def __next__(self):
        '''此方法用于实现迭代器协议'''
        print("MyIterator.__next__方法被调用!")
        if self.start >= self.stop:  # 迭失终止条件
            raise StopIteration
        r = self.start               # 先将要返回的数存于变量r中
        self.start += self.step      # 迭代器后移
        return r                     # 送回给next(it) 调用

class MyRange:
    def __init__(self, start, stop=None, step=1):
        if stop is None:
            stop = start
            start = 0
        self.start = start  # 起始值
        self.stop = stop    # 终止值
        self.step = step    # 步长
    def __repr__(self):
        return "MyRange(%d, %d, %d)" % (self.start,self.stop, self.step)
    def __iter__(self):
        '''此方法用于把MyRange类型创建的对象当做可迭代对象'''
        print("__iter__被调用")
        # 此处必须返回迭代器
        return MyIterator(self.start, self.stop, self.step)

L = [x for x in MyRange(5, 10)]
print(L)
print('----------------------------')
R = MyRange(5, 10, 2)
it = iter(R)     # R.__iter__
print(next(it))  # it.__next__

        指定自身既是迭代器又是可迭代对象       

# 此示例示意用自定义的类MyRange实现可迭代对象和实现迭代器

class MyRange:
    def __init__(self, start, stop=None, step=1):
        if stop is None:
            stop = start
            start = 0
        self.start = start  # 起始值
        self.stop = stop    # 终止值
        self.step = step    # 步长
    def __repr__(self):
        return "MyRange(%d, %d, %d)" % (self.start,self.stop, self.step)
     
    def __iter__(self):
        '''此方法用于把MyRange类型创建的对象当做可迭代对象'''
        print("__iter__被调用")
        return self
     
    def __next__(self):
        '''此方法用于实现迭代器协议'''
        print("MyIterator.__next__方法被调用!")
        if self.start >= self.stop:  # 迭失终止条件
            raise StopIteration
        r = self.start               # 先将要返回的数存于变量r中
        self.start += self.step      # 迭代器后移
        return r                     # 送回给next(it) 调用

L = [x for x in MyRange(5, 10)]
print(L)
print('----------------------------')
R = MyRange(5, 10, 2)
it = iter(R)     # R.__iter__
print(next(it))  # it.__next__

六、环境管理器

        a、类内有__enter__方法 和 __exit__ 实例方法的类被称为环境管理器(也有叫上下文管理器)
        b、能够用with语句进行管理的对象必须是环境管理器
        c、__enter__将在进入with语句时被调用,并返回由 as 变量绑定的对象

        d、__exit__ 将在离开with语句时被调用, 且可以用参数来判断在离开with语句时是否有异常发生并做出相应的处理

# 本程序示意自定义的类作为环境管理器使用
class FileWriter:
    def __init__(self, filename):
        self.filename = filename  # 此属性用于记住文件名

    def writeline(self, s):
        '''此方法用于向文件内写入字符串,同时自动添加换行'''
        self.file.write(s)
        self.file.write('\n')

    def __enter__(self):
        '''此方法用于实现环境管理器'''
        self.file = open(self.filename, 'w')
        print("已进入__enter__方法,文件打开成功")
        return self                               # 返回值向用于 with中的as 绑定

    def __exit__(self, exec_type, exec_value, exec_tb):
        '''
        exec_type  为异常类异,没有异常发生时为None
        exec_value 为错误的对象,没有异常时为None
        exec_tb    为错误的traceback对象
        '''
        self.file.close()
        print("文件", self.filename, "已经关闭")
        if exec_type is None:
            print("退出with时没有发生异常")
        else:
            print("退出with时,有异常,类型是", exec_type,"错误是", exec_value)
        print("__exit__法被调用,已离开with语句")


try:
    with FileWriter('log.txt') as fw:
        while True:
            s = input("请输入一行: ")
            if s == 'exit':
                break
            if s == 'error':
                raise ValueError("故意制造的值错误")
            fw.writeline(s)
except:
    print("有错误发生,已转为正常")

print("这是with语句之外,也是程序的最后一条语句")

七、运算符重载

        让自定义的类生成的对象(实例)能够实例运算符进行操作

        作用

                a、让自定义类的实例像内建对象一样进行运算符操作
                b、让程序简洁易读

                c、对自定义的对象将运算符赋予新的运算规则

        说明

                运算符重载方法的参数已经有固定的含义,不建议改变原有的意义

1、算术运算重载

        方法名                      运算符和表达式      说明
        __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 hands side) 右手边

        二元运算符重载方法格式

                def  __xxx__(self, other):
                        ...
        示例

# 此示例示意自定义的类通过运算符重载实现运算符操作
class MyNumber:
    def __init__(self, v):
        self.data = v

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

    def __add__(self, other):
        '''实现加法操作,生成一个新的对象并返回给调用者'''
        print("__add__方法被调用")
        return MyNumber(self.data + other.data)
    def __sub__(self, rhs):
        return MyNumber(self.data - rhs.data)

n1 = MyNumber(100)
n2 = MyNumber(200)
n3 = n1 + n2  #  等同于n1.__add__(n2)
# n3 = n1.__add__(n2)

print(n1, "+", n2, '=', n3)  # MyNumber(300) ???
n4 = n1 - n2
print('n4 =', n4)
        1)反向算术运算符的重载

                当运算符的左侧为内建类型时,右侧为自定义类型进行算术运算时,会出现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         冪运算

        示例

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

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

    def __sub__(self, rhs):
        '''实现减法操作,生成一个新的对象并返回给调用者'''
        print("__sub__方法被调用")
        return MyNumber(self.data - rhs)

    def __rsub__(self, lhs):
        '''实现被减操作,生成一个新的对象并返回给调用者'''
        return MyNumber(lhs - self.data)

n1 = MyNumber(100)
n2 = MyNumber(200)
n3 = n1 - 200       #  等同于n1.__sub__(200)
# n3 = n1.__sub__(200)

print(n1, "-200", '=', n3)  
n4 = 600 - n2       #  等同于n2.__rsub__(600)
#n4 = n2.__rsub__(600)
print('n4 =', n4)
        2)复合赋值算术运算符重载
                以复合赋值算术运算符 x += y 为例,此运算符会优先调用 x.__iadd__(y) 方法,如果没有__iadd__方法时会将复合赋值运算符拆为 x = x + y,然后调用 x = x.__add__(y) 方法,如果再不存在__add__方法则会触发TypeError异常

                其它复合赋值算术运算符也具有相同的规则

       复合赋值算术运算重载

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

        说明

                a、如果__add__和__iadd__的方法不同(运算结果不同)的时候,x += x 和 x = x + x是不等价的,两者得到的结果是不同的,其他复合运算同理
                b、如果__add__和__iadd__同时存在,复合运行优先采用__iadd__方法
                c、如果__iadd__不存在,复合运行采用__add__方法
                d、如果__add__和__iadd__均存在,运行报错

        示例

# 此示例示意复合赋值算术运算符的重载
class YouList:
    def __init__(self, iterable):
        self.data = [x for x in iterable]

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

    def __add__(self, rhs):
        print("__add__方法被调用")
        return YouList(self.data + rhs.data)

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

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

    def __add__(self, rhs):
        print("__add__方法被调用")
        return MyList(self.data + rhs.data)

    def __iadd__(self, rhs):
        print("__iadd__方法被调用")
        self.data.extend(rhs.data)
        return self


L1 = MyList([100])
L1 += L1            # __iadd__方法被调用
print('L1 =', L1)

L2 = YouList([100])
L2 += L2            # __add__方法被调用
print('L2 =', L2)

2、比较运算符的重载

        方法名                      运算符和表达式         说明
        __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              不等于
                 注: 比较运算符通常返回布尔值True 或False

3、位运算符的重载

          方法名                      运算符和表达式            说明
        __invert__(self, rhs)        ~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         右移

4、一元运算符的重载

        方法名     运算符和表达式    说明
        __neg__(self)          - self                        负号
        __pos__(self)          + self                       正号

        __invert__(self)       ~ self                       取反

       重载方法

                def __xxx__(self):

                        ...

        示例

# 此示例示意一元运算符的重载
class MyList:
    def __init__(self, iterable=()):
        self.data = [x for x in iterable]

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

    def __neg__(self):
        '''规则是正变负,负变正'''
        L = (-x for x in self.data)
        return MyList(L)

L1 = MyList([1, -2, 3, -4, 5])
L2 = -L1  # 等同于L1.__neg__()
print(L2)

        in / not in 运算符

                方法名        运算符和表达式   说明

                __contains__(self, e)        e in self                成员运算

        示例

# 此示例示意一元运算符的重载
class MyList:
    def __init__(self, iterable=()):
        self.data = [x for x in iterable]

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

    def __contains__(self, e):
        return e in self.data

L1 = MyList([1, -2, 3, -4, 5])
if 3 in L1:
    print("3 在 L1内")

if 4 not in L1:
    print('4 不在L1内')

5、索引和切片运算符的重载

         1) [ ]索引切片
          重载方法                   运算符和表达式  说明
        __getitem__(self, i)         x = self[i]          索引/切片取值
        __setitem__(self,i,val)     self.[i]=val         索引/切片赋值

        __delitem__(self, i)         del self[i]          del语句索引/切片

        作用

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

        示例

# 此示例示意[]运算符的重载
class MyList:
    def __init__(self, iterable=()):
        self.data = [x for x in iterable]

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

    def __getitem__(self, i):
        # print("i =", i)
        return self.data[i]
    def __setitem__(self, i, val):
        self.data[i] = val
    def __delitem__(self, i):
        del self.data[i]

        
L1 = MyList([1, -2, 3, -4, 5])
x = L1[0]           # L1.__getitem__(0)
print(x)

L1[1] = 2           # L1.__setitem__(1, 2)
print(L1)
print(L1[0:5:1])    # 切片读取列表

L1[::] = []         # 删除 列表中值
print(L1)
        2)slice 构造函数

                用于创建一个slice切片对象,此对象存储一个切片起始值,终止值,步长值信

        格式

                slice(start=None, stop=None, step=None) 创建 一个slice 切片对象
                        slice 对象属性
                        s.start 切片的起始值
                        s.stop 切片的终止值

                        s.step 要片的步长

        示例

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

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

    def __getitem__(self, i):
        print("i =", i)
        if type(i) is slice:
            print("您正在执行切片取值操作")
            print("起始值是:", i.start)
            print("终止值是:", i.stop)
            print("步长是:", i.step)
        return self.data[i]

L1 = MyList([1, -2, 3, -4, 5])
x = L1[1:8:2]
print(x)  # 

八、特性属性 @property

        实现其它语言所拥有的 getter 和 setter功能(实现魔法函数)

        作用

                a、用来模拟一个属性

                b、通过@property装饰器可以对模拟的属性赋值和取值加以控制

        示例

# 此示例示意特性属性的用法
class Student:
    def __init__(self, score):
        self.__score = score

    def get_score(self):
        '''实现getter'''
        return self.__score

    def set_score(self, s):
        '''实现setter'''
        print("正在调用setter")
        if 0 <= s <= 100:
            self.__score = s
        else:
            raise ValueError

    score = property(get_score, set_score)

s = Student(59)
print(s.score)  # print(s.get_score())
s.score = 97  # s.set_score(97)
print(s.score)  # ...
# 此示例示意特性属性的用法
class Student:
    def __init__(self, score):
        self.__score = score

    @property
    def score(self):  # score = propery(score)
        '''实现getter'''
        return self.__score

    @score.setter
    def score(self, s):
        '''实现setter'''
        print("正在调用setter")
        if 0 <= s <= 100:
            self.__score = s
        else:
            raise ValueError

s = Student(59)
print(s.score)  # print(s.get_score())
s.score = 97  # s.set_score(97)
print(s.score)  # ...

九、附录

        人工智能(python)—— 目录汇总



你可能感兴趣的:(人工智能,Python3)