一 名称空间(namespaces):存放名字的地方,是对栈区的划分。

有了名称空间之后,就可以在栈区中存放相同的名字,详细的名称空间。
分三种
1.1 内建名称空间
存放的名字:存放的python解释器内置的名字
print
<built-in function print>
存活周期:python解释器启动则产生,python解释器关闭则销毁。
1.2 全局名称空间
伴随python文件的开始执行/执行完毕而产生/回收,是第二个被加载的名称空间,文件执行过程中产生的名字都会存放于该名称空间中
存放的名字:只要不是函数内定义、也不是内置的,剩下的都是全局名称
存活周期:python文件执行则产生,python文件运行完毕后销毁
例:
def func():
x=2
y=2
import os
1.3 局部名称空间
存放的名字:在调用函数时,运行函数体代码过程中产生的函数内的名字(伴随函数的调用/结束而临时产生/回收,
函数的形参、函数内定义的名字都会被存放于该名称空间中)
存活周期:在调用函数时存活,函数调用完毕后则销毁
def foo(x):
y = 3 # 调用函数时,才会执行函数代码,名字x和y都存放于该函数的局部名称空间中
1.4 名称空间的加载顺序
内置名称空间>全局名称空>局部名称空间

1.5 销毁顺序
加载顺序相反

1.6 查找顺序(处在哪一层,就从哪一层往上找)
查找一个名字,必须从三个名称空间之一找到,查找顺序为:局部名称空间--->全局名称空间--->内置名称空间。
input = 111
def func():
input = 222
print(input) # 局部名称空间
func()
print(input) # 全局名称空间
如果局部名称空间和全局名称空间都未找到,就去内置空间找,打印结果为<built-in function input>
# 示范1
x = 111
def func():
print(x)
func() # x处于全局名称空间,局部空间找不到,就执行全局名称空间,跟x的位置没有关系
# 111
# 示范2:名称空间的“嵌套”关系是以函数定义阶段为准,与调用位置无关
x = 1
def func():
print(x)
def foo():
x = 22
func()
foo()
# 1
# 示范3:函数嵌套定义
input = 111
def fun1():
input = 222
def fun2():
input = 333
print(input)
fun2()
fun1() # 打印结果333
# 范例4:
x = 111
def func():
x = 222
print(x)
func()
print(x)
ps:名称查找,先定义中查找,再一层一层名称空间往上找。

二 作用域--->作用范围

2.1 全局作用域:内置名称空间、全局名称空间
(1)全局存活
(2)全局有效:被所有函数共享

局部作用域:局部名称空间的名字
(1)临时存活
(2)局部有效:函数内有效

2.2 作用域与名字查找的优先级
LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
locals 是函数内的名字空间,包括局部变量和形参
enclosing 外部嵌套函数的名字空间(闭包中常见)
globals 全局变量,函数定义所在模块的名字空间
builtins 内置模块的名字空间

三 global与nonlocal

# 范例1:
x = 111
def func():
x = 222
print(x)
func()
print(x)
# 222
# 111 # 范例2:如果在局部想要修改全局的名字对应的值(不可变类型),需要用global
x = 111
def func():
global x # 申明x这个名字是全局的名字,不要再造新的名字了
x = 222
print(x)
func()
print(x)
# 222
# 222
# 范例3:可变类型不用申明,直接加。
l = [111, 222]
def func():
l.append(333)
func()
print(l)
# [111, 222, 333]
# nonlocal(了解):修改函数外层函数包含的名字对应的值(不可变类型)
def f1():
x = 2
def f2():
nonlocal x
x = 3
f2() # 调用f2(),修改f1作用域中名字x的值
print(x) # 在f1作用域查看x
f1()
# 3

四 名称空间名字查找复习及总结

