60_函数的作用域(全局变量和局部变量)

60.函数的作用域(全局变量和局部变量)

变量起作用的范围称为变量的作用域,不同作用域内同名变量之间互不影响。

变量分为:全局变量局部变量

没有必要情况一般使用局部变量性能高

全局变量:

  1. 函数和类定义之外声明的变量。作用域为定义的模块,从定义位置开始直到模块 结束。
  2. 全局变量降低了函数的通用性可读性。应尽量避免全局变量的使用。
  3. 全局变量一般做常量使用
  4. 函数内改变全局变量的值,使用global声明一下

局部变量:

  1. 函数体中(包含形式参数)声明的变量。
  2. 局部变量的引用比全局变量优先考虑使用
  3. 如果局部变量和全局变量同名,则在函数内隐藏全局变量,只使用同名局部变量

【操作】全局变量的作用域测试

a = 100 #全局变量 
def f1():
    global a #如果要在函数内改变全局变量的值,增加 global关键字声明 
    # 如果不加这一句的话 下面  print(a) 将会报错。
    # UnboundLocalError: local variable 'a' referenced before assignment
    print(a) #打印全局变量a 的值
    a = 300
    # 就算放 print(a) 到这里
    # 打印的 是 300  
    # 但是 你在 函数外面 访问 a 的时候  依然 还是 100
f1() 
print(a) # 这一句是在 外面 打印 a  但是 却是 300 说明修改成功

执行结果:

100 
300 

【操作】全局变量和局部变量同名测试

a=100 
def f1(): 
    a = 3 # 同名的局部变量 
    print(a)
    
f1() 
print(a) # a 仍然是100,没有变化

执行结果:

3 
100

【操作】 输出局部变量和全局变量

a = 100
def f1(a,b,c):
    print("a b c : ",a,b,c) 
    print("局部 : ",locals()) #打印输出的局部变量 
    print("全局 : ",globals()) #打印输出的全局变量
    
f1(2,3,4)


# 运行效果

In [1]: a = 100
   ...: def f1(a,b,c):
   ...:     print("a b c : ",a,b,c)
   ...:     print("局部 : ",locals()) #打印输出的局部变量
   ...:     print("全局 : ",globals()) #打印输出的全局变量
   ...:
   ...: f1(2,3,4)
a b c :  2 3 4
局部 :  {'c': 4, 'b': 3, 'a': 2}
全局 :  {'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': <module 'builtins' (built-in)>, '__builtins__': <module 'builtins' (built-in)>, '_ih': ['', 'a = 100\ndef f1(a,b,c):\n    print("a b c : ",a,b,c) \n    print("局部 : ",locals()) #打印输出的局部变量 \n    print("全局 : ",globals()) #打印输出的全局变量\n    \nf1(2,3,4)'], '_oh': {}, '_dh': ['D:\\'], 'In': ['', 'a = 100\ndef f1(a,b,c):\n    print("a b c : ",a,b,c) \n    print("局部 : ",locals()) #打印输出的局部变量 \n    print("全局 : ",globals()) #打印输出的全局变量\n    \nf1(2,3,4)'], 'Out': {}, 'get_ipython': <bound method InteractiveShell.get_ipython of <IPython.terminal.interactiveshell.TerminalInteractiveShell object at 0x04C01510>>, 'exit': <IPython.core.autocall.ExitAutocall object at 0x04C01C50>, 'quit': <IPython.core.autocall.ExitAutocall object at 0x04C01C50>, '_': '', '__': '', '___': '', '_i': '', '_ii': '', '_iii': '', '_i1': 'a = 100\ndef f1(a,b,c):\n    print("a b c : ",a,b,c) \n    print("局部 : ",locals()) #打印输出的局部变量 \n    print("全局 : ",globals()) #打印输出的全局 变量\n    \nf1(2,3,4)', 'a': 100, 'f1': <function f1 at 0x042142B8>}

代码说明


a = 3  # 这就是一个全局变量


def test04():
    b = 4       # 局部变量
    print(b * 10)

    # global a  # 如果要在函数内改变全局变量的值,增加 global关键字,声明
    a = 300
    print(a)


test04()
print(a)
# 每次调用函数的时候,python会调用 一个 栈帧   strake frame
# 用完就丢掉了  b在 strake frame  栈帧里面

局部变量和全局变量效率测试

局部变量的查询和访问速度比全局变量快,优先考虑使用,尤其是在循环的时候。 在特别强调效率的地方或者循环次数较多的地方,可以通过将全局变量转为局部变量提高运 行速度。

代码如下:

import math
from timeit import timeit
# 代码段 1 全局变量
test_global_code="""
def test05():
	for k in range(10000000):
		math.sqrt(30)
"""
# 代码段 2 局部变量 math 赋给 b 
test_local_code="""
def test06():
	b=math.sqrt
	for k in range(10000000):
		b(3)
"""
# 用 timeit 来调用 number 是执行次数  
# 乘以 1000 是因为 换算为 毫秒 ms 数值看起来大一点。
timeit(test_global_code,number=10)*1000 # 全局  timeit 返回的是一个 浮点数
timeit(test_local_code,number=10)*1000 # 局部



In [4]: test_global_code="""
   ...: def test05():
   ...:     for k in range(10000000):
   ...:         math.sqrt(30)
   ...: """

In [5]: test_local_code="""
   ...: def test06():
   ...:     b=math.sqrt
   ...:     for k in range(10000000):
   ...:         b(3)
   ...: """
   
In [23]: timeit(test_local_code,number=1000000)*1000 # 局部
Out[23]: 66.5988000000084

In [24]: timeit(test_global_code,number=1000000)*1000 # 全局。 
Out[24]: 67.5967999999898
# 大家不要看  这里 只是提升了 一毫秒
# 因为 math 导入进来之后本来就挺快的
# 因为如果是你自己写的 变量。 那速度提升就很可观了。

关于一个生成默认参数的函数

def test():
    for i in range(3):
        def a():
            f=i
            # 这里的i 本来是无法保存的
            return f
        arr.append(partial(a,i)) # 用这个偏函数保存到 默认参数中去了。
        # 因为函数 a 没有 调用 所以 无法开辟空间  也就无法 维护 每一个 i 的值。记录i 的值。

在这里插入图片描述

看一个js 的例子

js es6 是有 let 这样的声明关键字的。 然后他声明的 是块级作用域 。

下面例子 i 只能在 {} 中生效,每循环一次 就会 开辟一块 空间 。 这个内存空间 就是作用域。

和我们python 中 函数的局部作用 差不多。 每次调用函数 都有临时 开辟一块 空间。 之后再 垃圾回收。

let arr=[]
for(let i=0;i<3;i++){
    arr.push(function(){
        return i
    })
}


在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值