面向对象编程理解-4

时间:2021-08-29 17:25:37

26 复合赋值算术运算符:

__iadd__(self,rhs)                       +=

__isub__(self,rhs)                       -=

__imul__(self,rhs)                       *=  

当__imul__重载后调用重载后的,如果没有,则调用__mul__

__itruediv__(self,rhs)                        /=

__ifloordiv__(self,rhs)                 //=

__imod__(self,rhs)                      %=

__ipow__(self,rhs)               **=

 

示例1

class MyList:

 

    def __init__(self, vaule):

        '''传入参数可变时,必须用拷贝,这样拿到的数据才为此对象所有,否则只是两个变量绑定到一份数据,

        改变原有数据时将改变对象属性的值,这是不允许的'''

        self.vaule = vaule.copy()

 

    def __str__(self):

        return 'MyList(' + str(self.vaule) + ')'

 

    def __mul__(self,other):

        return MyList(self.vaule * other)

 

l1 = MyList([1,2,3])

l1 *=2

print(l1)

执行结果

MyList([1, 2, 3, 1, 2, 3])

示例1

class MyList:

 

    def __init__(self, vaule):

        '''传入参数可变时,必须用拷贝,这样拿到的数据才为此对象所有,否则只是两个变量绑定到一份数据,

        改变原有数据时将改变对象属性的值,这是不允许的'''

        self.vaule = vaule.copy()

 

    def __str__(self):

        return 'MyList(' + str(self.vaule) + ')'

 

    def __mul__(self,other):

        return MyList(self.vaule * other)

 

l1 = MyList([1,2,3])

l1 *=2

print(l1)

执行结果

MyList([1, 2, 3, 1, 2, 3])

 

 

示例2

class MyList:

 

    def __init__(self, vaule):

        '''传入参数可变时,必须用拷贝,这样拿到的数据才为此对象所有,否则只是两个变量绑定到一份数据,

        改变原有数据时将改变对象属性的值,这是不允许的'''

        self.vaule = vaule.copy()

 

    def __str__(self):

        return 'MyList(' + str(self.vaule) + ')'

 

    def __mul__(self,other):

        return MyList(self.vaule * other)

 

    def __imul__(self,rhs):

        self.vaule = self.vaule*rhs

对于l1 *=2,这个优先级高于__mul__

 
        return self

 

l1 = MyList([1,2,3])

l1 *=2

print(l1)

MyList([1, 2, 3, 1, 2, 3])

27 一元运算符

__neg__                   +正

__pos__                   -负

__invert__     ~取反

27.1 重载方法

def __xxx__(self,lhs):

   语句

class MyList:

 

    def __init__(self, v):

        self.value = v.copy()

 

    def __str__(self):

        return 'MyList('+str(self.value)+')'

 

    def __neg__(self):

 

        for i in range(len(self.value)):

            self.value[i] = -self.value[i]

        return MyList(self.value)

 

L1 = MyList([1,2,3])

L2 = -L1   #实现MyList([-1,-2,-3])

print(L2)

 

 

class MyList:

 

    def __init__(self, v):

        self.value = v.copy()

 

    def __str__(self):

        return 'MyList(' + str(self.value) + ')'

 

    def __neg__(self):

 

        for i in range(len(self.value)):

            self.value[i] = -self.value[i]

        return MyList(self.value)

 

def __invert__(self):

        self.value.reverse()

        return  MyList(self.value)

 
    def __invert__(self):

相同

 
 

        mi = MyList(self.value)

 

        mi.value.reverse()

        return MyList(mi.value)

 

 

L1 = MyList([1, 2, 3])

L3 = ~L1  # 实现MyList([3,2,1])

print(L3)

28 比较运算符的重载:

   __lt__             <

   __le__            <=

__gt__        >

__ge__       >=

__eq__              ==

__ne__              !=

28.1 比较运算符通常返回True或False

29 位运算符重载:

   __invert__   ~取反

   __and__         &位与

   __or__           |位或

__xor__             ^位异或

__lshift__     <<左移位

__rshift__    >>右移位

30 内建函数的重载:

 __abs__        绝对值

__len__             长度

__reversed__          反转

__round__        对数进行四舍五入

·····

31 集合运算符

32 数值转换函数重载

str(obj)  __str__

complex(obj)  __complex__

int(obj)           __int__

float(obj) __float__

