函数作用域
global和nonlocal关键字
思考:
def func():
name = 'laowang'
print(name) # 能打印吗?
func()
print(name) # 能打印吗?
执行结果:
laowang
NameError: name 'name' is not defined 为什么没有被定义?
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。
局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。
调用函数时,所有在函数内声明的变量名称都将被加入到作用域中
当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字了。
1、global
能够在函数里修改全局变量的值。
a = 100 # 全局变量
def func1():
global a # 修改全局变量
a = 200
print(a)
func1()
print(a)
执行结果:
200
200
2、nonlocal
让嵌套函数能够修改嵌套函数之外的值,就是用来修改嵌套作用域的变量的。
def func1():
x = 100
def func2():
nonlocal x
x += 100
return x
return func2()
a = func1()
print(a)
执行结果:
200
递归
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
实例 1:
# 递归
def fibonacci(a):
if a == 0: # 简写 if a == 0 or a == 1: 与或非 逻辑运算符
return 0
elif a == 1:
return 1
else:
return fibonacci(a-1) + fibonacci(a-2)
a = fibonacci(20)
print(a)
执行结果:
6765
实例 2:
# 递归乘积
def factorial(num): # feik toolr ao
if num>1:
result = num*factorial(num-1)
else:
result = 1
return result
a = factorial(999) # 报错 998 不会
print(a)
思考: 下面的例子运行结果会怎么样?
def func()
print('hello')
func()
func()
该例子在打印多次hello后为什么会出现内存溢出?
因为该例子的函数没有出口。没有出口就会造成内存溢出。
内存溢出:内存不够,通常在运行大型软件或游戏时,软件或游戏所需要的内存远远超出了你主机内安装的内存所承受大小,就叫内存溢出。此时软件或游戏就运行不了,系统会提示内存溢出,有时候会自动关闭软件,重启电脑或者软件后释放掉一部分内存又可以正常运行该软件
闭包
闭包是函数里面嵌套函数,外层函数返回里层函数。
内部函数调用外部函数的的变量,外函数返回内函数的引用。
实例 1:
def func():
def func1():
return 'hello'
return func1()
print(func())
执行结果:hello
实例 2:
def func(x):
def func1():
return 'hello'+x
return func1
print(func('world')())
执行结果:hello world
实例 3:
def dome1():
a = 100
def dome2():
return a + a
return dome2
a = dome1()
print(a()) 200
------------------------------------
li = []
for i in range(4):
def func():
return i
li.append(func)
for f in li:
print(f()) 3 3 3 3
------------------------------------
li = []
for i in range(4):
def func(i):
def func1():
return i
return func1
li.append(func(i))
for f in li:
print(f()) 0 1 2 3
什么是引用?
在python中一切都是对象,包括整型数据1,函数,其实是对象。当我们进行a=1的时候,实际上在内存当中有一个地方存了值1,然后用a这个变量名存了1所在内存位置的引用。引用就好像c语言里的指针,大家可以把引用理解成地址。a只不过是一个变量名字,a里面存的是1这个数值所在的地址,就是a里面存了数值1的引用。
相同的道理,当我们在python中定义一个函数def demo(): 的时候,
内存当中会开辟一些空间,存下这个函数的代码、内部的局部变量等等。这个demo只不过是一个变量名字,
它里面存了这个函数所在位置的引用而已。我们还可以进行x = demo, y = demo,
这样的操作就相当于,把demo里存的东西赋值给x和y,这样x 和y 都指向了demo函数所在的引用,
在这之后我们可以用x() 或者 y() 来调用我们自己创建的demo() ,
调用的实际上根本就是一个函数,x、y和demo三个变量名存了同一个函数的引用。
装饰器
装饰器用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数。
装饰器的好处就在于不用更改原函数代码的前提下给函数增加新的功能。
作业:不影响之后写代码,会轻松很多,节省代码量
实例 1:
def func1(func3):
def func2():
print('----验证功能----')
func3()
return func2
def func3():
print('----登录功能----') # 登陆功能,不改变增加验证功能
a = func1(func3) #一般调用写法
a()
改成装饰器后:
def func1(func3):
def func2():
print('----验证功能----')
func3()
return func2
@func1 #相当于上面的a = func1(func3)
def func3():
print('----登录功能----') # 登陆功能,不改变增加验证功能
func3()
结果均为:
----验证功能----
----登录功能----
实例 2:(计算for循环所花费时间)
from datetime import datetime
def run_time(func): # 这是一个用来计算程序执行时间的装饰器
def new_func():
start_time = datetime.now()
print('开始时间为:%s'%start_time)
func()
end_time = datetime.now()
print('结束时间为:%s'%end_time)
total_time = end_time - start_time
print('总共花费时间为:%s'%total_time)
return new_func
@run_time
def count_sum2(): #从1加到10000
count = 0
for i in range(1,10001):
count = count+i
return count
count_sum2()
运行结果:
开始时间为:2021-03-31 00:36:48.318660
结束时间为:2021-03-31 00:36:48.319690
总共花费时间为:0:00:00.001030