函数嵌套指的是在函数内部又调用了其它的函数。
# 求三个数的最大值
def max2(x, y):
if x > y:
return x
else
return y
def max3(x, y, z):
res1 = max2(x, y)
res2 = max2(res1, z)
return res2
print(max3(11, 199, 2))
函数的嵌套定义指的是在函数内又定义了其它函数。
def func1():
print('from func1')
def func2():
print('from func2')
print(func2) # 输出函数func2的地址
func2()
名称空间从字面意思理解就是存放名字的地方,在学习变量的时候知道:定义一个变量就是开辟一块内存空间,这个内存空间存放的就是变量的值,除了变量值之外,还有变量名。
变量名和变量值的绑定关系这个数据要在内存中存储。变量名是名字,函数名也是名字,名称空间就是存放名字与值的绑定关系的地方。
名称空间分为三类
# 内置
print(print)
print(len)
#全局
x = 1 # 全局
def func(): # func是全局名称空间
name = 'Albert' # name是局部名称空间
if 10>3:
y = 2 # 全局
while True:
z = 5 # 全局
break
内置名称空间与全局名称空间的结束的生命周期基本上是一致的,程序执行结束或者文件关闭(手动强制关闭写python代码的这个文件),内置或者全局名称空间生命周期结束。局部名称空间生命周期是从函数调用开始到函数结束,即函数生命周期终止。
加载顺序:内置名称空间->全局名称空间->局部名称空间
查找名字:局部名称空间->全局名称空间->内置名称空间
# 加载顺序很好理解,查找顺序是以当前位置为起始点
len = 0
def f1():
len = 1
def f2():
len = 2
print(len)
len = 3
f2()
f1() # 输出为2
变量作用域是指一个变量可以使用的范围,例如在函数中定义的变量只允许本函数使用,称之为局部变量;而在代码非函数中定义的变量则称为全局变量,允许在多个函数或者代码中共同访问。
Python为了进行全局变量的标注,提供了global关键字,只需要在变量使用前利用global进行声明就可以自动将函数中操作的变量设置为全局变量。
关于变量名称解析的LEGB原则
如果按照以上顺序都无法找到指定的变量名称,那么在程序执行时就会报错。
在代码开发中常常会出现同一变量名被重复使用的情况,为避免使用时出现问题,项目开发定义变量时往往使用一些标记结合变量名称一起进行定义,例如:
采用此类方法可以从根本上杜绝变量名重名的影响。而是否采用这种命名方式,还需要取决于开发者所处的开发公司的命名要求来决定。
全局作用域包含的是内置名称空间与全局名称空间的名字,它的特点是:
如果在局部使用全部作用域的变量是没有问题的,但是如果在局部修改全局作用域的变量则不能直接修改,而要使用global关键字才能修改。
global_count = 0
def global_check():
print(global_count) # 直接使用全局变量
def global_modify():
global global_count # 修改前需要先使用global
global_count += 1
print(global_count)
global_check()
global_modify()
局部作用域包含的是局部名称空间的名字,它的特点是
如果在局部使用的是嵌套在函数内部的局部变量,可以直接使用,而修改需要使用nonlocal关键字。
def make_counter():
count = 0
def check_counter():
print(count)
check_counter()
def modify_counter():
nonlocal count
count += 1
print(count)
modify_counter()
make_counter()
函数在python中是第一类对象,这个话可以通俗理解为函数也是一个对象,就是int,字符串,列表和字典一样都是对象,等学到面向对象就能有进一步的理解,现在可以暂时理解为函数对象可以像int或者字符串一样使用。
# 1、函数可以被引用
# int示例
x = 1
y = x
# 函数示例
def bar():
print('from bar')
f = bar
f()
# 2、可以当参数传入
# int示例
x = 1
def func(a):
print(a)
func(x)
# 函数示例
def bar():
print('from bar')
def wrapper(func):
func()
wrapper(bar)
# 3、可以当函数的返回值
# int示例
x = 1
def foo()
return x
res = foo()
print(res)
# 函数示例
def bar()
print('from bar')
def foo(func)
return func
f = foo(bar)
f()
# 4、可以当容器类型的元素
# int示例
z = 1
l = [z, ]
print(l)
# 函数示例
def get():
print('from get')
def put():
print('from put')
l1 = [get, put]
l1[0]{}
利用这一特性,可以优雅的取代原来的if多分支(elif这种多分支是我们写代码要尽可能避免的)。
def auth():
print('登录。。。。')
def register():
print('注册。。。。')
def check():
print('查看。。。。')
def transfer():
print('转账。。。。')
def pay():
print('支付。。。。')
fun_dict = {
'1':auth,
'2':register,
'3':check,
'4':transfer,
'5':pay}
def interactive():
while True:
print(
"""
1 登录
2 注册
3 查看
4 转账
5 支付
""")
choice = input('>>').strip()
if choice in fun_dict:
fun_dict[choice]()
else:
print('非法操作')
interactive()
闭包函数就是定义在函数内部的函数,也就是函数的嵌套定义。根据字面意思理解,闭包函数有两个关键字闭和包,分别是封闭和包裹。需要注意的重点是:闭包函数的作用域关系在函数定义阶段就固定死了,与调用位置无关。
def outer():
x = 1
def inner():
# 注意和nonlocal的区别
# nonlocal x
# x += 1
x = 2
print('from inner',x)
return inner # outer函数返回inner函数对象
f = outer() # 现在f是一个全局变量,同时是inner函数对象
print(f)
x = 3 # 这个x = 3并不能改变inner函数外层的x
f()
def foo():
x = 4 # 这个x = 4同样也不能改变
f() # 全局作用域在任意位置都可以调用
foo()
闭包函数可以用外层函数来调用内部的函数,打破了函数的层级限制,与此同时该函数包含对外部函数作用域中名字的引用。
def outer():
name = 'Albert'
def inner():
print('my name is %s' % name)
return inner
f = outer()
f()
(1)以参数的形式传入
import requests # requests模块就是模拟浏览器向目标站点发请求
def get(url)
response = requests.get(url) # get方法获取请求返回对象
print(response)
if response.status_code == 200: # 200是一个状态码,代表请求成功
print(response.text) # text方法是获取返回对象的内容
get('https://www.baidu.com')
(2)以闭包函数的形式
闭包函数就是在函数外再包裹一层作用域,由于这个作用域在外层函数内部,所以只作用在内层函数上。
def outer(url) # 给外层参数传参相当于 url='https://www.baidu.com'
def get():
response = request.get(url)
if response.status_code == 200:
print(response.text)
return get
baidu = outer('https://www.baidu.com')
python = outer('https://www.python.org')
baidu()
python()
使用闭包结构的最大特点是可以保持外部函数操作的状态,但是如果要想在内部函数中修改外部函数中定义的局部变量或者参数的内容,则必须使用nonlocal关键字。
def print_data(count):
def out(data):
nonlocal count
count += 1
print("count:{},\ndata:{}".format(count,data))
return out
oa = print_data(1)
oa("www.baidu")
器指的工具(只要是工具,就应该想到函数),装饰指的是为被装饰对象添加新功能。需要注意的是:项目一旦上线之后,就应该遵循开发封闭的原则。开放封闭指的是对修改函数内的源代码和调用方式是封闭的,对功能的扩展是开放的。
看起来有点矛盾,但这就是我们要做的。在这样的要求下,我们必须找到一种解决方案,能够在不修改一个功能源代码以及调用方式的前提下,为其添加新功能。这就用到了装饰器,它能够在不修改被装饰对象源代码与调用方式的前提下,为被装饰器对象添加新功能。
(1)无参装饰器实现过程
无参修饰器指的是装饰器本身没有参数
# 要求:为index函数添加一个统计时间的功能
import time # 这是一个与时间相关的模块
def index():
time.sleep(3) # 睡3秒
print('welcome to index page')
index()
# 版本一(只有index函数可以使用)
import time # 这是一个与时间相关的模块
def index():
time.sleep(3) # 睡3秒
print('welcome to index page')
start_time = time.time() # 从1970年开始计时的时间戳
index()
end_time = time.time()
print('run time is %s' % (end_time - start_time))
% 版本二(两个函数都可以使用,但是有大量重复代码)
def index():
time.sleep(3) # 睡3秒
print('welcome to index page')
def home(name):
time.sleep(5)
print('welcome %s to home page' % name)
start_time = time.time()
index()
stop_time = time.time()
print('run time is %s' % (end_time - start_time))
start_time = time.time()
home('Albert')
stop_time = time.time()
print('run time is %s' % (end_time - start_time))
# 版本三(修改了源函数的调用方式)
import time
def index():
time.sleep(3) # 睡3秒
print('welcome to index page')
def home(name):
time.sleep(5)
print('welcome %s to home page' % name)
def wrapper(func):
start_time = time.time()
func()
stop_time = time.time()
print('run time is %s' % (stop_time - start_time))
wrapper(index)
# 版本四(使用闭包函数,不修改源函数调用方式)
import time
def index():
time.sleep(3) # 睡3秒
print('welcome to index page')
def outer(func):
def wrapper():
start_time = time.time()
func()
stop_time = time.time()
print(stop_time - start_time)
return wrapper
index = outer(index) # 赋值给index覆盖原来的index,index = wrapper
index() # wrapper()
# 版本五(解决原函数返回值无效)
import time
def index():
time.sleep(1)
print('welcome to index page')
return 1 # 假设源函数有一个返回值
def outer(func):
def wrapper():
start_time = time.time()
res = func()
stop_time = time.time()
print(stop_time - start_time)
return res
return wrapper
index = outer(index)
res = index()
print(res)
# 版本六(终极版,解决有参函数和无参函数通用的问题)
import time
def index():
time.sleep(1)
print('welcome to index page')
return 1 # 假设源函数有一个返回值
def home(name):
time.sleep(5)
print('welcome %s to home page' % name)
def timer(func): # 装饰器也是一个函数,起一个好听的名字
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
stop_time = time.time()
print(stop_time - start_time)
return res
return wrapper
index = timer(index) # 新的index=wrapper
home = timer(home) # 新的home=wrapper
home(name='Albert') # wrapper(name='Albert')
home('Albert') # wrapper('Albert')
index() # wrapper()
# 无参装饰器模板
def outer(func):
def inner(*args, **kwargs):
"""
这里写装饰器逻辑
:param args:任意位置参数
:param kwargs:任意关键字参数
:return:一个函数对象
"""
res = func(*args, **kwargs)
return res
return inner
(2)装饰器语法糖
import time
# 装饰器也是一个函数,使用函数必须先定义,所以装饰器放在最上方
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
stop_time = time.time()
print(stop_time - start_time)
return res
@timer # 在被装饰对象正上方单独一行添加,相当于执行index=timer(index)
def index():
time.sleep(1):
print('welcome to index page')
return 1
(3)用户认证装饰器
import time
current_user = {'username': None}
def auth(func):
def wrapper(*args, **kwargs):
if current_user['username']:
print('已经登陆过了')
res = func(*args, **kwargs)
return res
name = input('用户名>>').strip()
pwd = input('密码>>').strip()
if name == 'Albert' and pwd == '1':
print('登录成功')
current_user['username'] = name
res = func(*args, **kwargs)
return res
else:
print('用户名或密码错误')
return wrapper
@auth
def index():
time.sleep(1)
print('welcome to index page')
@auth
def home(name):
time.sleep(2)
print('welcome %s to home page' % name)
index()
home('Albert')