zoukankan      html  css  js  c++  java
  • 第二十九章 运算符重载

    #1.
    #A:运算符重载只是意味着在类方法中拦截内置的操作,当类的实例出现在内置操作中,python会自动调用重载的方法
    #B:__init__构造函数是最常见的运算符重载
    
    #2.
    #A:常见的运算符重载方法:
    '''
    __init__                构造函数
    __del__                 析构函数     
    __add__                 +
    __or__                  |
    __repr__, __str__       打印,转换
    __call__                函数调用
    __getattr__             点号运算
    __setattr__             属性赋值语句    X.any = value
    __delattr__             属性删除        del X.any
    __getattribute__        属性获取        X.any
    __getitem__             索引运算
    __setitem__             索引赋值
    __delitem__             索引和分片删除   del X[key] X[i:j] = sequence
    __len__                 长度
    __It__, __gt__, __le__, __ge__, __eq__, __ne__      X < Y, X > Y, X <= Y, X >= Y, X == Y, X != Y
    __radd__                右侧加法        other + X
    __iadd__                增强加法        X += Y
    __iter__, __next__      迭代环境
    __contains__            成员关系测试
    __index__               整数值
    __get__, __set__        描述符属性
    __delete__, __new__     创建和删除
    __sub__                 减法
    __enter__, __exit__     环境管理器
    '''
    
    #3.
    #A:一些内置的操作,如打印,有默认的重载方法,继承于python3.0中隐含的object类中
    
    #4.
    #A:索引和分片:__getitem__, __setitem__
    #B:除了索引,对于分片表达式也调用__getitem__
    #C:__getitem__也可以是python中一种重载迭代的方式
    class CTest():
        L0 = [1, 2, 3]
        def __getitem__(self, index):
            print(index)
            return CTest.L0[index]
        def __setitem__(self, index, value):
            print(index)
            CTest.L0[index] = value
    
    Test = CTest()
    value = Test[0]         #value = 1  输出0
    Test[0] = 'a'           #输出0
    value = CTest.L0        #value = ['a', 2, 3]
    
    value = Test[0:2]       #value = ['a', 2]   输出slice(0, 2, None)
    Test[0:2] = 'abc'
    value = Test.L0         #value = ['a', 'b', 'c', 3]  输出slice(0, 2, None)
    
    L0 = []
    for value in CTest():
        L0.append(value)    #L0 = ['a', 'b', 'c', 3] 输出0
    1
    2
    3
    4
    
    
    #5.
    #A:尽管__getitem__能在迭代环境中使用,但是这只是退而求其次的方法
    #B:python中的迭代环境都会先尝试__iter__方法,再尝试__getitem__
    #C:迭代环境是通过调用内置函数iter去尝试寻找__iter__方法来实现的,而这种方法应该返回一个迭代器对象
    #  如果提供了,python就会重复调用这个迭代器对象的next方法,直到发送StopIterator异常
    # 如果没找到这类的__init__方法,python就会改用__getitem__机制,直到发生IndexError异常
    class CTest():
        count0 = 0
        count1 = 0
        def __init__(self, start, stop):
            self.start = start
            self.stop = stop
        def __iter__(self):
            CTest.count0 += 1
            return self
        def __next__(self):
            CTest.count1 += 1
            if self.start == self.stop:
                raise StopIteration
            else:
                self.start += 1
                return self.start ** 2
    
    Test = CTest(0, 5)
    L0 = []
    for value in Test:
        L0.append(value)                #L0 = [1, 4, 9, 16, 25]
    value = CTest.count0, CTest.count1  #value = (1, 6)
    try :
        value = next(Test)
    except StopIteration:
        pass                            #运行至此
    #对于上述类,一个类实例的迭代器只有一种状态,可以创建一个类,其实例的迭代器有多个状态
    
    class CIter():
        def __init__(self, value):
            self.value = value
            self.start = 0
        def __next__(self):
            if self.start == len(self.value):
                raise StopIteration
            else:
                value = self.value[self.start]
                self.start += 1
                return value
    
    class CTest():
        def __init__(self, value):
            self.value = value
        def __iter__(self):
            return CIter(self.value)
    
    Test = CTest("abc")
    L0 = []
    for i in Test:
        for j in Test:
            L0.append(i + j)            #L0 = ['aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca', 'cb', 'cc']
    #对于这个类,一个类的实例可以拥有多个状态
    
    #6.
    #A:运算符重载往往是多个层级的:类提供特定的方法或者提供退而求其次的更通用的替代方案
    #  布尔测试会先尝试一个特定的__bool__,如果没有则会尝试__len__
    class CTest():
        def __init__(self, value):
            self.value = value
        def __bool__(self):
            return bool(self.value)
        def __len__(self):
            return len(self.value)
        def __contains__(self, value):
            return value in self.value
    Test = CTest('abc')
    b0 = bool(Test)                     #b0 = True
    v0 = len(Test)                      #v0 = 3
    b1 = 'b' in Test                    #b1 = True
    
    #7.
    #A:__getattr__方法是拦截属性点号运算的,当类实例使用点号访问未定义属性的时候就会调用此方法,若访问的属性在继承树中存在则不会调用
    #B:__setattr__方法会拦截所有属性的赋值语句,在此函数中对self进行赋值会导致无限递归,所以要使用实例的属性字典进行赋值
    #C:可以利用__setattr__来对属性赋值进行拦截,来防止在类外部对类实例的属性进行更改,从而达到类似于属性的private属性
    class CTest():
        def __init__(self):
            self.value = 'abc'
        def __getattr__(self, str):
            print(str + " is not exist")
        def __setattr__(self, str, value):
            #self.str = value           会导致无限循环
            self.__dict__[str] = value + '__setattr__'
    Test = CTest()
    Test.value                          #并不会产生输出
    Test.str                            #输出str is not exist
    Test.value = 'szn'
    v0 = Test.value                     #v0 = 'szn__setattr__'
    b0 = 'str' in Test.__dict__         #b0 = False
    Test.str = 'str'
    b1 = 'str' in Test.__dict__         #b1 = True
    
    #8.
    #A:__getattribute__方法会拦截所有的属性获取,而非仅仅是未定义的,此方法很容易导致无限递归
    #B:__getattribute__中要用object,不然会陷入无穷递归
    class CTest():
        def __init__(self):
            self.value = 'abc'
        def __getattribute__(self, str):
            if 'value' == str:
                return object.__getattribute__(self, str)
            else:
                return str
    Test = CTest()
    v0 = Test.str                       #v0 = 'str'
    v1 = Test.value                     #v1 = 'abc'
    
    #9.
    #A:打印操作会首先尝试__str__然后尝试__repr__
    #B:__str__, __repr__都必须返回字符串,其他结果类型不会转换并会引发错误
    class CTest():
        def __repr__(self):
            return 'repr'
    Test = CTest()
    str0 = str(Test)                     #str0 = 'repr'
    str1 = repr(Test)                    #str1 = 'repr'
    
    class CTest():
        def __str__(self):
            return 'str'
    Test = CTest()
    str0 = str(Test)                     #str0 = 'str'
    str1 = repr(Test)                    #str1 = '<__main__.CTest object at 0x0000000002E3B630>'
    
    #10.
    #A:__radd__右侧加法, __iadd__增强加法, __add__加法
    #B:当两个类实例相加时,先调用__add__,然后通过简化左边的运算数来除法__radd__
    #C:每个二元运算都有类似的右侧和原处重载方法
    class CTest():
        def __init__(self):
            self.str = ''
        def __add__(self, value):
            print('a')
            return self.str + value
        def __iadd__(self, value):
            print('i')
            self.str += value
            return self
        def __radd__(self, value):
            print('r')
            return self.str + value
    
    Test = CTest()
    v0 = Test + 'a'                 #v0 = 'a' 输出a
    v1 = 'b' + Test                 #v1 = 'b' 输出r
    Test += 'c'                     #输出i
    s0 = Test.str                   #s0 = 'c'
    v2 = CTest() + CTest()          #v2 = ''  输出a
    r
    
    #11.
    #A:__call__函数调用运算符
    #B:__del__析构函数
    class CTest():
        def __call__(self, str):
            return str
        def __del__(self):
            print("del
    ")
    Test = CTest()
    str = Test('a')                 #str = 'a'
    Test = 'a'                      #输出del
    

      

  • 相关阅读:
    一些Asp.Net面试题答案
    未能加载文件或程序集"Microsoft.Web.Infrastructure 的解决方案
    偶然的发现(与Code无关)
    配置一台测试机 每个域用户独立会话
    使用 Git 和 Visual Studio Online 进行版本控制
    1.大数据概述
    递归下降语法分析程序设计
    文法 LL1
    C语言的文法分析
    词法分析
  • 原文地址:https://www.cnblogs.com/szn409/p/6776167.html
Copyright © 2011-2022 走看看