美文网首页python干货python专题Python
详解Python类中的特殊方法(前后都有双下划线的方法)-__l

详解Python类中的特殊方法(前后都有双下划线的方法)-__l

作者: 超级超级小天才 | 来源:发表于2020-12-05 06:20 被阅读0次

    其他关于Python的总结文章请访问:https://www.jianshu.com/nb/47435944

    详解Python类中的特殊方法(前后都有双下划线的方法)-lenstrgetitemitergetattrcall

    类中定义的一些特殊方法,也就是方法名称前后都有双下划线标识的方法,都具有特殊的意义,重写这些方法可以帮助类更好地发挥功能,这里主要介绍几种常用的、重要的方法。

    我们以一个偶数类(Even)为例,其中会创建一个N个偶数的列表,同时创建一个该类的实例even

    class Even:
        def __init__(self, N):
            self.N = N
            self.even_list = [2 * x for x in range(N)]
    
    even = Even(10)
    

    len方法

    __len__方法在当 len 函数作用于该类的时候被调用,比如我们定义Even类的长度就是偶数列表的个数:

    def __len__(self):
        return self.N
    

    此时调用len函数作用于Even类的实例上就会调用 __len__ 方法:

    print(len(even)) # 20
    

    如果没有定义 __len__ 方法,当len函数作用于类的实例上时就会报错:

    TypeError: object of type 'Even' has no len()
    

    str方法

    __str__方法在当 print 函数作用于该类的时候被调用,比如我们继续编写Even类,加入__str__方法:

    def __str__(self):
        return "An Even Numbers List with {} Items:\n{}".format(self.N, self.even_list)
    

    此时调用 print(even) 就可以得到如下的结果:

    An Even Numbers List with 10 Items:
    [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
    

    repr方法

    __repr__方法是在直接(比如解释器中)直接调用类或者实例时被触发的,它和__str__很像,唯一不同的是没有print操作,比如这样调用时会触发 __repr__(Python解释器中):

    >>> even
    

    注意上边跟 >>> print(even) 的区别)

    一般来说__repr__方法和__str__方法输出的内容相同,所以通常可以使用简单的方式来定义__repr__方法:

    __repr__ = __str__
    

    getitem方法

    __getitem__方法在对类进行迭代时触发,而且必须传入一个整数作为参数:

    def __getitem__(self, n):
        return self.even_list[n]
    

    这样就可以使用for循环进行对Even类的遍历了,或者使用 even[i] 这样对Even类进行索引,甚至是使用切片:

    for i in range(len(even)):
        print(even[i], end=' ')
    
    print()
    
    for e in even:
        print(e, end=' ')
    
    print()
    
    print(even[2:8])
    print(even[8:2:-1])
    

    可以得到输出结果:

    0 2 4 6 8 10 12 14 16 18 
    0 2 4 6 8 10 12 14 16 18 
    [4, 6, 8, 10, 12, 14]
    [16, 14, 12, 10, 8, 6]
    

    setitem方法

    __setitem__方法是和__getitem__方法对应的,用来更改某下标所对应处的值,必须传入两个参数,一个key用于指定要修改的下标,一个value用于告知要修改的值:

    def __setitem__(self, key, value):
        self.even_list[key] = value
    

    这样就可以修改类的某个索引处的值了:

    print(even[0])  # 0
    even[0] = 100
    print(even[0])  # 100
    

    delitem方法

    __delitem__方法实现了del作用于类时的逻辑:

    def __delitem__(self, key):
        del self.even_list[key]
        self.N = len(self.even_list)
    

    这样使用 del 作用与类就可以得到相应的结果:

    print(even)
    del even[0:5]
    print(even)
    

    得到的结果:

    An Even Numbers List with 10 Items:
    [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
    An Even Numbers List with 5 Items:
    [10, 12, 14, 16, 18]
    

    iter方法和next方法

    __iter__方法返回一个可迭代对象,供 for ... in ... 循环对类进行迭代,同时配合__next__方法在对类使用 next 函数时调用获取下一个迭代值,并且 __next__方法中可以实现迭代结束后给出 StopIteration 错误的逻辑。

    getattr方法

    __getattr__方法在类的实例试图调用一个不存在的属性时触发,可以对应地返回一个属性值或者函数,也可以完成对于一些属性抛出错误的逻辑:

    def __getattr__(self, item):
        if item == 'length':
            return self.N
        if item == 'get_length':
            return lambda: self.N
        raise AttributeError("Even doesn't have the attribute {}".format(item))
    

    此时如果这样使用类,就会得到相应的结果:

    print(even.length)  # 10
    print(even.get_length())  # 10
    print(even.some_other_attribute)  # AttributeError: Even doesn't have the attribute some_other_attribute
    

    注意该方法只会处理调用不存在的属性的情况,如果属性存在则不会到__getattr__方法中寻找

    call方法

    __call__方法在类的实例被调用的时候触发,还可以接收参数,我们可以使用callable函数来判断一个类的实例是不是可调用的,callable一个没有定义__call__方法的类的实例会返回False,反之返回True

    def __call__(self):
        print("Hello, you called me: an even numbers list with {} items".format(self.N))
    

    此时调用该类的实例:

    even()
    print(callable(even))
    

    就会得到相应的结果:

    Hello, you called me: an even numbers list with 10 items
    True
    

    上述内容的完整类的代码

    class Even:
        def __init__(self, N):
            self.N = N
            self.even_list = [2 * x for x in range(N)]
    
        def __len__(self):
            return self.N
    
        def __str__(self):
            return "An Even Numbers List with {} Items:\n{}".format(self.N, self.even_list)
    
        __repr__ = __str__
    
        def __getitem__(self, n):
            return self.even_list[n]
    
        def __setitem__(self, key, value):
            self.even_list[key] = value
    
        def __delitem__(self, key):
            del self.even_list[key]
            self.N = len(self.even_list)
    
        def __getattr__(self, item):
            if item == 'length':
                return self.N
            if item == 'get_length':
                return lambda: self.N
            raise AttributeError("Even doesn't have the attribute {}".format(item))
    
        def __call__(self):
            print("Hello, you called me: an even numbers list with {} items".format(self.N))
    

    相关文章

      网友评论

        本文标题:详解Python类中的特殊方法(前后都有双下划线的方法)-__l

        本文链接:https://www.haomeiwen.com/subject/vfbwwktx.html