bool(obj)   __bool__

32.1 浮点类型示例

class MyFloat:

 

    def __init__(self, n):

        self.data = n

 

    def __float__(self):      

返回必须是float类型或其对象

str只能返回str类型其对象

 
        return float(self.data)

 

 

 

n = MyFloat('100')

print(float(n))

执行结果

100

 

32.2 bool测试运算符重载
32.2.1方法格式:

def __bool__(self):

   ·····

32.2.2作用:

用if语句的真值测试表达式中

用于while语句的真值表达式中

用于bool(obj)函数取值

32.2.3说明:

当没有__bool__(slef)方法时,真值测试将以__len__(self)的方法的返回值来进行测试bool值

如果__bool__(self)和__len__(self)同时重载,则以__bool__(slef)为准

32.2.3 示例

class MyList:

 

    def __init__(self, count=0, value=0):

        self.data = []

        for x in range(count):

            self.data.append(value)

 

    def __repr__(self):

        return 'MyList(' + repr(self.data) + ')'

 

    def __bool__(self):

        for x in self.data:

            if x:

                return True

        return False

    def __len__(self):

        return len(self.data)

 

 

a = MyList(10,1)

print(bool(a))

 

33 in/not in重载(是否在一个容器中)

33.1 重载方法

def __contains__(slef,e):

   ········

33.2 示例

class even:

    '''偶数类,用于显示偶数是否在有序列表中'''

 

    def __init__(self, begin, end):

        self.begin = begin

        self.end = end  # 不包含end

    def __contains__(self,e):

        if e<self.begin or e> self.end:

            return False

        if e%2 == 0:

            return True

        return False

 

e1 = even(1, 10)

#e1中的值为[2,4,6,8]

# Traceback (most recent call last):

#   File "in_even.py", line 11, in <module>

#     if 4 in e1:

# TypeError: argument of type 'even' is not iterable

 

 

if 3 in e1:

    print("4在even(1,10)中")

else:

    print("3不在even(1,10)中") 

 

练习:

class Primes:

 

    def __init__(self, end):

        self.begin = 2

        self.end = end

 

    def __contains__(self, e):

        if e < self.begin or self.end < e:

            return False

        if e == 2:

            return False

        for x in range(2, e):

            if e % x == 0:

                return False

        return True

 

p1 = Primes(100)

if 3 not in p1:

    print("不是素数")

else:

print("是素数")

#类内直接调用此模块内  并且在类外面的函数

34 索引和切片运算符的重载:

34.1 重载方法

__getiterm__(self,i)                     #用索引/切片获取值

__setiterm__(self,i,value)           #设置索引或切片的值

__deliterm__(self,i)                     #进行删除索引操作

34.2 作用:

让自定义对象能进行索引和切片操作

原有索引功能:

   L =[1,2,3,4]

   L[2]= 3.14  索引赋值

   print(L[2])  索引取值

   del  L[2]  删除索引

34.3 示例

索引示例

class MyList:

 

    def __init__(self, count=0, value=0):

        self.data = []

        for x in range(count):

            self.data.append(value)

 

    def __repr__(self):

        return 'MyList(' + repr(self.data) + ')'

 

    def __getitem__(self, index):

       # ml = MyList()

       # ml.data = self.data[index]

       # return ml    

return  self.data[index]  # 返回索引所对应的值

 

    def __setitem__(self, index, value):

        self.data[index] = value  # return self

 

    def __delitem__(self, index):

        del self.data[index]  # return self

        # 此时del函数做了两件事,删除索引,并重新制索引

 

 

myl = MyList(5, 1)

myl[1] = 2

print(myl)

print(myl[1])       

 

切片示例

class MyList:

 

    def __init__(self, count=0, value=0):

        self.data = []

        for x in range(1, 6):

            self.data.append(x)

 

    def __repr__(self):

        return 'MyList(' + repr(self.data) + ')'

 

    def __getitem__(self, index):

        return self.data[index]  # 返回索引所对应的值

 

    def __setitem__(self, index, value):

        self.data[index] = value  # return self

 

    def __delitem__(self, index):

        del self.data[index]  # return self

        # 此时del函数做了两件事,删除索引,并重新制索引

 

 

myl = MyList(5, 1) 

print(myl[1:5:2])  # index = slice(1,5,2)

# myl[index] index可以是切片

