第11天 函数对象、函数嵌套、名称空间与作用域、装饰器

在python中,函数是第一类对象,函数是第一等公民
本质上函数可以当变量用
def func(): # func=函数的内存地址
print(“from func”)

1.可以赋值
f = func
print(f) #打印的结果就是func的内存地址
f() #运行代码func(),from func

2.可以当作参数传给另一个函数
def foo(x):
print(x)
x() #加括号触发func代码的运行,from func
func=内存地址
foo(func)

3.可以当作函数的返回值
def foo(x):
return x

res=foo(func)
print(res)

4.可以当作容器类型的元素
l=[func]
l0 #把func函数名当作元素放进l的列表中.运行代码结果为from func

银行取款功能
def withdraw():
print(“提款”)
def tranfer():
print(“转账”)
def check_balance():
print(“查询余额”)
def save():
print(“存款”)

func_dic = {
“1”: [“提款”, withdraw],
“2”: [“转账”, tranfer],
“3”: [“查询余额”, check_balance],
“4”: [“存款”, save]
}
while True:
print(“0” “退出”)
for k,v in func_dic.items():
print(k)
choice = input(“输入指令”).strip()
if choice == “0”:
break
if choice in func_dic:
func_dic[choice]1
else:
print(“输入错误”)

函数的嵌套调用
def max2(x,y):
if x>y:
return x
else:
return y

def max4(a, b, c, d):
res1 = max2(a, b)
res2 = max2(res1, c)
res3 = max2(res2, d)
return res3

print(max4(11, 99, 66, 55)) #打印结果为99

函数的嵌套定义
def f1():
x = 10
def f2():
print(“from f2”)
print(x) #一个变量放进函数里面只能在函数里面使用
print(f2)
f1()
print(x) #打印结果不显示
print(f2) #打印结果不显示

namespaces名称空间:存放名字的地方
内置名称空间:存放内置的名字
生命周期:python解释器启动则产生,关闭则销毁

全局名称空间:存放的是顶级的名字(只有不在函数内的都是顶级名字)
        生命周期:运行python文件时则产生,python文件运行完毕则销毁

运行python,启动python解释器,先运行内置名称空间文件,然后会立刻运行全局名称空间文件,再是局部空间
x = 10
y = 20
if 1 > 0:
z = 30

with open(“a.txt”, mode=“wt”)as f:
a = 333

while True:
c = 444
以上这些都是属于全局名称空间

局部名称空间:存放的是函数内的名字
        生命周期:定义函数时是不会产生名称空间的,调用函数则产生,函数调用完毕则销毁

x=10
def foo(m):
m=111
n=222
foo(111)

内置名称空间就一个,一个文件就一个全局名称空间,调用一个函数就有一个局部空间名称,局部空间名称有好多个

名称空间找名字的优先级关系:先从当前空间找,一级一级往上找.名称空间之间没有嵌套关系
在函数内找名称,先从函数局部名称空间里找名字,再去全局名称空间找,最后再去内置名称空间找
如果在全局名称空间找,就先从全局名称空间里面找名字,再去内置空间找,不会去局部名称空间找
核心:名字的访问优先级
基于当前的位置向外查找
函数内->外层函数->…->全局->内置
在定义的时候不要把内置的名字拿来定义.这样有可能会覆盖内置的名字
len = 10

def func():
len = 20
print(len) #len在局部名称空间内,运行结果先运行len=20

func()
print(len) #len在全局名称空间内,运行结果len=10

案例
def f1():
# x=555
def f2():
# x=666
print(x)
f2()
x = 444
f1()
改代码运行时,先从局部名称空间最里层,先找到x=666,
再找到x=555,如果局部名称空间内没有找到名称时,会找到全局名称空间x=444
按照顺序找到任意一个名称都不会再继续往外层寻找了

LEGB:(在函数定义阶段就成成立了)
L:local 函数内部作用域
E:Enclosing 函数内部与内嵌函数之间
G:Global 全局作用域
B:build-in 内置作用

名称空间与作用域的关系时在函数定义阶段(扫描语法时)就确立的,与什么时候调用以及调用位置无关
案例1:
x=111
def f1():
print(x)

def f2():
x = 222
f1()
f2() 在定义阶段,x=111,结果为111

案例2:
x = 111
def f1():
print(x)
x = 222 #局部名称空间的x是先引用后定义的,运行代码会直接语法报错
f1()

作用域
全局作用域:内置名称空间+全局名称空间
特点:全局存活,全局有效
局部作用域:局部名称空间的名字
特点:临时存货,局部有效

global
案例1 全局名称空间的名称为可变类型时
l = []
def func():
l.append(1111)
func()
print(l)
案例2 全局空间名称为不可变类型时
x = 111
def func():
global #当全局的值是不可变类型时,加了global全局作用域后会把全局的x=111的值改成函数里面x=222的值
x = 222
func()
print(x)
尽量不要用global局部作用域改全局的作用域

nonlocal
x = 111
def f1():
x = 222
def f2():
nonlocal x
x=333
f2()
print(x)
f1()
#nonlocal会把外层的f1的x=222改成内层的x=333,如果说第一个外层没有找到局部名会一直往外层找,找到全局层之前还找不到会直接报错

闭包函数:
闭:指的是该函数的定义时在函数内的函数
包:值得是该函数引用了一个外层函数作用域的名字

def outter():
x = 111

def wrapper():
print(x)

return wrapper

f = outter()
print(f)

def foo():
x=222
f()

foo()

为函数体代码传参的方案
方案1:直接用参数传
def wrapper(x):
print(x)

wrapper(111)
wrapper(222)
wrapper(333)

方案2:闭包函数传参
def outter(x):
# x=111
def wrapper():
print(x)
return wrapper
f1 = outter(111)
f1()
f2 = outter(222)
f2()
f3 = outter(333)
f3()

装饰器
什么是装饰器
装饰器就是一个用来为被装饰对象添加新功能的工具

为何要用装饰器
开放封闭原则:一旦软件上线运行之后,应该对修改源代码封闭,对扩展功能开发
原则:
1.不修改函数内的源代码
2.不修改函数的调用方式
装饰器就是在遵循原则1和2的前提下,为被装饰对象添加上新功能

如何实现装饰器
需求:为函数index添加统计运行时间的功能
方案一:
import time

def index():
start = time.time()
time.sleep(1)
print(“from index”)
stop = time.time()
print(“run time is %s” % (stop - start))

index()

方案二:
import time

def index():
time.sleep(1)
print(“from index”)

start = time.time()
index()
stop = time.time()
print(“run time is %s” % (stop - start))

方案三:
import time

def index():
time.sleep(1)
print(“from index”)

def wrapper():
start = time.time()
index()
stop = time.time()
print(“run time is %s” % (stop - start))

wrapper()

方案四:
import time

def index():
time.sleep(1)
print(“from index”)

def wrapper(func):
start = time.time()
func()
stop = time.time()
print(“run time is %s” % (stop - start))

wrapper(index)

方案五:
import time

def index():
time.sleep(1)
print(“from index”)

def wrapper(func):
start = time.time()
func()
stop = time.time()
print(“run time is %s” % (stop - start))

wrapper(index)

你可能感兴趣的:(python)