1、函数与命名空间:python中函数的命名空间始终是定义该函数的命名空间。因此函数中引用的全局变量始终是定义该函数模块中的全局变量。
2.闭包及其应用:闭包指的是python语言中将组成函数的语句和这些语句的执行环境打包到一起所得到的对象。当使用嵌套函数时,闭包将捕获内部函数执行所需的整个环境。此外,嵌套的函数可以使用被嵌套函数中的任何变量,就像普通函数引用全局变量一样,而不需要参数引入,示例如下:
x=14
def foo():
x=3
def bar():
print("the value of x:",x)#引用外层函数中的x
bar()#调用嵌套的内层函数
if __name__=='__main__':
foo()
程序运行的结果是3而不是全局变量14
闭包可以实现延迟求值,即将参数传递给一个函数而不是立即执行,示例如下:
def delay_fun(x,y):
def cal():
return x+y
return cal
if __name__=='__main__':
print('return a fuction of sum but do not give the final result ')
msum=delay_fun(3,4)#执行该语句并不执行真正的计算,得到只是x+y这个形式
print()
print(msum())#执行运算得到最终的结果
闭包定义不同的泛型函数,示例如下:
def line(a,b):
def aline(x):
return a*x+b
return aline
if __name__=='__main__':
line23=line(2,3)#a,b分别为2,3
line50=line(5,0)#a,b分别为5,0
print(line23(4))#x为4
print(line50(2))#x为2
从上面的示例可以看书,闭包的应用都是利用嵌套函数持有定义环境变量的特性来完成相关功能的。
3.上下文管理器是指实现上下管理协议方法的对象,它主要用于安全地释放资源(如打开的文件、数据库连接或网络连接、对对象的锁定等);对于上下文管理器对象可以使用with语句来使用它,在with语句中可以使用上下文管理器管理或提供资源,当退出with语句时,由上下文管理器来负责安全地释放资源。
上下文管理器的协议方法有下面两个:
__enter__(self)#进入上下文时调用的,它创建并返回一个可以引用的资源对象,供with语句中的程序使用
__exit__(self,type,value,tb)#该方法是退出上下文时调用的,它主要用来安全地释放资源对象,方法中的参数type、value、tb用于跟踪退出错误时发生的错误类型、值和跟踪信息。
使用上下文管理器的with语句形式为:
with context as var:
pass
其中的变量var将取得上下文管理器的__enter__()方法所返回的资源引用,供with后的代码块使用。示例如下:
class filemgr:
def __init__(self,filename):
self.filename=filename
self.f=None
def __enter__(self):#定义协议方法
self.f=open(self.filename,encoding='utf-8')
return self.#返回资源引用
def __exit__(self,t,v,tb):#定义协议方法
if self.f:
self.f.close()#释放文件资源
if __name__=='__main__':
with filemgr('section8.py') as f:
for line in f.readlines():
print(line,end='')
4.用字符串操作对象属性:在python的内建函数中有两个函数hasattr()和setattr(),它们原型分别如下:
hasattr(object,name)#测试某个对象是否含有某个属性
setattr(object,name,val)#可以设置某个对象的属性值
示例如下:
class democlass:
class_val=3
def __init__(self,x=0,y=0):
self.x=x
self.y=y
self.info()
def info(self):
print("类属性",democlass.class_val)
print("实例属性",self.x)
print("实例属性",self.y)
if __name__=='__main__':
dc=democlass()
if hasattr(democlass,'class_val'):
setattr(democlass,'class_val',1000)
if hasattr(dc,'x'):
setattr(dc,'x','xxxx')
if hasattr(dc,'y'):
setattr(dc,'y','yyyy')
dc.info()
setattr(dc,'z','zzzz')
print(dc.z)
注意一般情况下这些操作在编写框架时或者特殊的情况下才会使用,通常都是使用面向对象的方法来设置属性。
5.使用字典可以构造分支程序,但是一般情况不推荐这种使用方法会给程序阅读和理解带来困难。示例如下:
import random
def patha():
print("path a")
def pathb():
print("path b")
def pathc():
print("path c")
if __name__=='__main__':
path_dic={}
path_dic['a']=patha
path_dic['b']=pathb
path_dic['c']=pathc
paths='abc'
for i in range(4):
path=random.choice(paths)
print("choose the path:",path)
path_dic[path]()
6.重载类的特殊方法
python中,类中有一些以两条下划线开始并且以两条下划线结束的方法,称之为类的专有方法。专有方法是针对类的特殊操作的方法,下面给出这些专有方法:
__init__:构造函数,生成对象时用
__del__:析构函数,释放对象的时候调用
__add__:加运算
__mul__:乘运算
__cmp__:比较运算
__repr__:打印、转换
__setitem__:按照索引赋值
__getitem__:按照索引获取值
__len__:获得长度
__call__:函数调用
示例如下:
class book:
def __init__(self,name="python从入门到精通"):
self.name=name
def __add__(self,obj):#重载这个方法实现类相加
return self.name +"add"+obj.name
def __len__(self):#重载这个方法求其长度
return len(self.name)
if __name__=='__main__':
booka=book()
bookb=book("Java从入门到精通")
print("len(booka)",len(booka))
print("len(bookb)",len(bookb))
print(booka+bookb)#两个类相加
该代码显示了通过重载类的特殊方法实现类的运算
7.duck typing和多态:python语言属于动态类型语言,所以变量的类型是不确定的。ducktyping就是动态类型的一种风格。
在这种风格中,一个对象的有效语义不是继承自特定的类或实现特定的接口,而是由当前的方法和属性的集合决定的。在duck typing中,关注的不是对象的类型本身而是它是如何使用的。所以在使用duck typing的语言中,这样的一个函数可以接受任何类型的对象,并调用其方法。
在python面向对象的编程中,没有谈及多态,也不用定义接口。在python语言中,调用时是不检查参数类型的,如果被调用的方法不存在,则会引发错误。
如下所示:
class duck:
def __init__(self,name='duck'):
self.name=name
def quack(self):
print("gagaga")
class cat:
def __init__(self,name='cat'):
self.name=name
def quack(self):
print("miaomiao")
class tree:
def __init__(self,name='tree'):
self.name=name
def duck_demo(obj):
obj.quack()
if __name__=='__main__':
duck1=duck()
cat1=cat()
tree1=tree()
duck_demo(duck1)
duck_demo(cat1)
duck_demo(tree1)
程序会在运行duck_demo(tree1)时出错,因为在该对象中没有定义quack方法