第三章 Python基礎——文件操作&函數 續
3.6函數進階
名稱空間:name space
例:若變量X=1,1存放於內存中,那存放X與1綁定關系的地方就叫做名稱空間。
名稱空間共三種,分別如下:
- locals:是函數內名稱空間,包括局部變量和形參
- globals:全局變量,函數定義所在模塊的名字空間
- builtins:內置模塊的名字空間
不同變量的作用域不同就是由於這個變量所在的命名空間決定的。
作用域即範圍:
- 全局範圍:全局存活,全局有效
- 局部範圍:臨時存活,局部有效
註:查看作用域方法 globals(),locals()
作用域查找順序:
level=‘L0‘ n=22 def func(): leval=‘L1‘ n=33 print(locals()) def outer(): n=44 level=‘L2‘ print(locals(),n) def inner():#此處打印n是多少? level=‘L3‘ print(locals(),n) inner() outer() func()
問題:在inner()裏的打印n的值是多少?
LEGB代表名字查找順序:locals->enclosing function->globals->__builtins__
- locals是函數內的名字空間,包括局部變量和形參
- enclosing外部嵌套函數的名字區間
- globals全局變量,函數定義所在模塊的名字空間
- builtins內置模塊的名字空間
閉包
關於閉包,即函數定義和函數表達式位於另一個函數的函數體內(嵌套函數)。
詳解:而且,這些內部函數可以訪問他們所在外部函數中聲明的所有局部變量、參數。當其中一個這樣的內部函數在包含他們的外部函數被調用時,就會形成閉包。也就是說,內部函數會在外部函數返回後被執行。而當這個內部函數執行時,它仍然必須訪問其外部函數的局部變量、參數以及其他內部函數。這些局部變量、參數和函數聲明(最初時)的值是外部函數返回時的值,但也會會受到內部函數的影響。
def outer(): name=‘alex‘ def inner(): print("在inner裏打印外層函數的變量“,name) return inner f=outer() f()
閉包的意義:返回的函數對象,不僅僅是一個函數對象,在函數外還包裹了一層作用域,這使得該函數無論在何處調用,優先使得自己外層包裹的作用域。
裝飾器
例1:
#_*_coding:utf-8_*_ user_status = False #用戶登錄了就把這個改成True def login(): _username = "alex" #假裝這是DB裏存的用戶信息 _password = "abc!23" #假裝這是DB裏存的用戶信息 global user_status if user_status == False: username = input("user:") password = input("pasword:") if username == _username and password == _password: print("welcome login....") user_status = True else: print("wrong username or password!") else: print("用戶已登錄,驗證通過...") def home(): print("---首頁----") def america(): login() #執行前加上驗證 print("----歐美專區----") def japan(): print("----日韓專區----") def henan(): login() #執行前加上驗證 print("----河南專區----") home() america() henan()
註:在軟件開發中有一個原則“開放-封閉”原則,簡單來說,它規定已經實現的代碼不允許被修改,但可以被擴展,即:
封閉:已實現的功能代碼不應該被修改
開放:對現有功能的擴展開放
def login(func): #把要執行的模塊從這裏傳進來 def inner():#再定義一層函數 _username = "alex" #假裝這是DB裏存的用戶信息 _password = "abc!23" #假裝這是DB裏存的用戶信息 global user_status if user_status == False: username = input("user:") password = input("pasword:") if username == _username and password == _password: print("welcome login....") user_status = True else: print("wrong username or password!") if user_status == True: func() # 看這裏看這裏,只要驗證通過了,就調用相應功能 return inner #用戶調用login時,只會返回inner的內存地址,下次再調用時加上()才會執行inner函數
簡化上邊的代碼——去掉下邊這行
america=login(america)#你在這裏相當於把america這個函數替換了
最終簡化為:
#_*_coding:utf-8_*_ user_status = False #用戶登錄了就把這個改成True def login(func): #把要執行的模塊從這裏傳進來 def inner(*args,**kwargs):#再定義一層函數 _username = "alex" #假裝這是DB裏存的用戶信息 _password = "abc!23" #假裝這是DB裏存的用戶信息 global user_status if user_status == False: username = input("user:") password = input("pasword:") if username == _username and password == _password: print("welcome login....") user_status = True else: print("wrong username or password!") if user_status == True: func(*args,**kwargs) # 看這裏看這裏,只要驗證通過了,就調用相應功能 return inner #用戶調用login時,只會返回inner的內存地址,下次再調用時加上()才會執行inner函數 def home(): print("---首頁----") @login def america(): #login() #執行前加上驗證 print("----歐美專區----") def japan(): print("----日韓專區----") # @login def henan(style): ‘‘‘ :param style: 喜歡看什麽類型的,就傳進來 :return: ‘‘‘ #login() #執行前加上驗證 print("----河南專區----") home() # america = login(america) #你在這裏相當於把america這個函數替換了 henan = login(henan) # #那用戶調用時依然寫 america() henan("3p")
帶參數裝飾器:
#_*_coding:utf-8_*_ user_status = False #用戶登錄了就把這個改成True def login(auth_type): #把要執行的模塊從這裏傳進來 def auth(func): def inner(*args,**kwargs):#再定義一層函數 if auth_type == "qq": _username = "alex" #假裝這是DB裏存的用戶信息 _password = "abc!23" #假裝這是DB裏存的用戶信息 global user_status if user_status == False: username = input("user:") password = input("pasword:") if username == _username and password == _password: print("welcome login....") user_status = True else: print("wrong username or password!") if user_status == True: return func(*args,**kwargs) # 看這裏看這裏,只要驗證通過了,就調用相應功能 else: print("only support qq ") return inner #用戶調用login時,只會返回inner的內存地址,下次再調用時加上()才會執行inner函數 return auth def home(): print("---首頁----") @login(‘qq‘) def america(): #login() #執行前加上驗證 print("----歐美專區----") def japan(): print("----日韓專區----") @login(‘weibo‘) def henan(style): ‘‘‘ :param style: 喜歡看什麽類型的,就傳進來 :return: ‘‘‘ #login() #執行前加上驗證 print("----河南專區----") home() # america = login(america) #你在這裏相當於把america這個函數替換了 #henan = login(henan) # #那用戶調用時依然寫 america() # henan("3p")
3.6生成器,叠代器
列表生成式:
例:把列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],要求把列表裏的每個值都加1
>>> a = [i+1 for i in range(10)] >>> a [1, 2, 3, 4, 5, 6, 7, 8, 9, 10列表生成式]
這種寫法就叫做生成式
生成式
在python中一邊循環一邊計算的機制稱為生成器:generator
要創建一個generator,有很多種方法。第一種方法很簡單,只要把一個列表生成式的[]
改成(),
就創建了一個generator:
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>
建L
和g
的區別僅在於最外層的[]
和()
,L
是一個list,而g
是一個generator。
我們可以直接打印出list的每一個元素,想要打印書generator的每一個元素有哦兩種方法:
第一種用next()
>>> next(g) 0 >>> next(g) 1 >>> next(g) 4 >>> next(g) 9 >>> next(g) 16 >>> next(g) 25 >>> next(g) 36 >>> next(g) 49 >>> next(g) 64 >>> next(g) 81 >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
第二種for循環,generator也是可叠送的對象
>>> g = (x * x for x in range(10)) >>> for n in g: ... print(n) ... 0 1 4 9 16 25 36 49 64 81
叠送器
可以直接作用於for
循環的數據類型有以下幾種:
一類是集合數據類型,如list
、tuple
、dict
、set
、str
等;
一類是generator
,包括生成器和帶yield
的generator function。
這些可以直接作用於for
循環的對象統稱為可叠代對象:Iterable
。
可以使用isinstance()
判斷一個對象是否是Iterable
對象:
>>> from collections import Iterable >>> isinstance([], Iterable) True >>> isinstance({}, Iterable) True >>> isinstance(‘abc‘, Iterable) True >>> isinstance((x for x in range(10)), Iterable) True >>> isinstance(100, Iterable) False
而生成器不但可以作用於for循環,還可以被next()函數不斷調用並返回下一個值,直到最後拋出StopIteration錯誤表示無法繼續返回下一個值了。
*可以被next()函數調用並不斷返回下一個值的對象稱為叠代器:Iterator。
可以使用isinstance()判斷一個對象是否是Iterator對象:
>>> from collections import Iterator >>> isinstance((x for x in range(10)), Iterator) True >>> isinstance([], Iterator) False >>> isinstance({}, Iterator) False >>> isinstance(‘abc‘, Iterator) False
生成器都是Iterator
對象,但list
、dict
、str
雖然是Iterable
,卻不是Iterator
。
把list
、dict
、str
等Iterable
變成Iterator
可以使用iter()
函數:
>>> isinstance(iter([]), Iterator) True >>> isinstance(iter(‘abc‘), Iterator) True
Python的Iterator
對象表示的是一個數據流,Iterator對象可以被next()
函數調用並不斷返回下一個數據,直到沒有數據時拋出StopIteration
錯誤。可以把這個數據流看做是一個有序序列,但我們卻不能提前知道序列的長度,只能不斷通過next()
函數實現按需計算下一個數據,所以Iterator
的計算是惰性的,只有在需要返回下一個數據時它才會計算。
Iterator
甚至可以表示一個無限大的數據流,例如全體自然數。而使用list是永遠不可能存儲全體自然數的。
第三章 Python基礎——文件操作&函數 續