详解Python类中的特殊方法(前后都有双下划线的方法)-__len__、__str__、__getitem__、__iter__、__getattr__、__call__等

其他关于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类中的特殊方法(前后都有双下划线的方法)-__len__、__str__、__getitem__、__iter__、__getattr__、__call__等)