python学习笔记(六)——函数的作用域和装饰器
目錄
- 函數作用域
- global和nonlocal關鍵字
- 遞歸
- 閉包
- 裝飾器
函數作用域
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 = 200print(a) func1() print(a)執行結果: 200 2002、nonlocal
讓嵌套函數能夠修改嵌套函數之外的值,就是用來修改嵌套作用域的變量的。
def func1():x = 100def func2():nonlocal xx += 100return xreturn func2()a = func1() print(a)執行結果: 200遞歸
在函數內部,可以調用其他函數。如果一個函數在內部調用自身本身,這個函數就是遞歸函數。
實例 1:
# 遞歸 def fibonacci(a):if a == 0: # 簡寫 if a == 0 or a == 1: 與或非 邏輯運算符return 0elif a == 1:return 1else:return fibonacci(a-1) + fibonacci(a-2)a = fibonacci(20) print(a)執行結果: 6765實例 2:
# 遞歸乘積 def factorial(num): # feik toolr aoif num>1:result = num*factorial(num-1)else:result = 1return resulta = 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'+xreturn func1 print(func('world')()) 執行結果:hello world實例 3:
def dome1():a = 100def dome2():return a + areturn dome2a = dome1() print(a()) 200------------------------------------ li = [] for i in range(4):def func():return ili.append(func)for f in li:print(f()) 3 3 3 3 ------------------------------------ li = [] for i in range(4):def func(i):def func1():return ireturn func1li.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 func2def 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_timeprint('總共花費時間為:%s'%total_time)return new_func@run_time def count_sum2(): #從1加到10000count = 0for i in range(1,10001):count = count+ireturn countcount_sum2()運行結果:
開始時間為:2021-03-31 00:36:48.318660
結束時間為:2021-03-31 00:36:48.319690
總共花費時間為:0:00:00.001030
總結
以上是生活随笔為你收集整理的python学习笔记(六)——函数的作用域和装饰器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 复习笔记(二)——C++面向对象设计和使
- 下一篇: websocket python爬虫_p