更多精彩内容,请关注公众号【平凡而诗意】~
完整代码请查看github项目: advance-python(https://github.com/Jackpopc/advance-python/blob/master/2-magic-method_2.ipynb)
前言
特殊方法是为我们定义的类添加上某些特殊功能的方法,上一讲分组讲解了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还有其他的特殊方法,例如逻辑运算、按位运算等,感兴趣的可以参考官方文档仔细学习一下,本文仅列举一些相对常用的一些特殊方法。
文档获取
本讲的Markdown格式文档我进行共享了,需要的可以关注公众号【平凡而诗意】回复关键字"python"获取。