标签:情况 lap 成功 怎样 nonlocal com 访问 新功能 ==
1、函数对象
在面向对象编程中,一切皆对象。所以函数也可以当作对象来操作。
比如将函数func1作为参数传给func2内部、或将func1在func2内返回(return)、将函数作为列表的元素,字典的vaule ......等
注意这些操作中,作为对象的func1是没有加()的,也就是作为一个对象,被当作值使用,而不是直接调用执行func1内的代码。
这就是函数对象的概念。
运用这个概念,可以简单的写一个函数字典:

def register():
print("register......")
def auth():
print("login....")
def check():
print("checking....")
func_dict = {"1": register, "2": auth, "3": check}
while True:
func_list = ["注册", "登录", "查看"]
for i, item in enumerate(func_list, start=1):
print(i, item)
cmd = input(" inpput cmdmand>>")
if func_dict.get(cmd):
func_dict.get(cmd)()
else:
print("输入有误")
既然函数是对象,函数的操作都可以在其他函数内操作,比如定义和调用:

def open_door():
print("打开冰箱门")
def putin():
print("把大象放进冰箱")
def close_door():
print("关上冰箱门")
close_door()
putin()
open_door()
2、名称空间和作用域
名称空间(命名空间)有如下几种:
名称空间:存储 名称与内存地址绑定体(名称与地址的映射) 的空间,它有三种:
内置名称空间(Built-in):存放python自带的名称与值的绑定体,len、 print、 sum等内置方法的名字,注意关键字比如if、while...不存放在其中
在python解释器启动时创建,一直保留直到解释器退出。
全局名称空间(Global):当打开一个文件然后执行时,全局名称空间记录了文件中定义的变量,包括此文件中定义的函数、类、其他导入的模块、模块级的变量与常量。
在.py文件被加载时创建,通常一直保留直到文件执行结束,python解释器退出销毁
局部名称空间(Local):每个函数所拥有的命名空间,记录了函数中定义的所有变量,包括函数的参数、内部定义的局部变量。
在函数被调用时才被创建,但函数返回结果或抛出异常时被删除。(每一个递归函数都拥有自己的命名空间)。
此外,如果函数多层嵌套,介于全局和局部间,还有当前所在层函数的名称空间,比如函数嵌套定义时,putin()函数有自己的名称空间,也可以看作局部名称空间,只不过
它的子函数close_door()还有自己的局部名称空间(Local),即,局部是相对的。
名称空间的加载顺序:内置======》全局======》局部
名称空间的访问顺序:局部===逐层往上===》全局====》内置
作用域,即名称空间的作用范围,Global广义化为—— 全局+内置名称空间、Local—— 局部名称空间
可以用 print(global()) 和在局部用print(local()) 查看当前位置的作用域内都有哪些"名称”。
还可以用 global 变量名 的方式,将变量声明为全局变量。nonlocal 变量名,将会声明:之后在当前作用域使用这个变量,将会引用外层(优先上一层)变量,但引用不到全局。
函数的作用域在定义时就固定了,与之后调用函数的位置无关!!!!
函数的作用域在定义时就固定了,与之后调用函数的位置无关!!!!
函数的作用域在定义时就固定了,与之后调用函数的位置无关!!!!
3、闭包函数
定义在一个函数func1内的函数func2,在返回内部函数func2时,不是单纯返回此函数的地址,还将函数中访问到的本层和上一层(非全局)名称与值的映射一起返回了。

闭包就是函数对象的应用
4、装饰器
现在你写了一个函数,在你的程序里多次调用,后期你需要给函数扩展功能,根据开闭原则:可以扩展功能,加入新的代码,但不能修改原有写好的代码。所以你需要在不改变函数调用方式何不修改函数内代码的情况下,给函数增加功能。
以给shop()函数添加计算函数执行时间为例:
import time, random
# shop()原来的代码如下
def shop():
print("shopping...")
time.sleep(random.random())
你需要这样写才能完成你的功能:
start = time.time()
shop()
stop = time.time()
print("this process run %.5f s" % (stop - start))
为了容易调用,你决定将它封装为一个函数:

