3.6函数进阶
名称空间:name space
例:若变量X=1,1存放于内存中,那存放X与1绑定关系的地方就叫做名称空间。
名称空间共三种,分别如下:
- locals:是函数内名称空间,包括局部变量和形参
- globals:全局变量,函数定义所在模块的名字空间
- builtins:内置模块的名字空间
不同变量的作用域不同就是由于这个变量所在的命名空间决定的。
作用域即范围:
- 全局范围:全局存活,全局有效
- 局部范围:临时存活,局部有效
注:查看作用域方法 globals(),locals()
作用域查找顺序:
level='L0'
n=22
def func():
leval='L1'
n=33
print(locals())
def outer():
n=44
level='L2'
print(locals(),n)
def inner():#此处打印n是多少?
level='L3'
print(locals(),n)
inner()
outer()
func()
问题:在inner()里的打印n的值是多少?
LEGB代表名字查找顺序:locals->enclosing function->globals->__builtins__
- locals是函数内的名字空间,包括局部变量和形参
- enclosing外部嵌套函数的名字区间
- globals全局变量,函数定义所在模块的名字空间
- builtins内置模块的名字空间
闭包
关于闭包,即函数定义和函数表达式位于另一个函数的函数体内(嵌套函数)。
详解:而且,这些内部函数可以访问他们所在外部函数中声明的所有局部变量、参数。当其中一个这样的内部函数在包含他们的外部函数被调用时,就会形成闭包。也就是说,内部函数会在外部函数返回后被执行。而当这个内部函数执行时,它仍然必须访问其外部函数的局部变量、参数以及其他内部函数。这些局部变量、参数和函数声明(最初时)的值是外部函数返回时的值,但也会会受到内部函数的影响。
def outer():
name='alex'
def inner():
print("在inner里打印外层函数的变量“,name)
return inner
f=outer()
f()
闭包的意义:返回的函数对象,不仅仅是一个函数对象,在函数外还包裹了一层作用域,这使得该函数无论在何处调用,优先使得自己外层包裹的作用域。
装饰器
例1:
#_*_coding:utf-8_*_
user_status = False #用户登录了就把这个改成True
def login():
_username = "alex" #假装这是DB里存的用户信息
_password = "abc!23" #假装这是DB里存的用户信息
global user_status
if user_status == False:
username = input("user:")
password = input("pasword:")
if username == _username and password == _password:
print("welcome login....")
user_status = True
else:
print("wrong username or password!")
else:
print("用户已登录,验证通过...")
def home():
print("---首页----")
def america():
login() #执行前加上验证
print("----欧美专区----")
def japan():
print("----日韩专区----")
def henan():
login() #执行前加上验证
print("----河南专区----")
home()
america()
henan()
注:在软件开发中有一个原则“开放-封闭”原则,简单来说,它规定已经实现的代码不允许被修改,但可以被扩展,即:
封闭:已实现的功能代码不应该被修改
开放:对现有功能的扩展开放
def login(func): #把要执行的模块从这里传进来
def inner():#再定义一层函数
_username = "alex" #假装这是DB里存的用户信息
_password = "abc!23" #假装这是DB里存的用户信息
global user_status
if user_status == False:
username = input("user:")
password = input("pasword:")
if username == _username and password == _password:
print("welcome login....")
user_status = True
else:
print("wrong username or password!")
if user_status == True:
func() # 看这里看这里,只要验证通过了,就调用相应功能
return inner #用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数
简化上边的代码——去掉下边这行
america=login(america)#你在这里相当于把america这个函数替换了
最终简化为:
#_*_coding:utf-8_*_
user_status = False #用户登录了就把这个改成True
def login(func): #把要执行的模块从这里传进来
def inner(*args,**kwargs):#再定义一层函数
_username = "alex" #假装这是DB里存的用户信息
_password = "abc!23" #假装这是DB里存的用户信息
global user_status
if user_status == False:
username = input("user:")
password = input("pasword:")
if username == _username and password == _password:
print("welcome login....")
user_status = True
else:
print("wrong username or password!")
if user_status == True:
func(*args,**kwargs) # 看这里看这里,只要验证通过了,就调用相应功能
return inner #用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数
def home():
print("---首页----")
@login
def america():
#login() #执行前加上验证
print("----欧美专区----")
def japan():
print("----日韩专区----")
# @login
def henan(style):
'''
:param style: 喜欢看什么类型的,就传进来
:return:
'''
#login() #执行前加上验证
print("----河南专区----")
home()
# america = login(america) #你在这里相当于把america这个函数替换了
henan = login(henan)
# #那用户调用时依然写
america()
henan("3p")
带参数装饰器:
#_*_coding:utf-8_*_
user_status = False #用户登录了就把这个改成True
def login(auth_type): #把要执行的模块从这里传进来
def auth(func):
def inner(*args,**kwargs):#再定义一层函数
if auth_type == "qq":
_username = "alex" #假装这是DB里存的用户信息
_password = "abc!23" #假装这是DB里存的用户信息
global user_status
if user_status == False:
username = input("user:")
password = input("pasword:")
if username == _username and password == _password:
print("welcome login....")
user_status = True
else:
print("wrong username or password!")
if user_status == True:
return func(*args,**kwargs) # 看这里看这里,只要验证通过了,就调用相应功能
else:
print("only support qq ")
return inner #用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数
return auth
def home():
print("---首页----")
@login('qq')
def america():
#login() #执行前加上验证
print("----欧美专区----")
def japan():
print("----日韩专区----")
@login('weibo')
def henan(style):
'''
:param style: 喜欢看什么类型的,就传进来
:return:
'''
#login() #执行前加上验证
print("----河南专区----")
home()
# america = login(america) #你在这里相当于把america这个函数替换了
#henan = login(henan)
# #那用户调用时依然写
america()
# henan("3p")
3.6生成器,迭代器
列表生成式:
例:把列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],要求把列表里的每个值都加1
>>> a = [i+1 for i in range(10)]
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10列表生成式]
这种写法就叫做生成式
生成式
在python中一边循环一边计算的机制称为生成器:generator
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]
改成(),
就创建了一个generator:
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>
建L
和g
的区别仅在于最外层的[]
和()
,L
是一个list,而g
是一个generator。
我们可以直接打印出list的每一个元素,想要打印书generator的每一个元素有哦两种方法:
第一种用next()
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
25
>>> next(g)
36
>>> next(g)
49
>>> next(g)
64
>>> next(g)
81
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
第二种for循环,generator也是可迭送的对象
>>> g = (x * x for x in range(10))
>>> for n in g:
... print(n)
...
0
1
4
9
16
25
36
49
64
81
迭送器
可以直接作用于for
循环的数据类型有以下几种:
一类是集合数据类型,如list
、tuple
、dict
、set
、str
等;
一类是generator
,包括生成器和带yield
的generator function。
这些可以直接作用于for
循环的对象统称为可迭代对象:Iterable
。
可以使用isinstance()
判断一个对象是否是Iterable
对象:
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False
而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
*可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
可以使用isinstance()判断一个对象是否是Iterator对象:
>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
生成器都是Iterator
对象,但list
、dict
、str
虽然是Iterable
,却不是Iterator
。
把list
、dict
、str
等Iterable
变成Iterator
可以使用iter()
函数:
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True
Python的Iterator
对象表示的是一个数据流,Iterator对象可以被next()
函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration
错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()
函数实现按需计算下一个数据,所以Iterator
的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator
甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。