<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
名稱空間是從名稱到物件的對映,大部分的名稱空間都是通過 Python 字典來實現的。
名稱空間提供了在專案中避免名字衝突的一種方法。各個名稱空間是獨立的,沒有任何關係的,所以一個名稱空間中不能有重名,但不同的名稱空間是可以重名而沒有任何影響。
len/eval/enumerate/bytes/max/min/sorted/map/filter....
如果找不到變數 runoob,它將放棄查詢並引發一個 NameError 異常:
NameError: name 'runoob' is not defined。
名稱空間的生命週期取決於物件的作用域,如果物件執行完成,則該名稱空間的生命週期就結束。
因此,我們無法從外部名稱空間存取內部名稱空間的物件。
如下圖所示,相同的物件名稱可以存在於多個名稱空間中。
作用域就是一個 Python 程式可以直接存取名稱空間的正文區域。
全域性名稱空間和區域性名稱空間中可能會存在名字相同的變數,但是這兩個變數互不影響。
Python 中,程式的變數並不是在哪個位置都可以存取的,存取許可權決定於這個變數是在哪裡賦值的。
變數的作用域決定了在哪一部分程式可以存取哪個特定的變數名稱。
Python的作用域一共有4種,分別是:
對於變數作用域,變數的存取以: L –> E –> G –>B 的 規則查詢。
在區域性找不到,便會去區域性外的區域性找(例如閉包),再找不到就會去全域性找,再者去內建中找。
舉例:
x = 1 def func(): print(x) #10 x = 10 func()
內建作用域是通過一個名為 builtin 的標準模組來實現的,但是這個變數名自身並沒有放入內建作用域內,所以必須匯入這個檔案才能夠使用它。
在Python3.0中,可以使用以下的程式碼來檢視到底預定義了哪些變數:
import builtins print(dir(builtins))
Python 中只有模組(module),類(class)以及函數(def、lambda)才會引入新的作用域,其它的程式碼塊(如 if/elif/else/、try/except、for/while等)是不會引入新的作用域的,也就是說這些語句內定義的變數,外部也可以存取,
如下程式碼:範例中 msg 變數定義在 if 語句塊中,但外部還是可以存取的。如果將 msg 定義在函數中,則它就是區域性變數,外部不能存取。
if True: msg = 'I am from Runoob' print(msg) # 'I am from Runoob'
定義在函數內部的變數擁有一個區域性作用域,定義在函數外的擁有全域性作用域。
區域性變數只能在其被宣告的函數內部存取,而全域性變數可以在整個程式範圍內存取。呼叫函數時,所有在函數內宣告的變數名稱都將被加入到作用域中。
# 作用域注意點 x = 1 def f1(): # 定義階段x=1 print(x) #1 def f2(): x = 2 #此x為f2函數的區域性變數,f1無法直接存取 f1() f2()
def f1(): def inner(): print('from inner') return inner f = f1() # from inner 。把區域性定義的函數inner()放在全域性之中 def bar(): f() bar()
函數內可以存取全域性變數,但不能直接更新(修改)其值,可以加上 global 參照以更新變數值 :
x = 1 def f1(): x = 2 def f2(): global x # 修改全域性 x = 3 f2() f1() print(x) # 3
如果要修改巢狀作用域(enclosing 作用域,外層非全域性作用域)中的變數則需要 nonlocal 關鍵字了
x = 1 def f1(): x = 2 def f2(): nonlocal x x = 3 f2() print(x) # 3 f1()
閉包:閉是封閉(函數內部函數),包是包含(該內部函數對外部作用域而非全域性作用域的變數的參照)。
閉包指的是:函數內部函數對外部作用域而非全域性作用域的參照。
def outter(x): x = 1 def inner(): print(x) return inner #返回的是函數名(函數物件) f = outter(2) f() # 1 f() # 1 f() # 1 # 檢視閉包的元素 print(f.__closure__[0].cell_contents) # 1
閉包的意義:返回的函數物件,不僅僅是一個函數物件,在該函數外還包裹了一層作用域,這使得,該函數無論在何處呼叫,優先使用自己外層包裹的作用域。
延遲計算(原來我們是傳參,現在我們是包起來)、爬蟲領域。
import requests def outter(url): def get(): response = requests.get(url) print(f"done: {url}") return get baidu = outter('https://www.baidu.com') python = outter('https://www.python.org') baidu() baidu() python() python()
裝飾器指的是為被裝飾器物件新增額外功能。因此定義裝飾器就是定義一個函數,只不過該函數的功能是用來為其他函數新增額外的功能。裝飾器的實現必須遵循兩大原則:
裝飾器其實就是在遵循以上兩個原則的前提下為被裝飾物件新增新功能。
不改變函數體程式碼,並且不改變函數呼叫方式,它本質就是一個閉包函數。
def f1(x): def f2(): print(x) # 10 return f2 f2 = f1() f2() # f2()
在不改變當前函數的情況下, 給其增加新的功能:
def log(pr): # 將被裝飾函數傳入 def wrapper(): print("**********") return pr() # 執行被裝飾的函數 return wrapper # 將裝飾完之後的函數返回(返回的是函數名) @log def pr(): print("我是小小洋") pr() # ********** # 我是小小洋
回撥函數和返回函數的範例就是裝飾器。
舉例:
import time def index(): print('welcome to index') time.sleep(1) def time_count(func): # func = 最原始的index def wrapper(): start = time.time() func() end = time.time() print(f"{func} time is {start - end}") # time is -1.0038220882415771 return wrapper index = time_count(index) # index為被裝飾函數index的記憶體地址,即index = wrapper index() # wrapper()
如果原始的被裝飾函數index()有返回值的時候,wrapper()函數的返回值應該和index()的返回值相同,也就是說,我們需要同步原始的index()和wrapper()方法的返回值。
import time def index(): print('welcome to index') time.sleep(1) return 123 def time_count(func): # func = 最原始的index def wrapper(): start = time.time() res1 = func() end = time.time() print(f"{func} time is {start - end}") # time is -1.0050289630889893 return res1 return wrapper index = time_count(index) res = index() print(f"res: {res}") # res: 123
如果原始的被裝飾函數index()方法需要傳參,那麼我們之前的裝飾器是無法實現該功能的,由於有wrapper()=index(),所以給wrapper()方法傳參即可。
import time def index(): print('welcome to index') time.sleep(1) return 123 def home(name): print(f"welcome {name} to home page") time.sleep(1) return name def time_count(func): def wrapper(*args, **kwargs): start = time.time() res = func(*args, **kwargs) end = time.time() print(f"{func} time is {start-end}") # time is -1.0039079189300537 return res return wrapper home = time_count(home) res = home('egon') print(f"res: {res}") #res: egon
def deco(func): def wrapper(*args,**kwargs): res = func(*args,**kwargs) return res return wrapper
在被裝飾函數正上方,並且是單獨一行寫上@裝飾器名
import time def time_count(func): #裝飾器 # func = 最原始的index def wrapper(*args, **kwargs): start = time.time() res = func(*args, **kwargs) end = time.time() print(f"{func} time is {start-end}") # time is -1.0005171298980713 return res return wrapper @time_count # home = time_count(home) def home(name): print(f"welcome {name} to home page") #welcome egon to home page time.sleep(1) return name res = home('egon') print(f"res: {res}") #res: egon
注意無參裝飾器只套兩層。
import time current_user = {'username': None} def login(func): # func = 最原始的index def wrapper(*args, **kwargs): if current_user['username']: res1 = func(*args, **kwargs) return res1 user = input('username: ').strip() pwd = input('password: ').strip() if user == 'nick' and pwd == '123': print('login successful') current_user['username'] = user res1 = func(*args, **kwargs) return res1 else: print('user or password error') return wrapper @login def index(): print('welcome to index') time.sleep(1) res = index() #username: nick #password: 123 #login successful #welcome to index
我們首先看看三層閉包怎麼運用。
def f1(y): def f2(): x = 1 def f3(): print(f"x: {x}") # x: 1 print(f"y: {y}") # x: 1 return f3 return f2 f2 = f1(2) f3 = f2() f3()
在函數中嵌入裝飾器
import time current_user = {'username': None} def auth(engine='file'): def login(func): def wrapper(*args, **kwargs): if current_user['username']: res = func(*args, **kwargs) return res user = input('username: ').strip() pwd = input('password: ').strip() if engine == 'file': print('base of file') if user == 'nick' and pwd == '123': print('login successful') current_user['username'] = user res = func(*args, **kwargs) return res else: print('user or password error') elif engine == 'mysql': print('base of mysql, please base of file') return wrapper return login @auth(engine='file') def index(): print('welcome to index') time.sleep(1) res = index()
username: nick
password: 123
base of file
login successful
welcome to index
沒錯,裝飾器不僅可以是函數,還可以是類,相比函數裝飾器,類裝飾器具有靈活度大、高內聚、封裝性等優點。使用類裝飾器主要依靠類的__call__方法,當使用 @ 形式將裝飾器附加到函數上時,就會呼叫此方法。
class Foo(object): def __init__(self, func): self._func = func def __call__(self): print ('class decorator runing') self._func() print ('class decorator ending') @Foo def bar(): print ('bar') bar() functools.wraps
使用裝飾器極大地複用了程式碼,但是他有一個缺點就是原函數的元資訊不見了,比如函數的docstring、__name__、參數列,先看例子:
# 裝飾器 def logged(func): def with_logging(*args, **kwargs): print func.__name__ # 輸出 'with_logging' print func.__doc__ # 輸出 None return func(*args, **kwargs) return with_logging # 函數 @logged def f(x): """does some math""" return x + x * x logged(f)
不難發現,函數 f 被with_logging取代了,當然它的docstring,__name__就是變成了with_logging函數的資訊了。好在我們有functools.wraps,wraps本身也是一個裝飾器,它能把原函數的元資訊拷貝到裝飾器裡面的 func 函數中,這使得裝飾器裡面的 func 函數也有和原函數 foo 一樣的元資訊了。
from functools import wraps def logged(func): @wraps(func) def with_logging(*args, **kwargs): print func.__name__ # 輸出 'f' print func.__doc__ # 輸出 'does some math' return func(*args, **kwargs) return with_logging @logged def f(x): """does some math""" return x + x * x
一個函數還可以同時定義多個裝飾器,比如:
@a @b @c def f (): pass
它的執行順序是從裡到外,最先呼叫最裡層的裝飾器,最後呼叫最外層的裝飾器,它等效於
f = a(b(c(f)))
現在我們來看一下裝飾器在哪些地方特別耀眼,以及使用它可以讓一些事情管理起來變得更簡單。
裝飾器能有助於檢查某個人是否被授權去使用一個web應用的端點(endpoint)。它們被大量使用於Flask和Django web框架中。這裡是一個例子來使用基於裝飾器的授權:
from functools import wraps def requires_auth(f): @wraps(f) def decorated(*args, **kwargs): auth = request.authorization if not auth or not check_auth(auth.username, auth.password): authenticate() return f(*args, **kwargs) return decorated
紀錄檔是裝飾器運用的另一個亮點。這是個例子:
from functools import wraps def logit(func): @wraps(func) def with_logging(*args, **kwargs): print(func.__name__ + " was called") return func(*args, **kwargs) return with_logging @logit def addition_func(x): """Do some math.""" return x + x result = addition_func(4) # Output: addition_func was called
到此這篇關於Python函數高階用法的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45