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

在python中,函数是第一类对象,函数是第一等公民

本质上函数可以当变量用
def func():                # func=函数的内存地址
    print("from func")

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

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

foo(func)

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

res = foo(func)		# func当成参数传入foo(func),返回值是func重新赋值给res
print(res)			# res = func的函数内存地址

4.可以当作容器类型的元素
l = [func]
l[0]()             # 把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)  # 10 (一个变量放进函数里面只能在函数里面使用)
    print(f1)  # 函数f1的内存地址
    print(f2)  # <function f1.<locals>.f2 at 0x00E18388> 函数f1内部函数2的内存地址

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		# m,n都是局部名称空间的名字
    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)	# 111

def f2():
    x = 222
    
    f1()
f2()      
# 定义阶段全局变量x=111,在函数f2内部调用f1的函数,f1找x的时候,函数内部没有x,会找到全局x=111,找不到就报错,不会找到f2的函数内部

案例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  # nonlocal表示函数名是来自外层函数的,不是全局。加了nonlocal打印结果为333
        x = 333

    f2()
    print(x)  # x=222与x=333同时在函数内部的时候,调用f1函数运行f2代码,直接打印f1定义的变量值x=222
f1()
nonlocal会把外层的f1的x=222改成内层的x=333,如果说第一个外层没有找到局部名会一直往外层找,找到全局层之前还找不到会直接报错

闭包函数

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

def outter():
    x = 111

    def wrapper():
        print(x)

    return wrapper


f = outter()  # f = wrapper = outter()
#f()  f()= wrapper() = outter()()
print(f)  # 函数名wrapper的内存地址

def foo():
    x = 222
    f()	  # 等同于wrapper(),wrapper内部没有定义,去函数outter内部找,如果找不到就去全局找,找不到就报错。不会在函数foo里面找

foo()

为函数体代码传参的方案

方案1:直接用参数传
def wrapper(x):
    print(x)

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


方案2:闭包函数传参
def outter(x):
    # x=111	     如果outter定义了变量x=111,那么打印结果为111,函数的名称空间查找顺序,先查找内部,没有查外层函数,最后查全局
    def wrapper():
        print(x)
    return wrapper
    
f1 = outter(111)	# f1 = wrapper
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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值