Python一切皆对象,但同时,Python还是一个多范式语言(multi-paradigm),你不仅可以使用面向对象的方式来编写程序,还可以用面向过程的方式来编写相同功能的程序(还有函数式、声明式等,我们暂不深入)。Python的多范式依赖于Python对象中的特殊方法(special method)。
特殊方法名的前后各有两个下划线。特殊方法又被成为魔法方法(magic method),定义了许多Python语法和表达方式,正如我们在下面的例子中将要看到的。当对象中定义了特殊方法的时候,Python也会对它们有“特殊优待”。比如定义了__init__()方法的类,会在创建对象的时候自动执行__init__()方法中的操作。
可以通过dir()来查看对象所拥有的特殊方法,比如dir(1),我们把1看作是一个整数类的实例,执行dir(1)就是查看1这个整数对象拥有的特殊方法。
运算符
Python中的运算符是通过调用对象的特殊方法来实现的,举一个最常见的例子1+1,实际上是调用1这个对象的__add__()方法。
比如:
'abc' + 'xyz' # 连接字符串
实际上是执行了下述操作:
'abc.__add__('xyz')'
所以在python中看两个对象能否进行加法运算,首先要看相应的对象是否有__add__()方法。一旦对象有__add__()方法,即使这个对象从数学上来说不可加,但是我们仍然可以用加法的形式(+运算符)来表达object.__add__()方法,这有点类似C#中的运算符重载,在Python中,运算符起到简化书写的功能,但它依靠特殊方法实现。
Python不强制用户使用面向对象的编程方法。用户可以选择自己喜欢的使用方式(比如选择使用+符号,还是使用更加面向对象的__add__()方法)。特殊方法写起来总是要更费事一点。
尝试下面的操作,看看效果,在想想这些对象的方法对应的运算符。
(1.8).__mul__(2.0)
(True.__or__(False)
内置函数
与运算符类似,python的内置函数也是调用对象的特殊方法,比如:
abs(-1) # 求绝对值
实际上是执行了下述操作:
(-1).__abs__() # 调用-1这个对象的特殊方法来求绝对值。
相对于去调用对象特殊方法,直接使用内置函数显的更加短小简洁,当然,可能看起来没有调用对象的特殊方法那么直观。
序列对象的引用
python中的list,tuple,range这三类都属于序列对象,他们各自有不同的特性,适用于不同的场景,他们有一个共同的特点就是他们的对象都是一个序列,可以简单的理解成是一个数组。
下面是我们一个常见的对一个list对象的引用:
li=[1,2,3,4,5,6,7,8] # 定义一个从1-8的list对象li
a=li[3] # 变量a指向对象li中的第三个元素的引用
这是一个很常见的引用,就像我们在C#中通过数组下标来访问一个数组成员一样。
在python中,它相当于是调用了li对象的__getitem__()方法来访问list中的成员一样:
li.__getitem__(3)
可以思考一下,这个__getitem__()方法是如何定义的?
函数
在python中,函数也是一种对象。实际上,任何一个有__call__()特殊方法的对象都被当作是函数。比如下面的例子:
class SampleMore(object): # 定义一个类,其__call__()方法接收一个参数a并返回a+5
def __call__(self,a):
return a+5
add = SampleMore() # 实例化这个类,并用add变量引用这个类的对象。
add(2) # 调用这个对象的方法,实际上就是调用__call__()方法
map(add,[2, 4, 5]) # 将add作为函数依次作用到这个list中。
add作为SampleMore类的一个对象,当被当作函数来调用时,add执行加5的操作。add还可以作为函数对象,被传递给map()函数。
总结
对于内置的对象(比如整数、表、字符串等),它们所需要的特殊方法都已经在Python中准备好了。而用户自己定义的对象也可以通过增加特殊方法,来实现自定义的语法。特殊方法比较靠近Python的底层,许多Python功能的实现都要依赖于特殊方法。我们将在以后看到更多的例子。
参考