命名空间(又称“名称空间”): 存放名字的地方 (概念性的东西)
例如:变量x = 1, 1存放在内存中,命名空间就是存放名字x与1绑定关系的地方。
名称空间有3种:
- locals:是函数内的(或者是locals所在的那一层的)名称空间|,包括局部变量和形参
- globals:全局变量
- builtins: 内置模块的名字空间
不同变量的作用域不同就是由这个变量所在的命名空间决定的
作用域即范围:
1. 全局范围: 全局存活,全局有效
2. 局部范围: 临时存活, 局部有效
查看作用域方法: globals(),locals()
作用域的查找顺序: LEGB
L: locals
E: enclosing (相邻的)
G:globals
B: builtins
闭包:
def func(): n = 10 def func2(): print(‘func2:‘, n) return func2 # 没有执行func2, 只是把func2的函数名(func2的内存地址) f = func() #执行func函数, 此时func()得到的结果是func2的内存地址,即f就是func2的内存地址 f() # 执行f, 由于f就是func2的内存地址,此时执行的就是func2函数 # 输出结果: # func2: 10 # 在函数(func)外部执行了函数内部的子函数(func2),而且子函数(func2)还能够调用其父级函数(func)作用域里面所有的值。 这种现象就是闭包
装饰器:
软件开发“开放-封闭” 原则:已经实现的功能代码不允许被修改,但可以被扩展。
另外,不要改变别人函数的调用方式
现在公司有一个网站模块功能如下:
def home(): print(‘---------主页----------‘) def america(): print(‘--------欧美专区-------‘) def japan(): print(‘--------日韩专区-------‘)
现在需要在america 和 japan这两个板块前加上以下登录认证功能:
login_status = False def login(): info = [‘neo‘, ‘abc123‘] # 储存的用户信息 global login_status if not login_status: name_input = input(‘用户名:‘) password_input = input(‘密码:‘) if name_input == info[0] and password_input == info[1]: print(‘登陆成功‘) login_status = True else: print(‘密码错误‘) exit() else: print(‘用户已登录,通过检测‘)
现有如下几种方法可选:
1. 直接在America和Japan模块里面加上login认证程序, 如:
def japan(): login() # 把自己写的认证程序加到别人写好的模块里面 print(‘--------日韩专区-------‘)
这种方式违反“封闭”原则,pass。
2. 把america和japan这两个函数名当做参数传到login函数里面,如:
login_status = False def login(func): info = [‘neo‘, ‘abc123‘] # 储存的用户信息 global login_status if login_status == False: name_input = input(‘用户名:‘) password_input = input(‘密码:‘) if name_input == info[0] and password_input == info[1]: print(‘登陆成功‘) login_status = True else: print(‘密码错误‘) exit() if login_status == True: print(‘用户已登录,通过检测‘) func() #把需要认证的模块函数名传进来调用执行 def home(): print(‘---------主页----------‘) def america(x,y,z): print(‘--------欧美专区-------‘,x,y,z) def japan(): print(‘--------日韩专区-------‘) login(japan) #需要认证时,就把函数名当做参数变量传给login函数
这种方式改变了原模块(如japan())的调用方式
3. 装饰器:
login_status = False def login(func): def inner(): info = [‘neo‘, ‘abc123‘] # 储存的用户信息 global login_status if login_status == False: name_input = input(‘用户名:‘) password_input = input(‘密码:‘) if name_input == info[0] and password_input == info[1]: print(‘登陆成功‘) login_status = True else: print(‘密码错误‘) exit() if login_status == True: print(‘用户已登录,通过检测‘) func() #把需要认证的模块函数名传进来调用执行 return inner #login()执行的时候,得到的结果只是 把inner的函数名(内存地址)返回给login(func) def home(): print(‘---------主页----------‘) def america(): print(‘--------欧美专区-------‘) def japan(): print(‘--------日韩专区-------‘) japan = login(japan) # login(japan)的执行结果是得到了inner函数的内存地址,再赋值给前面的japan 变量后,变量japan就是inner函数的内存地址。 japan() # 此时执行japan函数其实执行的里面的inner函数,由于闭包的父级函数执行完后里面的变量内存并不会释放、子函数inner里面能够使用login函数里面的所有参数变量,所以inner里面的变量func执行的时候会向login函数调用其传入的先前的japan函数。 这就是装饰器的原理。 #装饰器的正规写法: @login def japan(): print(‘---------日韩专区--------‘) # 1.两个函数组成一个闭包,装饰函数做父级,被装饰的函数放在子级函数里面,子级函数名return给父级 # 2. 被修饰的函数名作为参数传给父级函数 # 3.子级函数里面包括装饰代码(如:登录认证)和 被装饰的函数(如:japan())