函数返回值和作用域
函数的返回值
- python函数使用return语句返回“返回值”
- 所有函数都有返回值,如果没有return语句,隐式调用return none
- return语句并不一定式函数的语句块最后一条语句
- 一个函数可以存在多个return语句,但是只有一条被执行,如果没有一条return被执行,则调用return none
- 如果有必要,可以显示调用return none 可以简写为return
- 如果函数执行了return语句,函数就会返回,当前被执行的return语句之后的其他语句就不会被执行
示例1:
def add(x): print(x) return x+1 print(x) print(add(5))
如果函数执行了return语句,函数就会返回,当前被执行的return语句之后的其他语句就不会被执行,输出为:
5 6
示例2:
def guess(x): if x > 5: return '>5' else: return '<=5' print(guess(6))
一个函数可以存在多个return语句,但是只有一条被执行,输出如下:
>5
返回多个值
- 函数不能同时返回多个值
- return[1,2,3]是返回一个列表,是一个列表对象
- return 1,2,3看似返回多个值,被python封装成一个元祖
示例3:
def showlist(): return [1,2,3] def showlist2(): return 1,2,3 print(showlist()) x,y,z = showlist() print(x,y,z) print(showlist2()) a,b,c = showlist2() print(a,b,c)
可以使用解构提取值,输出为:
[1, 2, 3] 1 2 3 (1, 2, 3) 1 2 3
函数嵌套
- 在一个函数中定义了另一个函数
- 函数有可见范围,这就是作用域概念
- 内部函数不能再外部直接用,会抛异常
示例:
def outer(): def inner(): print('inner') print('outer') inner() outer()
作用域
- 一个标识符的可见返回,这就是标识符的作用域,一般常说变量的作用域
- 全局作用域,在整个程序环境中都可见
- 局部作用域,在函数,类等内部可见,局部变量使用范围不能超过其所在的局部作用域
示例:
x = 1 def foo(): x += 1 print(x) foo()
输出报错,因为在函数内x += 1时,变量x赋值即从新定义,但x未在函数内定义,报错
Traceback (most recent call last): File "E:/PycharmProjects/untitled/test/a.py", line 13, in <module> foo() File "E:/PycharmProjects/untitled/test/a.py", line 10, in foo x += 1 UnboundLocalError: local variable 'x' referenced before assignment
示例:
def outer(): x = 50 def inner(): x = 30 print('inner{}'.format(x)) print('outer{}'.format(x)) inner() outer()
输出为:
outer50
inner30
外层变量作用域在内层可见,如果内层定义外层同名变量,相当于从新定义了一个,但是内层的不会覆盖外层
全局变量global
- 使用global关键字的变量,将foo内部的x 声明为使用外部的全局作用域中定义x
- 全局作用域中必须有x的定义
- 外部作用域变量会内部作用域可见,但也不要在内部的局部作用域使用,因为函数的目的就是为了封装,尽量与外界隔离
- 如果函数需要使用外部全局变量,请使用函数的形参传参
- 不要使用global,学习他是为了深入理解变量作用域
示例:
x = 5 def foo(): global x x = 10 x += 1 print(x) foo()
输出为
11
使用global关键字的变量,将foo内的x声明为使用外部的x
但x=10赋值即定义,在内部作用域为一个外部作用域的变量x赋值,不是在内部作用域定义个新变量x,x的作用域为全局
闭包
自由变量:未在本地作用域中定义的变量,例如定义在内层函数外的外层函数的作用域中变量
闭包:是一个概念,出现在嵌套函数中,指的是内层函数引用到了外层函数的自由变量,就形成了闭包,很多语言都有这个概念
示例:
def counter(): c = [0] def inc(): c[0] += 1 return c[0] return inc foo = counter() print(foo(),foo()) c = 100 print(foo())
输出为:
1 2 3
c已经在counter函数中定义过,inc中使用方式为c元素修改至,不是重新定义,不会报错
inc引用的自由变量c为函数counter变两次,形成闭包
nonlocal关键字
使用nonlocal关键字,将变量标记为不在本地作用域定义,而是上级的某一级局部作用域中定义,但不是全局作用域中定义
示例:
def counter(): count = 0 def inc(): nonlocal count count += 1 return count return inc foo = counter() print(foo()) print(foo())
输出:
1 2
count是外层函数的局部变量,被内部函数引用
内部函数使用nonlocal关键字声明count变量在上级作用域而非本地作用域中定义
变量名解析原则LEGB
local,本地作用域,局部作用域的local明明空间,函数调用时创建,调用结束消亡
enclosing,python2.2时引入了嵌套函数,实现了闭包,这就是嵌套函数的外部函数的命名空间
global,全局作用域,即一个模块的命名空间,模块被import时创建,解释器退出时消亡
build-in,内置模块的命名空间,声明周期从python解释器启动时创建到解释器退户时消亡,例如print(open),print和open都是内置的函数
函数的销毁
全局函数销毁
- 重新定义同名函数
- del语句删除函数对象
- 程序结束时
示例:
def foo(xyz=[],u='abc',z=123): xyz.append(1) return xyz print(foo(),id(foo),foo.__defaults__) def foo(xyz=[],u='abc',z=123): xyz.append(1) return xyz print(foo(),id(foo),foo.__defaults__) del foo print(foo(),id(foo),foo.__defaults__)
输出为:
Traceback (most recent call last): [1] 1730166338152 ([1], 'abc', 123) File "E:/PycharmProjects/untitled/test/a.py", line 19, in <module> print(foo(),id(foo),foo.__defaults__) [1] 1730166338968 ([1], 'abc', 123) NameError: name 'foo' is not defined
两次定义函数foo的地址不同,del语句删除函数后报错
局部函数销毁
- 重新再上级作用域定义同名函数
- del语句删除函数名称,函数的引用计数减1
- 上级作用域销毁时
示例:
def foo(xyz=[],u='abc',z=123): xyz.append(1) def inner(a=10): pass print(inner) def inner(a=100): print(xyz) print(inner) return inner bar = foo() print(id(foo),id(bar),foo.__defaults__,bar.__defaults__) del bar print(id(foo),id(bar),foo.__defaults__,bar.__defaults__)
输出为:
Traceback (most recent call last): File "E:/PycharmProjects/untitled/test/a.py", line 20, in <module> print(id(foo),id(bar),foo.__defaults__,bar.__defaults__) NameError: name 'bar' is not defined <function foo.<locals>.inner at 0x0000020DED0F3268> <function foo.<locals>.inner at 0x0000020DED0F3598> 2258835026400 2258835027352 ([1], 'abc', 123) (100,)