print(myl[slice(1, 5, 2)])

 

35 函数调用模拟重载

   __call__方法

35.1 作用:

   让一个对象能像函数一样调用

35.2 方法格式

 def__call__(self,参数列表):

   ·········

注:此重载方法的参数可以是1个或多个

class MySum:

    # def __call__(self):

        # '''函数调用'''

        # print("__call__")

        # return 100

 

    # def __call__(self,a,b):

    #     '''函数调用'''

    #     print("__call__")

    #     return a+b

    def __init__(self):

        self.data = 0

    def __call__(self, *args, **kwargs):

        print('args:', args, 'kwargs:', kwargs)

        s = sum(args)

        self.data += s

        return s

 

 

mys = MySum()

r = mys(100, 200)  # 对象可以像方法一样调用

print(r)

print(mys.data)

 

36 属性管理重载

属性管理函数

   getattr(obj,name)

   setattr(obj,name,value)

hastattr(obj,name[,defalut])

   delattr(obj,name)

36.1 作用

实现对特殊属性的管理

模拟一些特殊属性

36.2 重载格式:

   def__setattr__(self,n,v):  #设置属性

          ··········

def __getattribute__(self,n,):  #获取属性

          ··········

   def__getattr__(self,n): 

          ·······

          在__getattribute__产生AttributeError异常时重载新尝试获取属性

 def__delattr__(self,n):             #删除属性

   ·········

注:以上四个方法当属性不存在时,需要产生AttributeError异常错误

36.3 示例

# 1.写一个正方形类:

#     有三个属性:

#     边长是:length

#     周长: zhouchang

#     面积:area

# 要求:用此类生成对象,此三个属性中一个变化,其他属性同步变化

class Square:

 

    length = 0  # 类属性,对象也能调用

 

    def __init__(self, l):

        self.__class__.length = l

 

    def __setattr__(self, name, value):

        if name == 'perimeter':

            self.__class__.length = (value / 4)

        else:

            self.__class__.length = value

 

    def __getattr__(self, name):

        if name == 'perimeter':

            return self.__class__.length * 4

 

    def __delattr__(self,name):

        if  name == 'perimeter':

            print("不允许删除此属性")

        raise AttributeError

 

 

sq = Square(10)

print(sq.length)

sq.perimeter = 400   #perimeter属性是不存在的.属性赋值

print(sq.length)

print(sq.perimeter)

 

del sq.perimeter

36.4 说明:

__getattr__是在找不到对应属性时才调用,当没有属性时需要产生AttributeError错误

__getattribute__在任何时候都会被调用,当没有属性时需要产生AttributeError错误,然后进入__getattr__继续寻找

37 迭代器(高级)

37.1 迭代器协议

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

next(it) 对应__next__(self)方法

iter(obj) 对应__iter__(self)方法,通常返回一个可迭代对象

补充:for 语句和推导式,先调用iter(obj)拿出迭代器

     range() 生成器函数

   xfor x in range()    生成器表达式

37.2 示例

class Odd:  # odd 奇数

 

    def __init__(self, begin, end):

        self.begin = begin

        self.end = end

        self.cur = begin

 

    def __next__(self):

        print("__next__被调用")

        if self.cur >= self.end:

            raise StopIteration

        r = self.cur

        self.cur += 2

        return r

 

    def __iter__(self):  # self本身是生成器 self本身也是迭代器,for循环必须#根据此方法拿到迭代器

        self.cur = self.begin  # 每次循环先调用一遍此函数,在调用__next__函数

        return self

 

odd = Odd(1, 10)

 

print(next(odd))  # 1

print(next(odd))  # 3

print(next(odd))  # 5

37 异常(高级)

with 语句

37.1 语法:

with 表达式[as 变量]:

语句块

with 表达式1 [as 变量名1][,表达式2 [as 变量名2]······]

   语句块

37.2 说明:

as 子句中的变量绑定生成的对象

37.3 作用:

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

37.4 示例

textWith.txt:

aaaaaa

bbbbbb

cccccc

dddddd

 

with open("textWith.txt", 'r') as f:

    while True:

        l = f.readline().lstrip()

        print(l, end = '')

        if len(l) == 0:

            break

print()

 

执行结果

aaaaaa

bbbbbb

cccccc

dddddd

#交给文件管理器进行管理,不管有无异常文件均能关闭文件,

#目前只有文件能如此