def inner():
start = time.time()
shop()
stop = time.time()
print("this process run %.5f s" % (stop - start))
但是这样来看,你修改了函数的调用方式,你现在需要调用inner 才能完成功能。如果强行将shop=inner(),shop(),会发生循环调用,然后报错,怎样才能让shop()不会自己调用自己呢?
让shop这个函数名与调用 () 不在同一层名称空间,只有通过闭包的方式才能拿到一次,然后执行shop。同时在执行的那一层可以添加新功能。即:
def timer():
func=shop
def inner():
start = time.time()
func()
stop = time.time()
print("this process run %.5f s" % (stop - start))
return inner
shop=timer()
shop()
看到么,函数里,func = shop 就相当于最初的3中闭包语句里的 x =1,我们通过闭包的方式完成了传值!!记住,闭包也是一种传值方式!
但是还不够,这样的功能被写死了,只能计算shop()的时间,我们之前在函数参数那一节学过用第一种用变量传值的方式,还记得么?用到这里就是:
def timer(func):
def inner():
start = time.time()
stop = time.time()
print("this process run %.5f s" % (stop - start))
return inner
shop=timer(shop) # 前一个shop是变量名,第二个shop是函数(一个地址,shop函数的代码地址)作为vaule传给timmer里的形参func
shop()
这样就完成了一个装饰器
装饰器思路
现在思考下,这个装饰器有没有不足?
1.用装饰器实际上是“偷梁换柱”将被装饰函数换成了inner,如果被装饰函数有参数传入,而inner现在不能接收参数,就会报错了。
2.如果被装饰函数有返回值,用目前的装饰器接收不到。
所以进一步完善下:
def timer(func):
def inner(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
stop = time.time()
print("this process run %.5f s" % (stop - start))
return res
return inner
到这里,想必你已经能总结出一个装饰器的固定模板了,那就是:

def timer(func):
def inner(*args, **kwargs):
# 添加功能
res = func(*args, **kwargs)
# 添加功能
return res
return inner
最后,给你一个快捷使用装饰器的方式,在编程中,将某种代码简化,固定成形的语法被称为语法糖,装饰器这里就有一颗语法糖,无参装饰器的完整使用方法如下:
import time, random
def timer(func):
def inner(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
stop = time.time()
print("this process run %.5f s" % (stop - start))
return res
return inner
# 语法糖
@timer
def shop():
print("shopping...")
time.sleep(random.random())
shop()
试试再给shop()和与之同样的pay()加上认证的功能吧。

import time
import random
status_dict = {"user": None, "login": False}
db = ‘info.txt‘
def auth(auth_source="text"):
def auth_status(func):
def wrapper(*args, **kwargs):
if status_dict["user"] and status_dict.get("login"):
return func
if auth_source == "text":
uname = input("输入用户名》》")
upwd = input("输入密码》》")
with open(db, ‘rt‘, encoding=‘utf8‘) as f:
for line in f:
info_dict = eval(line.strip())
if uname == info_dict.get("name") and upwd == info_dict.get("pwd"):
print("login successful")
status_dict["user"] = uname
status_dict["login"] = True
res = func(*args, **kwargs)
return res
else:
print("username or pwd error!")
elif auth_source == " mySQL":
print("没有数据")
else:
print("没有数据")
return wrapper
return auth_status
def timer(func):
def inner(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
stop = time.time()
print("this process run %.5f s" % (stop - start))
return res
return inner
@timer
def shop():
print("shopping...")
time.sleep(random.random())
shop()
@auth(auth_source="text")
@timer
def pay():
print("paying...")
pay()
当你想新增的功能需要接收一个参数时,需要写成三层的有参装饰器。
标签:情况 lap 成功 怎样 nonlocal com 访问 新功能 ==
原文地址:https://www.cnblogs.com/guyanzhi/p/10043370.html