# 例1
x = 1
def func():
print(x)
def foo():
x = 22
func()
x = 333
foo()
# 333 # 例2
input = 111
def f1():
def f2():
input=333
print(input)
input=222
print('f1 out--->', input)
f2()
f1()
# f1 out---> 222
# 333 名称空间namespaces
名字---》栈区
名称空间是对栈的一种划分,真正存在的是栈区,名称空间只是一种虚拟的划分 内置名称空间
全局名称空间
局部名称空间 重点1:
名词查找:当前所在的位置向外查找
局部---》全局---》内置 重点2:
名称空间只有优先级之分,本身并无嵌套关系,画图只是为了理解 重点3:
名称空间的嵌套关系决定了名字的查找顺序
而名称空间的嵌套关系是以函数定义阶段为准的,
既函数的嵌套关系与名字的查找顺序是在定义阶段就已经确定好的 全局作用域:内置名称空间+全局名称空间
全局存活,全局有效 局部作用域:
临时存活,局部有效

五 函数对象

# 精髓:可以把函数当成变量去用
# func=内存地址
def func():
print('hello world')
# 1、可以赋值
# f = func()
print(func()) # 是return的返回值
# print(f, func) # f是return的返回值None,func就是内存地址 # 2、可以当做函数的参数传给另一个函数
def foo(x):
print(x)
foo(func) # foo(func的内存地址)
# <function func at 0x0000021B8BBD9280> # 3、可以当做函数另外一个函数的返回值
def foo(x):
return x
res = foo(func)
print(res)
res()
# <function func at 0x0000011EFFDD9280>
# hello world # 4、可以当做容器类型的一个元素
l = [func, ]
print(l)
l[0]()
# [<function func at 0x000001B666C49280>]
# hello world
# 例:ATM取款功能
def quit():
print('退出')
def enter():
print('登录')
def transfer():
print('转账')
def withdrwal():
print('取款')
def balance_inquriy():
print('查询余额')
choice_dic = {'1': enter,
'2': transfer,
'3': withdrwal,
'4': balance_inquriy}
while True:
print('''
0 退出
1 登录
2 转账
3 取款
4 查询余额''')
choice = input('请选择:').strip()
if not choice.isdigit():
print('必须输入数字,ox:')
continue
if choice == '0':
break
if choice in choice_dic:
choice_dic[choice]()
else:
print('请选择正确的选项')

六 函数嵌套

# 函数嵌套
# 1、函数的嵌套调用:在调用一个函数的过程中又调用其他函数
# 求最大数:
def max(x, y):
if x > y:
return x
else:
return y
def max1(a, b, c, d):
res1 = max(a, b)
res2 = max(res1, c)
res3 = max(res2, d)
return res3
res = max1(1, 2, 5, 4)
print(res) # 2、函数的嵌套定义:在函数内定义其他函数
def f1():
def f2():
pass

六 闭包函数

1、大前提:
闭包函数=名称空间与作用域+函数嵌套+函数对象
核心点:名字的查找关系是以函数定义阶段为准

2、什么是闭包函数
“闭”函数指的该函数内嵌函数
“包”函数指的该函数包含对外层函数作用域名字的引用(不是全局作用域)
# 闭包函数:名称空间与作用域的应用+函数嵌套
def f1():
x=111
def f2():
print(x)
f2()
x=222
def foo():
x=333
f1()
foo()
# 111 # 闭包函数:函数对象,函数作为return的返回值
def f1():
x = 111
def f2():
print(x)
return f2 # 返回f2的内存地址
f = f1() # f2的内存地址,<function f1.<locals>.f2 at 0x000001BFAC6071F0>
print(f)
f() # f2函数的调用,把f2内嵌函数当成了全局作用域使用
# <function f1.<locals>.f2 at 0x000001A390AB24C0>
# 111
3、为何要有闭包函数--->闭包函数的应用
两种为函数体传参的方式
# 方式一:直接把函数体需要的参数定义成形参
def f(x):
print(x)
f(1)
# 方式二:函数对象方式进行传参
def f1():
x = 1
def f2():
print(x)
return f2
f = f1()
f()
# 1 # 改进
def f1(x):
# x=1
def f2():
print(x)
return f2
f = f1(1)
f() # 改进2
def f1(x):
# x=1
def f2(y, m):
print(f2) # <function f1.<locals>.f2 at 0x000001BBEAD571F0>
print(x)
print(y, m)
return f2
f = f1(1)
f(2, 3)
print(f) # <function f1.<locals>.f2 at 0x000001BBEAD571F0>,f和f2的内存地址是一样的,f的调用,就是f2的调用

