python代码运行原理
从python开始执行以后,就在内存里开辟一个空间,每当遇到一个变量的时候,就把变量名和值之间的对应关系记录下来。当遇到函数定义的时候,解释器只是象征性的将函数名读到内存,表示知道这个函数存在了。至于函数内部的变量和逻辑,解释器不关心。
等执行到函数调用的时候,python解释器会再开辟一块内存来存储这个函数里面的内容,这个时候,才关注函数里面有哪些变量。而函数中的变量会储存在新开辟出来的内存中,函数中的变量只能在函数内部使用,并且会随着函数执行完毕。这块内存中的所有内容也会被清空。
我们给这个‘存放名字与值得关系’得空间起了一个名字------命名空间。
代码在运行伊始,创建得存储‘变量名与值的关系’的空间叫做全局命名空间。
在函数的运行中开辟的临时的空间叫做局部命名空间。
命名空间和作用域
命名空间一共分为三种:
全局命名空间
局部命名空间
内置命名空间
内置命名空间中存放了python解释器为我们提供的名字:input,print,list...
三种命名空间之间的加载与取值顺序:
加载顺序:内置命名空间(程序运行前加载)-->全局命名空间(程序运行中:从上到下加载)-->局部命名空间(程序运行中:调用时才加载。)
取值顺序:
在局部调用:局部命名空间-->全局命名空间-->内置命名空间
在全局调用:全局命名空间-->内置命名空间
作用域:
作用域就是作用范围,按照生效分为可以分为全局作用域和局部作用域。
全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效
局部作用域:布局名称空间,只能在局部范围内生效。
globals()和locals()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 print(globals()) 2 print(locals())
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def func(): 2 a = 12 3 b = 20 4 print(locals()) 5 print(globals()) 6 7 func()
global关键字,nonlocal关键字。
global:
1、声明一个全局变量。
2、在局部作用域(函数内部)想要对全局变量进行修改时,需要用到global(限于字符串,数字。即全局作用域的列表和字典、集合可以在函数内部直接修改。)
def func(): global a a = 3 func() print(a) count = 1 def search(): global count count = 2 search() print(count)
ps:对可变数据类型(list,dict,set)可以直接引用不用通过global。
li = [1,2,3] dic = {'a':'b'} def change(): li.append('a') dic['q'] = 'g' print(dic) print(li) change() print(li) print(dic)
nonlocal:
1、不能修改全局变量
2、在局部作用域,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从哪层及以下此变量全部发生改变。
def add_b(): b = 42 def do_global(): b = 10 print(b) def dd_nonlocal(): nonlocal b b = b + 20 print(b) dd_nonlocal() print(b) do_global() print(b) add_b()
函数的嵌套和作用域链
函数的嵌套调用
def max2(x,y): m = x if x>y else y return m def max4(a,b,c,d): res1 = max2(a,b) res2 = max2(res1,c) res3 = max2(res2,d) return res3 # max4(23,-7,31,11)
函数的嵌套定义
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def f1(): 2 print("in f1") 3 def f2(): 4 print("in f2") 5 6 f2() 7 f1() 8 ########### 9 def f1(): 10 def f2(): 11 def f3(): 12 print("in f3") 13 print("in f2") 14 f3() 15 print("in f1") 16 f2() 17 18 f1()
函数的作用域链:小范围作用域可以使用大范围的变量,但是反之不行,他是单向的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def f1(): 2 a = 1 3 def f2(): 4 def f3(): 5 print(a) 6 f3() 7 f2() 8 9 f1() 10 ################ 11 def f1(): 12 a = 1 13 def f2(): 14 a = 2 15 f2() 16 print('a in f1 : ',a) 17 18 f1()
函数名的本质
函数名本质上就是函数的内存地址。
1、可以被引用
def fun(): print('in fun') print(fun)
2、可以被当作容器类型的元素
def f1(): print('f1') def f2(): print('f2') def f3(): print('f3') l = [f1,f2,f3] d = {'f1':f1,'f2':f2,'f3':f3} #调用 l[0]() d['f2']()
3、可以当作函数的参数和返回值
def f1(): print('f1') def func1(argv): argv() return argv f = func1(f1) f()
第一类对象:
1、可以在运行时创建
2、可用作函数参数或返回值
3、可存入变量的实体。
闭包
def fun(): name = 'root' def inner(): print(name) return inner() fun()
def fun(): name = 'root' def inner(): print(name) fun()
闭包函数:
内部函数包含对外部作用域而非全局作用域变量的引用,该内部函数称为闭包函数
# 函数内部定义的函数称为内部函数
由于有了作用域的关系,我们就不能拿到函数内部的变量和函数了。如果我们想拿就要返回。
我们都知道函数内的变量我们想在函数外部用,可以直接返回这个变量。
那么我们想在函数的外部直接调用函数内部的函数。直接返回这个函数的名字。(即fun,不带‘()’)
def fun(): name = 'root' def inner(): print(name) return inner fun()()
判断闭包函数的方法
def fun(): name = 'root' def inner(): print(name) print(inner.__closure__) return inner fun()()
#(<cell at 0x02DF6F10: str object at 0x0506C8E0>,)
name = 'ubuntu' def fun(): # name = 'root' def inner(): print(name) print(inner.__closure__) return inner fun()()
闭包嵌套
1 def wrapper(): 2 money = 100 3 def fun(): 4 name = 'root' 5 def inner(): 6 print(name, money) 7 return inner 8 return fun 9 10 wrapper()()()
装饰器
装饰器本质上就是一个python函数,它可以在其他函数不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。装饰器的应用场景:插入日志,性能测试,事物处理,缓存等。
开放封闭原则:
1、对扩展是开放的
任何一个程序,不可能在设计之处就已经想好了所有的功能,并且不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。
2、对修改是封闭的
已经上线的函数,对其进行修改,很可能会影响其他已经在使用该函数的用户。
装饰器模板
def timer(func): def inner(*args,**kwargs): '''执行函数之前要做的''' re = func(*args,**kwargs) '''执行函数之后要做的''' return re return inner
带参数的装饰器 #待填
def outer(flag): def time(fun): def fun(*args, **kwargs): if flag: pass ret = fun(*args, **kwargs) if flag: pass return ret return fun return time @outer(False) def func(): pass
多个装饰器装饰一个函数---俄罗斯套娃
def wrapper1(func): def inner(): print('wrapper1 ,before func') func() print('wrapper1 ,after func') return inner def wrapper2(func): def inner(): print('wrapper2 ,before func') func() print('wrapper2 ,after func') return inner @wrapper2 @wrapper1 def f(): print('in f') f()
参数的用法
def fun(start, stop=None, step=1): if stop is None: start, stop = 0, start result = [] i = start while i < stop: result.append(i) i += step return result print(fun(10))
函数的有用信息
from functools import wraps def logger(f): @wraps(f) def inner(*args, **kwargs): """ :param args: 函数名,密码 :param kwargs: 备用 :return: True """ ret = f(*args, **kwargs) return ret return inner @logger def login(username,password): """ 此函数是完成登录功能的函数,需要用户名,和密码两个参数,返回True 登陆成功 :return: True """ print(666) return True # login(1,2) #inner() # # login('alex', 123) print(login.__doc__) print(login.__name__)