019 Python中的面向对象 (下)

前言

    这篇笔记不太全,所以各一级标题没有编号,可以通过字体大小来区分~


函数重写 overwrite

定义

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

问题

class MyDict:

   Pass

D = MyDict()

len(D)可以求长度吗?

1.对象转字符串函数

repr(x)

返回一个能代表此对象的表达式字符串

通常:eval(repr(obj)) = obj

str(obj)

通过给定对象,返回一个字符串(给人阅读的字符串)

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

repr()函数的重写

def __repr__(self):

    ...

    return 字符串

str()函数的重写

def __str__(self):

    ...

    return 字符串

示例 mynumber.py

# mynumber.py

#示意 repr(obj) 和 str(obj)的重写方法

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

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


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

n1 = MyNumer(100)
print(str(n1))              
#__str__重写之前: <__main__.MyNumer object at 0x7fdf5701acf8>

#__str__重写之后:正在调用__Str__方法,转换为普通字符串
#                自定义数据100
# 此时 s = str(n1),

#先去找__str__, 再去找__repr__, 内建
print(repr(n1))

Str(obj)函数调用说明

1.str(obj)函数先查找obj.__str__()方法,调用此方法并返回结果

2.如果__obj.str__方法不存在,则调用obj.__repr__()方法并返回结果

3.如果obj.__repr__方法不存在,则调用object类的__repr__,实例方法显示<__main__.MyNumer object xxx>格式的字符串

3.内建函数重写

__abs__

Abs(obj)函数调用

__len__

Len(obj) 函数调用

__reversed__

Reversed(obj) 函数调用

__round__

round(obj) 函数调用

示例 myinteger.py

# myinteger.py
# 示意 abs \ len方法的重写方法

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 :
            t = MyInteger(-self.data)    
            #临时用-self.data创建一个新的对象返回回去
            #不用 return -self.data,是为了不改变数据类型
            return t 

        
        return MyInteger(self.data)



i1 = MyInteger(-100)
print(i1)   # = print(str(i1))   MyInteger(200)
#为什么i1可以取出值???
n = abs(i1) #abs返回啥,就print啥
print(n)        #MyInteger(100)




i2 = MyInteger(200)
print(abs(i2))  #MyInteger(200)

示例 myinteger_len.py

 # myinteger_len.py


# 示意 abs \ len方法的重写方法

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 :
            t = MyInteger(-self.data)    
            #临时用-self.data创建一个新的对象返回回去
            #不用 return -self.data,是为了不改变数据类型
            return t 

        
        return MyInteger(self.data)

    def __len__(self):#只能返回整形数,不能return 'hello'
        return 10
        





i1 = MyInteger(-100)

print(len(i1))  #len帮你调
print(i1.__len__()) #自己手动调

4.数值转换函数重写

__complex__

Complex(obj)函数调用

__int__

int(obj)函数调用

__float__

float(obj)函数调用

__bool__

bool(obj)函数调用

示例 mynumber2.py

# mynumber2.py
#示意 自定义对象转为python内建的数据类型

class MyNumber:
    def __init__(self, v):
        self.data = v
    def __repr__(self):
        return 'MyNumber(%d)' % self.data
    def __int__(self):
        return int(self.data)

n1 = MyNumber(100.5)
n = int(n1)     #没有__int__时,自定义转为整数,出错
print(n)

5.布尔测试函数重写

语法

Def __bool__(self):

    …

作用

1.用于bool(obj)函数取值

2.用于if语句真值表达式中

3.用于while语句的表达式中

说明

1.当自定义类内有__bool__(self)方法时,以此方法的返回值作为bool(obj)的返回值

2.当不存在__bool__(self)方法时,bool(x)返回__len__(self)方法的返回值是否为零来测试布尔值

3.当不存在__len__(self)方法时,则直接返回True

示例 bool.py

