Python函数小结

第四章 函数总结

1、函数返回值return总结:

  • Python函数使用return语句返回 ” 返回值 “,函数不能同时返回多个值,有且仅有一个值返回;
  • 所有函数都有返回值,如果没有return语句,隐式调用return None;
  • return 语句并不一定是函数的语句块的最后一条语句,但如果return语句调用后return语句后的所有部分将不再执行;
  • 函数可以存在多个return语句,但是只有一条可以执行。如果没有return则隐式调用return None;
  • 如果有必要,可以显示调用return None,可以简写为 return;
  • 如果函数执行了return语句,函数就会返回,当前被执行的return语句之后的其他语句就不会被执行了;
  • return作用:结束函数调用、返回值;

 

2、(函数)作用域:一个标识符的可见范围,这就是标识符的作用域。一般常说的是变量的作用域;

  1. 全局作用域:在整个程序运行环境中都可见;
  2. 局部作用域:(1)在函数、类等内部可见;

(2)局部变量使用范围不能超过其所在的局部作用域;

 

  • 外层变量作用域在内层作用域可见;(但是内层作用域中将外层变量赋值就不可以,因为赋值及重新定义,也就是在内层作用域中重新定义了一个变量。跟外层循环没关系。)
  • 内层作用域中,如果重新定义(赋值及重新定义)了外层中的变量标识符,相当于当前作用域中重新定义了一个新的变量、而且并没有覆盖外层作用域中的变量;
eg:

x = 5

def foo():

    x += 1

foo()

将会报UnboundLocalError

  • x = 5是一个全局变量,函数中 x += 1 其实是 x = x + 1
  • 相当于在foo函数内部定义一个局部变量 x ,那么foo内部所有x都是这个局部变量x了;
  • 此时这个 x 还没有完成赋值,就被右边拿来做加1操作了;

 

3、作用域关键字

  1. 全局变量 global;

(1)使用 global 关键字的变量,将foo内的 x变量 声明为外部的全局作用域中定义的 x;

(2)全局作用域中必须有 x 的定义,否则就需要在函数内自己赋值定义变量(注意该变量有关键字global);

(3)但是如果全局作用域中没有变量 x 的话,在函数内部赋值及定义,在内部作用域为一个外部作用域的变量 x 赋值,不是在内部作用域定义个新变量,所以 x += 1不会报错。注意:这里的 x 的作用域还是全局的;

 

global总结:

  • x += 1 这种是特殊形式产生的错误的原因?

答:先引用后赋值,而Python动态语言是赋值才算定义,才能被引用。解决办法,在这条语句前增加 x = 0 之类的赋值语句,或者使用 global 告诉内部作用域,去全局作用域查找变量定义;

  • 内部作用域使用 x = 5 之类的赋值语句会重新定义局部作用域使用的变量 x ,但是,一旦这个作用域中使用global声明x为全局的,那么x = 5 相当于在为全局作用域的变量x赋值;

 

  1. global 使用原则
  • 外部作用域变量会被内部作用域可见,但也不要在这个内部的局部作用域中直接使用,因为函数的目的就是为了封装,尽量与外界隔离;
  • 如果函数需要使用外部全局变量,请使用函数的形参传参解决;
  • 一句话:不用global。

 

2. nonlocal 关键字

  1. 使用了nonlocal关键字,表示该局部变量中的变量使用的是上级作用域中的变量;注意该上级不能是外部的全局变量;

 

3、默认值的作用域

  • 因为函数也是对象,python把函数的默认值放在了属性中,这个属性就伴随着这个函数对象的整个生命周期;
  • 查看 函数名 . __defaults__ 属性;
  • 函数的默认值是使用元组来保存的;
  • 属性 __defaults__ 中使用元组保存所有位置参数默认值;
  • 属性 __kwdefaults__ 中使用字典保存所有keyword—only参数的默认值;

 

注意:使用可变类型作为默认值,就可能修改这个默认值;

 

默认值的修改

  1. 使用影子拷贝创建一个新的对象,永远不能改变传入的参数;
  2. 【1】通过值得判断就可以灵活得选择创建或者修改传入对象;

【2】这种方式灵活,应用广泛;

【3】很多函数得定义,都可以看到使用None这个不可变得值作为默认参数,可以说这是一种惯用法;

 

4、闭包

  • 自由变量:未在本地作用域中定义的变量。例如定义在函数外的外层函数的作用域中的变量;(在A作用域中使用的变量x,却没有在A作用域中声明(即在其他作用域中声明的),对于A作用域来说,x就是一个自由变量。)
  • 闭包:指的是内层函数引用到了外层函数的自由变量,就形成了闭包。

注意:如果变量使用的是global关键字,但这是使用的是全局变量,而不是闭包;如果要对普通变量的闭包,可以使用nonlocal;

 

5、函数的销毁

【1】全局函数的销毁

  • 重新定义同名函数
  • del 语句删除函数名变量
  • 程序结束

【2】局部变量的销毁

  • 重新在上级作用域定义同名函数
  • del 语句删除函数名称,函数对象的引用计数减一
  • 上级作用域销毁时

 

6、函数执行流程(压栈过程):可以解释函数局部变量在函数调用是创建,在调用结束消亡;

【1】全局内存中生成 foo1 、foo2 、foo3 、main函数对象;

【2】main函数调用压栈;

【3】main 中查找内建函数 print 压栈,将常量字符串压栈,调用函数,弹出栈顶;(函数弹出的是返回值,此时栈底只有main 函数);

【4】main 中全局查找函数 foo1 压栈,将常量 100、101压栈,调用函数 foo1 ,创建栈帧。print 函数压栈,字符串和变量 b、b1 压栈,调用函数,弹出栈顶,返回值,foo1 函数结束调用弹出栈顶;

【5】main 中全局查找 foo2 压栈,将常量 200 压栈,调用 foo2 ,创建栈帧。

【6】foo3 函数压栈,变量 c 引用压栈,

【7】调用 foo3 ,创建栈帧。foo3 完成 print 函数调用后返回,弹出栈顶;

【8】foo2 恢复调用,执行 print 后,返回值。main 中 foo2 调用结束后弹出栈顶;

【9】继续执行 main 中的 print 函数调用,弹出栈顶。main 函数返回结束调用,弹出栈顶;

 

 

def foo1(b,b1=3):
    print("foo1 called",b,b1)

def foo2(c):
    foo3(c)
    print("foo2 called",c)

def foo3(d):
    print("foo3 called",d)

def main():
    print("main called")
    foo1(100,101)
    foo2(200)
    print("main ending")

main()

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值