Python一切皆对象,但同时,Python还是一个多范式语言(multi-paradigm),你不仅可以使用面向对象的方式来编写程序,还可以用面向过程的方式来编写相同功能的程序(还有函数式、声明式等,我们暂不深入)。Python的多范式依赖于Python对象中的特殊方法(special method)。
特殊方法名的前后各有两个下划线。特殊方法又被成为魔法方法(magic method),定义了许多Python语法和表达方式,正如我们在下面的例子中将要看到的。当对象中定义了特殊方法的时候,Python也会对它们有“特殊优待”。比如定义了__init__()方法的类,会在创建对象的时候自动执行__init__()方法中的操作。
# without context manager f = open("new.txt", "w") print(f.closed) # whether the file is open f.write("Hello World!") f.close() print(f.closed)
以及:
# with context manager with open("new.txt", "w") as f: print(f.closed) f.write("Hello World!") print(f.closed)
对象的属性可能来自于其类定义,叫做类属性(class attribute)。类属性可能来自类定义自身,也可能根据类定义继承来的。一个对象的属性还可能是该对象实例定义的,叫做对象属性(object attribute)。
def line_conf(): def line(x): return 2*x+1 return line # return a function object my_line = line_conf() print(my_line(5))
def line_conf(): b = 15 def line(x): return 2*x+b return line # return a function object b = 5 my_line = line_conf() print(my_line(5))
我们可以看到,line定义的隶属程序块中引用了高层级的变量b,但b信息存在于line的定义之外 (b的定义并不在line的隶属程序块中)。我们称b为line的环境变量。事实上,line作为line_conf的返回值时,line中已经包括b的取值(尽管b并不隶属于line)。
def line_conf(a, b): def line(x): return ax + b return line line1 = line_conf(1, 1) line2 = line_conf(4, 5) print(line1(5), line2(5))
# get square sumdef square_sum(a, b): return a**2 + b**2 # get square diffdef square_diff(a, b): return a**2 - b**2
print(square_sum(3, 4))
# modify: print input # get square sumdef square_sum(a, b): print("intput:", a, b) return a**2 + b**2 # get square diffdef square_diff(a, b): print("input", a, b) return a**2 - b**2 print(square_sum(3, 4)) print(square_diff(3, 4))
def decorator(F): def new_F(a, b): print("input", a, b) return F(a, b) return new_F # get square sum@decorator def square_sum(a, b): return a**2 + b**2 # get square diff@decorator def square_diff(a, b): return a**2 - b**2 print(square_sum(3, 4)) print(square_diff(3, 4))
装饰器可以用def的形式定义,如上面代码中的decorator。装饰器接收一个可调用对象作为输入参数,并返回一个新的可调用对象。装饰器新建了一个可调用对象,也就是上面的new_F。new_F中,我们增加了打印的功能,并通过调用F(a, b)来实现原有函数的功能。
我们知道,Python中的变量名和对象是分离的。变量名可以指向任意一个对象。从本质上,装饰器起到的就是这样一个重新指向变量名的作用(name binding),让同一个变量名指向一个新返回的可调用对象,从而达到修改可调用对象的目的。
- 上下文管理器
- 在不需要文件的时候,自动关闭文件
- with...as...
- 有隶属于它的程序块
- 当程序块结束后,自动关闭文件
- 对象属性
- 闭包
- 函数line,和环境变量 a,b 构成了闭包,提高了代码的复用性。
- 装饰器
- 提高了程序的可重复利用性,并增加了程序的可读性