python笔记Ⅶ--函数返回值、作用域与命名空间、递归
一、返回值:返回值就是函数执行以后返回的结果
1、可以通过 return 来指定函数的返回值。可以之间使用函数的返回值,也可以通过一个变量来接收函数的返回值。
2、return 后边跟什么值,函数就会返回什么值。
return 后边可以跟任意的对象,返回值甚至可以是一个函数。
例:
def fn():
# return 'Hello'
# return [1,2,3]
# return {'k':'v'}
def fn2() :
print('hello')
return fn2 # 返回值也可以是一个函数
r = fn() # 这个函数的执行结果就是它的返回值
r() # 这里r()就是一个函数,可以直接调用
print(fn())
print(r)
3、如果仅仅写一个return 或者 不写return,则相当于return None
def fn2() :
a = 10
return
r = fn2()
print(r)
返回的是None。
4、在函数中,return后的代码都不会执行,return 一旦执行函数自动结束
def fn3():
print('hello')
return
print('abc')
r = fn3()
print(r)
返回的是hello。
5、return与break、continue的区别:
① return用来结束函数
② break 用来退出当前循环
③ continue 用来跳过当次循环
def fn4() :
for i in range(5):
if i == 3 :
# break 用来退出当前循环
# continue 用来跳过当次循环
return # return 用来结束函数
print(i)
print('循环执行完毕!')
fn4()
返回的是0、1、2。
6、fn5 和 fn5()的区别
print(fn5) # fn5是函数对象,打印fn5实际是在打印函数对象 <function fn5 at 0x05771BB8>
print(fn5()) # fn5()是在调用函数,打印fn5()实际上是在打印fn5()函数的返回值 10
二、help()函数 :是Python中的内置函数,通过help()函数可以查询python中的函数的用法
语法:help(函数对象)
help(print) # 获取print()函数的使用说明
三、文档字符串(doc str)
> 在定义函数时,可以在函数内部编写文档字符串,文档字符串就是函数的说明。
> 当我们编写了文档字符串时,就可以通过help()函数来查看函数的说明。
> 文档字符串非常简单,其实直接在函数的第一行写一个字符串 ''' 就是文档字符串。
def fn(a:int,b:bool,c:str='hello') -> int:
'''
这是一个文档字符串的示例
函数的作用:......
函数的参数:
a,作用,类型,默认值......
b,作用,类型,默认值......
c,作用,类型,默认值......
'''
return 10
help(fn)
四、作用域与命名空间
1、作用域(scope):指的是变量生效的区域
例1:
def fn():
a = 10 # a定义在了函数内部,所以他的作用域就是函数内部,函数外部无法访问
print('函数内部:','a =',a)
print('函数内部:','b =',b)
fn()
print('函数外部:','a =',a)
print('函数外部:','b =',b)
这里a定义在了函数内部,所以他的作用域就是函数内部,函数外部无法访问 。
(1)在Python中一共有两种作用域:
① 全局作用域:全局作用域在程序执行时创建,在程序执行结束时销毁。
- 所有函数以外的区域都是全局作用域。
- 在全局作用域中定义的变量,都属于全局变量,全局变量可以在程序的任意位置被访问。
② 函数作用域: 函数作用域在函数调用时创建,在调用结束时销毁
- 函数每调用一次就会产生一个新的函数作用域。
- 在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问。
(2)变量的查找
当我们使用变量时,会优先在当前作用域中寻找该变量,
① 如果有则使用,
② 如果没有则继续去上一级作用域中寻找,如果有则使用,
③ 如果依然没有则继续去上一级作用域中寻找,以此类推,
④ 直到找到全局作用域,依然没有找到,则会抛出异常 NameError: name 'a' is not defined
(3)在函数中为变量赋值时,默认都是为局部变量赋值。如果希望在函数内部修改全局变量,则需要使用global关键字,来声明变量.
def fn3():
# a = 10
global a # 声明在函数内部的使用a是全局变量,此时再去修改a时,就是在修改全局的a
a = 10 # 修改全局变量
print('函数内部:','a =',a)
fn3()
print('函数外部:','a =',a)
2、命名空间(namespace):指的是变量存储的位置,每一个变量都需要存储到指定的命名空间当中。
scope = locals() # 当前命名空间
print(type(scope))
print(a)
print(scope['a'])
# 向scope中添加一个key-value
scope['c'] = 1000 # 向字典中添加key-value就相当于在全局中创建了一个变量(一般不建议这么做)
print(c)
(1)每一个作用域都会有一个它对应的命名空间。
(2)全局命名空间,用来保存全局变量。函数命名空间用来保存函数中的变量
(3)命名空间实际上就是一个字典,是一个专门用来存储变量的字典
(4)locals()用来获取当前作用域的命名空间。
① 如果在全局作用域中调用locals()则获取全局命名空间,
② 如果在函数作用域中调用locals()则获取函数命名空间,返回的是一个字典
(5)globals() 函数可以用来在任意位置获取全局命名空间。
def fn4():
a = 10
# scope = locals() # 在函数内部调用locals()会获取到函数的命名空间
# scope['b'] = 20 # 可以通过scope来操作函数的命名空间,但是也不建议这么做
global_scope = globals()
# print(global_scope['a'])
global_scope['a'] = 30
print(scope)
fn4()
五、递归:递归式函数,就是在函数中自己调用自己
递归是解决问题的一种方式,它和循环很像。它的整体思想是,将一个大问题分解为一个个的小问题,直到问题无法分解时,再去解决问题。
1、递归式函数的两个要件:
(1)基线条件
- 问题可以被分解为的最小问题,当满足基线条件时,递归就不再执行了
(2)递归条件
- 将问题继续分解的条件
2、递归和循环类似,基本是可以互相代替的,
(1)循环编写起来比较容易,阅读起来稍难
(2)递归编写起来难,但是方便阅读
3、无穷递归:如果这个函数被调用,程序的内存会溢出,效果类似于死循环
# def fn():
# fn()
# fn()