# bool.py
# 示意 __bool__方法的重写方法及用法

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)返回的规则'''
        print('__bool__方法被调用')
        # 如果没有任何元素,返回False
        if len(self.data) ==0:
            return False
        #实现的是any()的功能
        for x in self.data:
            if x:
                return True
        return False



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

myl = MyList()
print(myl)      #MyList([])
print(bool(myl))    #  在添加__bool__之前,False,bool会调用里面的__len__
print(len(myl))     # 0

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

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

迭代器

迭代器

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

迭代器协议

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

迭代器的实现方法

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

什么是可迭代对象

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

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

可迭代对象的语法形式

class MyIterable:

    def __iter__(self):

        语句块

        return 迭代器

示例 myrange.py

# myrange.py
# 示意 用自定义的类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 None     #出错
        #此处必须返回迭代器
        return MyIterator(self.start, self.stop, self.step)

L = [x for x in MyRange(5,10)]
print(L)

R = MyRange(5, 10, 2)
it  = iter(R)       # R.__iter__ 
print(next(it))     # it.__next__

面向对象编程语言的特征

(待完善)

封装

让有些东西变得不可见,只留一些方法给别人调用。

__双下划线开头,隐藏属性

继承/派生

不改变原有类的情况下,进行扩展、修改

覆盖

让原有的方法,在此类中不被调用;

Super()

用来访问被覆盖的方法

根据MRO顺序来查找方法

多态

如果一个对象有相同的方法,即使没有继承关系,也可以调用类中的函数。。。。

有继承/派生的类中

鸭子模型

多继承

支持多继承的:c++ 、python3

不支持多继承:Java、objective-C、Swift、C#

MRO属性

Method resolution order,用c3算法实现的(广度优先)

函数重写

让内建函数对我们自己写的函数进行操作

Repr、str、abs、… 、next(所有迭代器都有的方法)、iter(所有可迭代对象都有的方法)

可迭代对象 __iter__(self)

一定要返回迭代器

迭代器__next__(self)

用来实现迭代器协议

异常

相关语句

try-except:捕获异常

try-finally:一定要做的事,打开文件、关闭文件

Raise:触发异常,发送错误通知

Assert:根据条件触发AssertionError类型的错误通知

With语句

With语句

语法

With 表达式1 [ as 变量1], 表达式2   [ as 变量2],…:

    语句块

作用

使用与对资源进行访问的场合,确保使用过程中不管是否发生异常,都会执行必须的‘清理’操作,并释放资源

如:文件 使用后自动关闭,线程中锁的自动获取和释放等

说明

1.执行表达式用as子句中的变量绑定生成的对象

2.with语句并不会改变异常的状态

示例 with.py

# with.py
# 示意with语句的用法

src_file = input('请输入源文件:')
try:
    src = open(src_file, 'rb')
    try :
        try:
            #准备打开另一个文件
            dst_file = input('请输入目标文件:')
            dst = open(dst_file,'wb')
            try:
                #开始读写文件
                b = src.read()
                dst.write(b)
            finally:
                #关闭文件
                dst.close()
        except OSError:
            print('打开写文件失败')
    finally:
        src.close()
except OSError:
    print('打开文件失败')

示例 with2.py

# with2.py
# 示意with语句的用法

src_file = input('请输入源文件:')
dst_file = input('请输入目标文件:')
try:
    with open(src_file, 'rb') as src
            #准备打开另一个文件
            with open(dst_file,'wb') as dst:
                #开始读写文件
                b = src.read()
                dst.write(b)
                #with会自动关闭文件
            
except OSError:
    print('复制失败')

示例 with3.py

# with3.py
# 示意with语句的用法

src_file = input('请输入源文件:')
dst_file = input('请输入目标文件:')
try:
    with open(src_file, 'rb') as src, \
         open(dst_file, 'wb') as dst:
        b = src.read()
        dst.write(b)
            
except OSError:
    print('复制失败')

环境管理器 / 上下文管理器

定义

1.类内有__enter__方法和__exit__实例方法的类称为环境管理器

2.能够用with语句进行管理的对象必须是环境管理器

3.__enter__将在进入with语句时被调用,并返回由as变量绑定的对象

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

示例 with4.py

# with4.py

# 示意 环境管理器类的定义的使用
class A:
    '''此类的对象可以用于with语句进行管理'''
    def __enter__(self):
        print('已经进入了with语句')
        print('打开天然气')
        return self

    def __exit__(self, exc_type, exc_value, exc_tb):
        #当with进入异常时,还是会执行__exit__.
        #无论正常或异常,都会执行
        #放 必须要做的事
        if exc_type is None:
            print('在with语句中没有异常,正常离开')
        else:
            print('离开with语句时出现异常')
            print('异常类型是:', exc_type)
            print('错误值是:',exc_value)

        print('关闭天然气')
        print('已经离开了with语句')

try:
    with A() as a:
        print('这是with语句里的打印语句')
        3 / 0   #触发异常
except:
    print('有异常发生,程序已转为正常!')

print('程序退出')

运算符重载

定义

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

作用

1.让自定义类的实例像内建对象一样进行运算符操作

2.让程序简洁易读

3.对自定义的对象将运算符赋值新的运算规则

说明

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

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) 右手边

2. 二元运算符的重载格式

格式

def __xxx__(self, other):

    运算规则的语句...

练习:实现两个自定义的列表相加。

Mylist.py

#mylist.py
#exer_mylist.py的评讲

class MyList:
    class MyIterator:
    #把迭代器放进类里
        def __init__(self, lst):
            self.data = lst     #绑定要迭代的列表
            self.index = 0      #迭代的起始位置

        def __next__(self):
            if self.index >= len(self.data):
                raise StopIteration #发送迭代结束通知
            r = self.data[self.index]
            self.index += 1
            return r    #返回此次迭代的数据



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

    def append(self, v):
        self.data.append(v)

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

    def __iter__(self):
        '''迭代器'''
        return MyList.MyIterator(self.data)
        #因为把迭代器放进类里了,所以是MyList.开头

    def __len__(self):
        return len(self.data)   #self.data.__len__()

    def __add__(self, rhs):
        return MyList(self.data + rhs.data)

    def __mul__(self, rhs):
        return MyList(self.data * rhs)

L1 = MyList([1, 2, 3])
L2 = MyList([4, 5, 6])
L3 = L1 + L2
print(L3)
L4 = L2 + L1
print(L4)

L5 = L1 * 2
print(L5)

3.反向算术运算符的重载

定义

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

方法名

运算符和表达式

__radd__(self,rhs)

lhs + self

__rsub__(self,rhs)

lhs - self

__rmul__(self,rhs)

lhs * self

__rtruediv__(self,rhs)

lhs / self

__rfloordiv__(self,rhs)

lhs // self

__rmod__(self,rhs)

lhs % self

__rpow__(self,rhs)

lhs ** self

rhs(right hands side) 右手边

示例 mylist2.py

#mylist2.py
#示意 反向算术运算 重载
class MyList:
    def __init__(self, iterable=()):
        self.data = [x for x in iterable]

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

    def __mul__(self, rhs):
        return MyList(self.data * rhs)

    def __rmul__(self, lhs):
        return MyList(self.data * lhs)

L1 = MyList([1, 2, 3])
L6 = 2 * L1     #没有反向运算符重载时,等同于 2.__mul__(L1)
# L1.__imul__(2)
print(L6)

4. 复合赋值算术运算符重载

说明

以复合赋值算术运算 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

rhs(right hands side) 右手边

5. 比较运算符的重载

方法名

运算符和表达式

__lt__(self, rhs)

Self < rhs         little than

__le__(self, rhs)

Self <= rhs         little equal

__gt__(self, rhs)

Self > rhs

__ge__(self, rhs)

Self >= rhs

__eq__(self, rhs)

Self == rhs

__ne__(self, rhs)

Self != rhs

ps

比较运算符通常返回布尔值

6. 位运算符的重载

方法名

运算符和表达式

说明

__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

右移

7. 反向位运算符的重载

方法名

运算符和表达式

说明

__rand__(self, rhs)

lhs & self

位与

__ror__(self, rhs)

lhs | self

位或

__rxor__(self, rhs)

lhs ^ self

位异或

__rlshift__(self, rhs)

lhs << self

左移

__rrshift__(self, rhs)

lhs >> self

右移

8. 复合赋值位运算符的重载

方法名

运算符和表达式

说明

__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

右移

9. 一元运算符的重载

方法名

运算符和表达式

说明

__neg__(self)

-      self

负号

__pos__(self)

+ self

正号

__invert__(self)

~ self

取反

语法格式

def __xxx__(self):

    …

示例 mylist5.py

 

# mylist5.py
# 示意 一元运算符的重载

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)

10. in/not in 运算符

方法名

运算符和表达式

说明

__contains__(self, e)

e in self

成员运算

示例 mylist6.py

 

 

 

# mylist6.py
#  in / not in 运算符重载
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 in L1')
else:
    print('3 is not in L1')

11. 索引和切片运算符的重载

索引

重载方法

运算符和表达式

说明

__getitem__(self, i)

x = self [i]

索引/切片取值

__setitem__(self, i, val)

self [i] = val

索引/切片赋值

__delitem__(self, i)

del self [i]

del语句索引/切片

作用

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

示例 mylist7.py 索引

# mylist7.py
# 索引/切片重载

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):
        return self.data[i]

    def __setitem__(self, i, val):
        self.data[i] = val 


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


L1[1] = 2   #L1.__setitem__(1, 2)
print(L1)

slice函数

作用

1.用于创建一个slice切片对象

2.此对象存储一个切片起始值,终止值,步长值信息

格式

slice(start=None, stop=None,step=None)创建一个slice切片对象

slice对象属性

s.start 

切片的起始值

s.stop

切片的终止值

s.step

切片的步长

示例 mylist8.py 切片

# mylist8.py
#切片 重载
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('起始值:', i.start)
            #slice对象会被传给i,该对象存储start/stop/step
        return self.data[i]


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

 

特性属性

特性属性@property

实现其他语言所拥有的getter和setter功能

作用

1.用来模拟一个属性

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

示例  property.py

# property.py
# 示意 特性属性 

class Student:
    def __init__(self, score):
        self.__score = score

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

    def set_score(self, s):
        '''实现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)
#最好不要操作属性,用方法对其进行操作
#用property,其实,s.score调用的是s.set_score()
print(s.score) 

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值