七 装饰器

1、知识储备
*args,**kwargs
名称空间与作用域
函数对象
函数的嵌套定义
闭包函数

2、装饰器
1)、什么是装饰器
“器”指的是工具,可以定义成函数
“装饰”指的是为其他事物添加额外的东西点缀
装饰器:指的是定义一个函数,该函数是用来为其他函数添加额外的功能
2)、为何要用装饰器
开放封闭原则
开放:指的是对拓展功能是开放的
封闭:指的是对修改源代码是封闭的
装饰器就是在不修改装饰器对象源代码以及调用方式的前提下为被装饰对象添加新功能
3、如何用装饰器
需求:在不修改index函数的源代码以及调用方式的前提下为其添加统计运行时间的功能
# 方案一:在原代码基础上修改
import time
def index(x, y):
start = time.time()
time.sleep(1)
print('hello world:{},{}.'.format(x, y))
stop = time.time()
index('xiaobao', 'lq') # 方案二:没有修改被装饰对象的调用方式,也没有修改其源代码,并且加上了新功能,但是代码冗余
import time
def index(x, y):
time.sleep(1)
print('hello world:{},{}.'.format(x, y))
start = time.time()
index('xiaobao', 'lq')
stop = time.time()
print(stop - start) # 方案三:解决了方案二代码冗余问题,但带来一个新问题既函数的调用方式改变
import time
def index(x,y):
time.sleep(1)
print('hello world:{},{}.'.format(x,y))
def wrapper():
start = time.time()
index('xiaobao', 'lq')
stop = time.time()
print(stop - start)
wrapper()
# 方案三优化一:如何在方案三的基础上不改变函数的调用方式(方案三的优化一,将index的参数写活了)
import time
def index(x, y):
time.sleep(1)
print('hello world:{},{}.'.format(x, y))
def wrapper(*args, **kwargs):
start = time.time()
index(*args, **kwargs)
stop = time.time()
print(stop - start)
wrapper('xiabao', 'lq') # 方案三优化二:在优化一的基础上把被装饰对象写活了,原来只能装饰index
import time
def index(x, y):
time.sleep(1)
print('hello world:{},{}.'.format(x, y))
print(index)
def outer(func): # func=index(闭包函数)
def wrapper(*args, **kwargs):
start = time.time()
func(*args, **kwargs) # func就是闭包函数中例子中的x的查找
stop = time.time()
print(stop - start)
return wrapper
index = outer(index) # 这里的index实际就是wrapper的内存地址
index('xiaobao', 'lq')
print(index) # 方案三优化(被装饰函数有return的情况):最终优化完成。
import time
def home(m, n):
time.sleep(1)
print('welcome to home:{}和{}'.format(m, n))
return 'thanks'
res1 = home('xiaobao', 'zd')
print('未被装饰的返回值--->', res1)
def outer(func):
def wrapper(*args, **kwargs):
start = time.time()
func(*args, **kwargs)
stop = time.time()
print(stop - start)
return wrapper
home = outer(home)
res2 = home('xiaobao', 'zd')
print('装饰后的返回值--->', res2)
# welcome to home:xiaobao和zd
# 未被装饰的返回值---> thanks
# welcome to home:xiaobao和zd
# 1.0016324520111084
# 装饰后的返回值---> None
# 装饰器
def outer(func):
def wrapper(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
stop = time.time()
print(stop - start)
return res
return wrapper
# 在被装饰器对象正上方的单独一行写@装饰器名字
# index函数
@outer # index=outer(index)
def index(x, y):
time.sleep(1)
print('hello world:{},{}.'.format(x, y))
# home函数
@outer # home=outer(home)
def home(m, n):
time.sleep(1)
print('welcome to home:{}和{}'.format(m, n))
return 'thanks'
index('xiaobo', 'lq')
res3 = home('xiaobao', 'zd')
print(res3)

# hello world:xiaobo,lq.
# 1.0000083446502686
# welcome to home:xiaobao和zd
# 1.0008976459503174
# thanks

# 延伸:多个装饰器,加载顺序与运行顺序
@deco1 # index=deco1(deco2.wrapper的内存地址)
@deco2 # deco2.wrpper的内存地址=deco2(deco3.wrpper的内存地址)
@deco3 # deco3.wrpper的内存地址=deco3(index)
def index():
pass
# 总结无参装饰器模板
def outer(func):
def wrapper(*args, **kwargs):
# 1、调用原函数
# 2、为其增加新功能
res = func(*args, **kwargs)
return res
return wrapper

# 实现注册的装饰功能
def auther(func):
def wrapper(*args, **kwargs):
inp_name = input('请输入你的名字: ').strip()
inp_pwd = input('请输入你的密码: ').strip()
with open(r'user.txt', mode='r', encoding='utf-8') as f:
for line in f: # 生成的line是字符串(含了.read的功能),先.strip去除字符串前后的\n,再.split以':'为界切分成列表。
# print(line,end='') #liuqiao:123\n
print(line.strip('\n').split(':'))
u, p = line.strip('\n').split(':')
# 把用户输入的名字与密码与读出内容做比对
if inp_name == u and inp_pwd == p:
print('登录成功')
res = func(*args, **kwargs)
print(u, p)
return res
else:
print('账号名或者密码错误')
return wrapper
@auther
def index():
print('开始程序接下来的工作---》')
index()
# 请输入你的名字: xiaobao
# 请输入你的密码: 123
# 登录成功
# 开始程序接下来的工作---》
# xiaobao 123

八 装饰器补充(wrapper被装饰)

# 偷梁换柱,既将原函数名指向的内存地址偷梁换柱成wrapper函数,所以应该将wrapper做的跟原函数一样才行
def outter(func):
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
return res
wrapper.__name__ = func.__name__ # 手动添加将原函数的属性赋值给wrapper函数,这里wrapper成了被装饰对象。
wrapper.__doc__ = func.__doc__
return wrapper
@outter # index=outter(index)
def index(x, y):
''''这个是主页功能'''
print(x, y)
index(1, 2) # wrapper(1,2)
print(index.__name__)
print(index.__doc__) # 优化二
from functools import wraps
def outter(func):
@wraps(func) # 自动将原函数的属性赋值给wrapper函数,这里wrapper成了被装饰对象。
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
return res
# wrapper.__name__= func.__name__
# wrapper.__doc__= func.__doc__
return wrapper
@outter # index=outter(index)
def index(x, y):
''''这个是主页功能'''
print(x, y)
index(1, 2) # wrapper(1,2)
print(index.__name__)
print(index.__doc__)
print(index.__code__)

九 有参装饰器

1、知识储备:
from functools import wraps
def outter(func):
@wraps(func)
def wrappper(*args, **kwargs):
print('好累')
res = func(*args, **kwargs)
return res
return wrappper
# 由于语法糖@的限制,outter函数只能有一个参数,并且该函数只用来接受被装饰对象的内存地址
@outter # index=outter(index)
def index(x, y):
print(x, y)
index(1, 2)
偷梁换柱之后
index的参数什么样子,wrapper的参数就应该什么样子
index的返回值是什么样子,wrapper的返回值就应该什么样子
index的属性什么样子,wrapper的属性就应该什么样子(@wraps的使用)

2、有参装饰器应用
注册功能的装饰器,用户名和密码来之三种存储(file,sql,ldp)
from functools import wraps
def auther(db):
def deco(func):
@wraps(func)
def wrapper(*args, **kwargs):
user = input('输入名字:').strip()
pwd = input('请输入密码:').strip()
if user == "xiaobao" and pwd == "123":
if db == "file":
print('账户来之文件')
res = func(*args, **kwargs)
return res
elif db == "sql":
print('账户来之数据库')
res = func(*args, **kwargs)
return res
elif db == "lap":
print('账户来之lap')
res = func(*args, **kwargs)
return res
else:
print("不支持该db类型")
else:
print("账号或密码错误")
return wrapper
return deco @auther(db='file') # myfile=deco(myfile)-->@deco--->deco=auth(db='file')--->@auth(db='file')
def myfile(x, y):
print(x, y)
@auther(db='sql')
def mysql(x, y):
print(x, y)
@auther(db='lap')
def mylap(x, y):
print(x, y)
# myfile(1, 2)
mysql(3, 4)
# 输入名字:xiaobao
# 请输入密码:123
# 账户来之数据库
# 3 4
# 总结:有参装饰器模板
def auth(x, y, z):
def deco(func):
def wrapper(*args, **kwargs):
# 这些地方就是要加的x,y,z参数的地方(也是加功能)
print(x+y+z)
res = func(*args, **kwargs)
# 这些地方就是要加的x,y,z参数的地方(也是加功能)
return res
return wrapper
return deco @auth(x=1, y=2, z=3)
def index():
pass
index()
# 6

十 叠加多个装饰器

叠加多个装饰器的加载、运行分析
# index=deco3(deco2(deco1(index)))
# @deco1 # index=deco1(deco2.wrapper的内存地址)
# @deco2 # deco2.wrpper的内存地址=deco2(deco3.wrpper的内存地址)
# @deco3 # deco3.wrpper的内存地址=deco3(index)
# def index():
# pass def deco1(func1):
def wrapper1(*args,**kwargs): # func1就是wrapper2的内存地址
print('deco1.wrapper1运行')
res1=func1(*args,**kwargs)
print('加载顺序deco1')
return res1
return wrapper1 def deco2(func2):
def wrapper2(*args,**kwargs): # func2就是wrapper3的内存地址
print('deco2.wrapper2运行')
res2=func2(*args,**kwargs)
print('加载顺序deco2')
return res2
return wrapper2 def deco3(x):
def outter(func3):
def wrapper3(*args,**kwargs): # func3就是被装饰对象index函数的内存地址
print('deco3.wrapper3运行',x)
res3=func3(*args,**kwargs)
print('加载顺序deco3')
return res3
return wrapper3
return outter # 加载顺序自下而上
@deco1 # -->index=wrapper1(wrapper2的内存地址)------------>index=wrapper1的内存地址
@deco2 # -->index=wrapper2(wrapper3的内存地址)------------>index=wrapper2的内存地址
@deco3('xiaobao') # -->@outter3-->index=outter3(index)---->index=wrapper3的内存地址
def index(x,y):
print(x,y) # print(index) # <function deco1.<locals>.wrapper1 at 0x00000141D60F7790> # 执行顺序自上而下,既wrapper1-->wrapper2-->wrapper3-->index函数体-->return res3-->return res2-->return1 res1
#
index('zd','lq')
'''
函数调用结果
deco1.wrapper1运行
deco1.wrapper2运行
deco3.wrapper3运行 xiaobao
zd lq
加载顺序deco3
加载顺序deco2
加载顺序deco1
'''

python基础七(函数名称空间及作用域、函数对象、函数嵌套、闭包函数、装饰器)的更多相关文章

  1. python基础语法6 名称空间与作用域

    目录: 1.函数对象 2.函数嵌套 3.名称空间 4.作用域 函数是第一类对象 1.函数名是可以被引用: def index(): print('from index') a = index a() ...

  2. python之函数名称空间,作用域,嵌套函数

    目录 嵌套函数 定义 名称空间的三大类(只存变量名) 名称空间加载顺序 变量名的查找顺序为 作用域 嵌套函数 定义 函数内部定义的函数,无法在函数外部使用内部定义的函数. def f1(): def ...

  3. python函数名称空间与作用域、闭包

    一.命名空间概念 1.命名空间(name space) 名称空间是存放名字的地方. 若变量x=1,1存放在内存中,命名空间是存放名字x.x与1绑定关系的地方. 2.名称空间加载顺序 python te ...

  4. python函数----名称空间和作用域

    一 名称空间 名称空间即存放名字与对象映射/绑定关系的地方. 对于x=3,Python会申请内存空间存放对象3,然后将名字x与3的绑定关系存放于名称空间中,del x表示清除该绑定关系. ​在程序执行 ...

  5. python基础之函数名称空间与作用域

  6. Python编程四大神兽:迭代器、生成器、闭包和装饰器

    生成器 生成器是生成一个值的特殊函数,它具有这样一个特点:第一次执行该函数时,先从头按顺序执行,在碰到yield关键字时该函数会暂停执行该函数后续的代码,并且返回一个值:在下一次调用该函数执行时,程序 ...

  7. Python核心编程的四大神兽:迭代器、生成器、闭包以及装饰器

      生成器 生成器是生成一个值的特殊函数,它具有这样的特点:第一次执行该函数时,先从头按顺序执行,在碰到yield关键字时该函数会暂停执行该函数后续的代码,并且返回一个值:在下一次调用该函数执行时,程 ...

  8. python基础知识13---函数对象、函数嵌套、名称空间与作用域、装饰器

    阅读目录 一 函数对象 二 函数嵌套 三 名称空间与作用域 四 闭包函数 五 装饰器 六 练习题 一 函数对象 1 函数是第一类对象,即函数可以当作数据传递 #1 可以被引用 #2 可以当作参数传递 ...

  9. python基础之函数对象,嵌套,名称空间和作用域

    函数对象: 函数是第一类对象的含义是函数可以被当作数据处理 函数可用于: def func(): print(‘func’) 1.引用  f = func  把内存地址赋值给f 2.当作参数传给一个函 ...

  10. python之函数对象、函数嵌套、名称空间与作用域、装饰器

    一 函数对象 一 函数是第一类对象,即函数可以当作数据传递 #1 可以被引用 #2 可以当作参数传递 #3 返回值可以是函数 #3 可以当作容器类型的元素 二 利用该特性,优雅的取代多分支的if de ...

随机推荐

  1. 鹏程杯子2023 pwn

    主要就是修改stdin的最后几位,使他变为write,然后泄露libc,为所欲为即可. 本人是卡在不知道stdin那里可以修改. 然后使用一下jmp qword rbp这个gadget 0x400a9 ...

  2. java generic 介绍

    一 介绍: 在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的"任意化","任意化"带来的缺点是要做显式的强制类型转换, ...

  3. error C2039: "function": 不是 "std" 的成员的解决方法

    这个错误通过某度没找到合适的解决方案,故记录下来 其实如果使用 google 搜索错误的英文关键词,大概第一条就是解决问题的链接 Large number of "'function' is ...

  4. C++的strcat实现

    #include <iostream> #pragma warning(disable:4996); using namespace std; char* t = (char*)mallo ...

  5. golang常用库包:redis操作库go-redis使用(03)-高级数据结构和其它特性

    Redis 高级数据结构操作和其它特性 第一篇:go-redis使用,介绍Redis基本数据结构和其他特性,以及 go-redis 连接到Redis https://www.cnblogs.com/j ...

  6. 2021-10-11 vue的第三方组件二次封装

    原理 v-bind="$attrs"继承所有属性和props. v-on="$listeners"继承所有的方法. <template> <d ...

  7. 【libGDX】加载G3DJ模型

    1 前言 ​ libGDX 提供了自己的 3D 格式模型文件,称为 G3D,包含 g3dj(Json 格式)和 g3db(Binary 格式)文件,官方介绍见 → importing-blender- ...

  8. flutter打包android的一些配置修改(解决白屏,视频闪退)

    1.打包后视频播放闪退 视频播放器选择了flutter_tencentplayer(https://github.com/qq326646683/flutter_tencentplayer) 解决:不 ...

  9. pycharm中如何改变主题

    这边分享一个我自己在用的主题,蛮简约的,关键字高亮显示.再也不用全都是一样的颜色了.网盘地址在最后哈 好了话不多说,教大家如何把主题设置到pycharm中 图1:首先把主题jar包下载下来,然后打开p ...

  10. 【Docker】使用 Docker 部署 .Net Core 项目 (四)

    系列目录: [Docker] CentOS7 安装 Docker 及其使用方法 ( 一 ) [Docker] 使用Docker 在阿里云 Centos7 部署 MySQL 和 Redis (二) [D ...