[TOC]
Python 最大的特性,在于其语言的一致性。其定义了大量的与自然语言相近的魔法方法,用来保证语言的统一和一致性。当我们接触一个新的 Python 包时,我们能根据这些魔法方法,快速上手这个 Python 包。
魔法方法分为两类:
-
magic method
magic method built-in method __str__
str()
__len__
len()
__int__
int()
-
magic method for operators
magic method for operators built-in operator __and__
and
__or__
or
__add__
+
魔法方法的优点:
-
魔法方法统一了常见的语法规则
用户不需要再去记忆,对于获取一个对象的长度,究竟是用 .length() 还是 .size()
-
实现了魔法方法的类可以方便的调用 Python 丰富的标准库(不需要自己重复造轮子,Python 使用 Magic method 来实现多态)
例如,通过实现
__len__
和__getitem__
这两个魔法方法,该类就拥有了 list 特性,几乎所有 list 的方法都能适用 -
魔法方法的执行速度很快(其由 Python 解释器直接执行)
Python 解释器会将 built-in 方法解释成其对应的
__method__
魔法实现,然后执行这些魔法方法,Python解释器是这些魔法方法最频繁的执行者。
通过实现这些魔法方法,使得我们自定义的类,能够像 Python 的 built-in 类型一样用起来很方便。当我们想要创建一个新的类时,我们不仅要考虑其继承自哪些类,更要考虑,要实现哪些魔法方法,Python 的多态!
通常情况下,我们应该去实现魔法方法,而不是去直接调用这些方法,尽管我们可以直接调用。只有一个魔法方法比较特殊:__init__
用来调用父类的 init 方法
import math
class Vector():
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __bool__(self):
return bool(abs(self))
def __abs__(self):
return math.hypot(self.x, self.y)
def __mul__(self, other):
return Vector(self.x * other, self.y * other)
def __repr__(self):
return "vector(" + str(vector.x) + ", " + str(vector.y) + ")"
def __str__(self):
"""
__str__ 定义后,print(object) 会被 Python 解释器解释成 print(str(object))
如果没有定义 __str__,那么 print(object) 和 str(object) 会被解释成 __repr__(object)
如果连 __repr__ 也没有定义,那么就会打印一个对象 0x 值
通常情况下,只需要定义 __repr__ 即可
:return:
"""
return "hehe"
vector = Vector(3, 4)
print(abs(vector))
print(str(vector))
print(vector)
print(bool(vector))
5.0
hehe
hehe
True
Duck typing in computer programming is an application of the duck test—"If it walks like a duck and it quacks like a duck, then it must be a duck"—to determine if an [object](https://en.wikipedia.org/wiki/Object_(computer_science)) can be used for a particular purpose. With normal typing, suitability is determined by an object's type. In duck typing, an object's suitability is determined by the presence of certain [methods](https://en.wikipedia.org/wiki/Method_(computer_programming)) and properties, rather than the type of the object itself.[1]
如果它走起来像一只鸭子,叫声也像一只鸭子,那么它就是一个鸭子。
举例来说,如果一个类实现了
__len__()
方法和__getitem__()
两个 magic method, 那么该类就是一只list
Duck Typing is used to to determine if an object can be used for a particular purpose. 鸭子模型通常用于实现动态语言的多态。
Python 如何实现多态
大多数面向对象的编程语言,其多态的实现是因为某一类的对象都继承自一个 father,某一个类的特征也取决于该类的继承、接口及其自身的特征。而 Python 这一类语言不同,其多态的实现,可能是因为其类中实现了某一个特定的方法,使得该类拥有某一类特性。例如:
-
通过实现
__len__
和__getitem__
这两个魔法方法,我们自定义的类,就是一个 list,就可以拥有 list 的全部特性 -
字典的
update()
方法,其接受任何有 mapping 或 iterating 特性的对象首先判断接收的对象是否有
keys()
方法,如果有,则把它当成一只鸭子(mapping),否则再尝试 iterate 该对象,如果可以 iterate,那么就假定该对象中的元素为 元组对(key, value)。 -
lst.extend()
方法可以接受任何 iterating 的对象
如果不实现 __contains__
方法,那么 in 的操作,就会在 list 中做一个顺序遍历
-
repr()
会被解释成__repr__()
,repr 是 representation 的缩写,str()
会被解释成__str__()
-
print()
会隐式调用__str__()
-
__repr__
是对 object 的字符串描述,__str__
是str()
的魔法方法,并且print(object)
会默认被解释成print(__str__(object))
-
优先实现
__repr__()
方法。如果没有实现__str__
,那么 Python 解释器会默认调用__repr__
方法,所以__repr__
方法更通用 -
__repr__
在 debugging 和 logging 时会调用,是面向开发者的,__str__
通常用于终端用户的字符描述,是面向终端用户的
bool(object)
会被解释成 object.__bool__()
,如果 __bool__()
方法没有被定义,那么 Python 解释器会尝试调用 object.__len__()
方法,如果返回结果为0,则为 false. 这也解释了,为什么,对空的 list 和 set 取 bool 值时,返回的结果为 false。