前言
特殊方法是为我们定义的类添加上某些特殊功能的方法,上一讲分组讲解了Python的几对特殊方法(或者成为魔术方法),分别是,
- __new__与__init__
- __enter__与__exit__
- __str__与__repr__
- __setattr__、__getattr__
- __getattribute__、__delattr__
这些都是相对较为常用的。Python中类的特殊方法远不止这些,其中还有一些不太常用,或者在某些特定场景下用到的特殊方法。
本讲会按照功能对剩余的特殊方法进行分类,不再详细的把每个特殊方法的使用都展开阐述,会着重的从每种功能中挑选出具有代表性的特殊方法进行实现、详细讲解。
函数调用
假如我们定义一个用于算数运算的类,
class Operation(object): def __init__(self, x, y): self.x = x self.y = y def add(self): print("The result is {}".format(self.x + self.y)) opt = Operation(2, 2) opt.add() # 输出 The result is 4
从这段代码可以看出 ,这是我们一贯使用类及类方法的方式,实例化--调用,其实Python提供有特殊方法__call__能够让类的调用像调用函数的方式一样。
这句话听着似乎很绕口,具体什么含义呢?用一段代码来说明,
class Operation(object): def __init__(self): self.x = None self.y = None def add(self): print("The result is {}".format(self.x + self.y)) def __call__(self, x, y): self.x = x self.y = y self.add() opt = Operation() opt(3, 3) # 输出 The result is 6
当我们给类添加特殊方法__call__后,我们可以直接使用实例名(opt)来调用类的方法,就不用在用instance.method的方法去调用。换句话说就是,当我们定义__call__后,我们使用实例名进行调用时,它会首先进入__call__方法,执行__call__中的程序。
容器与序列
容器和序列分别涉及2个特殊方法:__contains__、__len__。
从__len__名称就可以看出它的功能,给类添加一个获取序列长度的功能,所以这里着重讲解一下容器,顺带讲解一下__len__。
我们在条件语句中经常会用到这样的语句if … in、if … not in,其中__contains__就可以给类添加这样一个功能,可以通过if … in、if … not in来调用类的实例,以一段代码来举例,
class Contain(object): def __init__(self, data): self.data = data def __contains__(self, x): return x in self.data def __len__(self): return len(self.data) contain = Contain([2,3,4,5]) if 2 in contain: print("222222") if 6 not in contain: print("666666") len(contain) # 输出 222222 666666 4
从代码中可以看出,当我们调用if 2 in contain时会调用__contains__这个特殊方法,通过方法中的语句返回一个布尔型的值。此外,可以看到代码中有这样一句调用len(contain),它就是前面提到的特殊方法__len__的功能,它可以给类添加一个获取序列长度的功能,当使用len(instance)时会调用__len__方法中的程序。
算数运算
用于实现算数运算的有以下类的特殊方法的有以下几个,
运算 | 代码 | 特殊方法 |
加法 | a + b | __add__ |
减法 | a - b | __sub__ |
乘法 | a * b | __mul__ |
除法 | a / b | __truediv__ |
向下取整除法 | a // b | __floordiv__ |
取余 | a % b | __mod__ |
以一段代码举例说明加法与乘法的使用,
class Operation(object): def __init__(self, value): self.value = value def __add__(self, other): return Operation(self.value + other.value) def __mul__(self, other): return Operation(self.value * other.value) def __str__(self): return "the value if {}".format(self.value) a = Operation(3) b = Operation(5) print(a + b) print(a * b) # 输出 the value if 8 the value if 15
同理,其他几种算法运算的使用方法同加法、乘法相同。
比较运算
类的特殊方法不仅提供了算术运算,还提供了比较运算的特殊方法,它们分别是,
运算 | 代码 | 特殊方法 |
等于 | a == b | __eq__ |
不等 | a != b | __ne__ |
大于 | a > b | __gt__ |
小于 | a < b | __lt__ |
大于等于 | a >= b | __ge__ |
小于等于 | a <= b | __le__ |
以一段代码解释比较运算符的使用,
class Cmp(object): def __init__(self, value): self.value = value def __eq__(self, other): return self.value == other.value def __gt__(self, other): return self.value > other.value a = Cmp(3) b = Cmp(3) a == b # 输出 True
可以看出,比较运算和算术运算的使用非常相似。
字典功能
我们可以通过如下几个特殊方法为类添加如同字典一样的功能,
运算 | 代码 | 特殊方法 |
取值 | x[key] | __setitem__ |
设置值 | x[key]=value | __getitem__ |
删除值 | del x[key] | __delitem__ |
下面以一段代码举例说明,
class Dictionaries(object): def __setitem__(self, key, value): self.__dict__[key] = value def __getitem__(self, key): return self.__dict__[key] def __delitem__(self, key): del self.__dict__[key] diction = Dictionaries() diction["one"] = 1 diction["two"] = 2 diction["three"] = 3 diction['three'] del diction['three'] diction['three'] # 输出 3 --------------------------------------------------------------------------- KeyError Traceback (most recent call last) <ipython-input-57-dfe1a566046b> in <module>() ----> 1 diction['three'] <ipython-input-55-21dcfd1e91cb> in __getitem__(self, key) 4 5 def __getitem__(self, key): ----> 6 return self.__dict__[key] 7 8 def __delitem__(self, key): KeyError: 'three'
可以看出,当删除键值为three的值之后再次去获取会报错。
其他
除了上述提到的特殊方法之后,Python还有很多特殊方法,这里不一一举例说明,下面列举出这些特殊方法以及它们的功能和使用方法,如果感兴趣的可以对应的去查找文档学习。
运算 | 代码 | 特殊方法 |
类析构函数 | del instant | __del__ |
格式化字符串 | format(x, format_spec) | __format__ |
遍历迭代器 | iter(list) | __iter__ |
取迭代器下一个值 | next(list) | __next__ |
列出类的所有属性和方法 | dir(instance) | __dir__ |
自定义散列值 | hash(instance) | __hash__ |
自定义拷贝 | copy.copy(instance) | __copy__ |
自定义深层拷贝 | copy.deepcopy(instance) | __deepcopy__ |
上下文环境布尔值 | if instance: | __bool__ |
当然,除了这些,Python还有其他的特殊方法,例如逻辑运算、按位运算等,感兴趣的可以参考官方文档仔细学习一下,本文仅列举一些相对常用的一些特殊方法。