python中的用法 Python中使用 的理解

2021-10-12 10:51:54 字數 4218 閱讀 1528

python函式中使用@

稍提一下的基礎

fun 和fun()的區別

以一段**為例:

def fun():

print('fun')

return none

a = fun() #fun函式並將返回值給a

print('a的值為',a)

b = fun #將fun函式位址賦給b

b() #呼叫b,b和fun指向的位址相同

print('b的值為',b)

'''輸出

funa的值為 none

funb的值為

根據輸出可以看出,a=fun()是將函式fun的返回值(none)賦給a,而b=fun是將函式的位址賦給b,如果呼叫函式,需要b()

類似的,其他內建函式也可以通過這種方法,相當於起了乙個同名的函式

>>>a = abs

>>>a(-1)

除此之外,原來的函式名也被覆蓋為其他函式,例如

def fun():

print('fun')

abs = fun

abs() #輸出fun

綜上,可以理解為fun,abs在不帶括號時為變數,該變數包含了函式在內容的位址

返回函式

以廖老師的教程為例

def lazy_sum(*args):

def sum():

ax = 0

for n in args:

ax = ax + n

return ax

return sum

>>> f = lazy_sum(1, 3, 5, 7, 9)

>>> f

.sum at 0x101c6ed90>

>>>f()

在單步除錯中可以發現,當讀到def sum():時,直譯器會直接跳到return sum將sum函式的位址返回給f,因此f()即為執行sum() (不是非常準確,但先如此理解)

如果對返回函式還是有些不理解的話,可以假設lazy_sum()的返回值改為1

def lazy_sum(*args):

def sum():

ax = 0

for n in args:

ax = ax + n

return ax

return 1

f = lazy_sum(1,3,5,7,9)

print(f)#q輸出1

print(f())#報錯'int' object is not callable

此時無論lazy_sum()的引數如何修改,都會把1賦給f,而1()是不可呼叫的,因此會報錯

⭐返回函式中的閉包問題也要了解一下,內嵌函式可以訪問外層函式的變數

引數的巢狀呼叫

仍然上述例子,此時將lazy_sum()改為空函式,內嵌的sum()需要引數:

def lazy_sum():

def sum(*args):

ax = 0

for n in args:

ax = ax + n

return ax

return sum

f = lazy_sum()(1,3,5,7,9)

print(f)#輸出25

按照運算的優先順序,可以理解為:

執行 lazy_sum(),返回sum;

執行sum(1,3,5,7,9),返回25;

將25賦給f

如果有了以上基礎,再來看@的用法就會覺得很容易了

@的使用

不帶引數的單一使用(乙個@修飾)

def spamrun(fn):

def sayspam():

print("spam,spam,spam")

fn()

return sayspam

@spamrun

def useful():

print('useful')

useful()

輸出:spam,spam,spam

useful

修飾效果相當於useful = spamrun(useful),具體步驟如下:

在初始化時,直譯器讀到@spamrun,此時將下方的useful作為引數傳入到spamrun中

spamrun(useful)中,由於是返回函式,直接將sayspam()的記憶體位址賦給useful

執行useful(),此時useful指向了sayspam,因此列印spam,spam,spam。然後執行fn(),此時的fn才指向原來的useful()的位址,開始執行print('useful')

執行流程可以在下圖了解一下,可以理解為經過@後,useful已經不直接指向函式useful()的位址了,而是sayspam。再呼叫useful()時,執行sayspam(),由於fn儲存原先useful()函式的位址,因此可以執行useful()的功能,即可以列印出'useful'。如果『使壞』把fn()去掉的話,相當於useful()再也不會執行了

一般情況下,使用@時不會改變函式原先的執行邏輯,而只是增加功能,因此成為裝飾器,如廖老師教程中可以使原函式列印日誌

def log(func):

print('call %s():' % func.__name__)

return func(*args, **kw)

@log

def now():

print('2015-3-25')

now()

call now():

2015-3-25

不帶引數的多次使用(兩個@)

def spamrun(fn):

def sayspam():

print("spam,spam,spam")

fn()

return sayspam

def spamrun1(fn):

def sayspam1():

print("spam1,spam1,spam1")

fn()

return sayspam1

@spamrun

@spamrun1

def useful():

print('useful')

useful()

spam,spam,spam

spam1,spam1,spam1

useful

修飾效果相當於useful = spamrun(spamrun1(useful))

疊加使用時,裝飾器的呼叫順序和宣告順序是相反的,可以理解成是乙個遞迴的過程。

遇到@spamrun,開始向下尋找def 函式名

結果第二行也是乙個@。@spamrun1繼續向下找

遇到了def useful,執行useful = spamrun1(useful)

回歸。@spamrun1返回useful給@spamrun,執行useful=spamrun(useful)

帶引數的單次使用

以廖老師教程中的舉例,簡化一些,先不考慮*args,**kw,因為涉及到返回函式的閉包問題

def log(text):

def decorator(func):

print('%s %s():' % (text, func.__name__))

return func()

return decorator

@log('execute')

def now():

print('2015-3-25')

now()

修飾效果相當於now=log('execute')(now)

​1. 直譯器讀到@log('execute'),先執行了log('execute'),返回函式decorator

​2. 將now作為decorator(func)的形參,返回warpper

3. 將`warpper`的記憶體位址賦給變數`now`

此時呼叫now(),先執行完print(...),然後return func()。注意此處是帶括號的,因此執行了真正的now函式,最終return的為none

帶引數的多次呼叫可以將之前的情況組合即可

總結@行不帶引數

@***

def fun***():

會被解釋成fun*** = ***(fun***)

如果@那行中帶引數,則被解釋成fun*** = ***(@行的引數)(fun***)

要深刻理解返回函式以及fun和fun()的區別

函式的記憶體位址,函式變數,函式的名稱的區別。預設情況下,函式變數指向函式的記憶體位址,但也可以被改變

初學python,學識短淺,希望多多交流

pytho中with語句的用法

python中的with語句使用於對資源進行訪問的場合,在程式處理過程中是否異常都會執行 enter self 方法,exit 清理 方法操作,釋放被訪問的資源,比如有檔案讀寫後自動關閉 執行緒中鎖的自動獲取和釋放都可以使用。用open開啟乙個檔案進行讀寫時,都有可能產生ioerror。而且檔案每次...

Pytho高階篇 yield的用法

yield 是python中非常有用的乙個關鍵字,可以實現很多魔法。yield關鍵字主要有一下幾個用法。1.yield基本用法 yield用在函式中,實現類似用return的功能,但是返回的是乙個generator.更多詳細解釋,參考下邊的 如何正確理解yiled在函式中的作用 2.yield實現上...

python中迭代器的基本方法 Python迭代器

迭代器是可以迭代的物件。在本教程中,您將了解迭代器的工作原理,以及如何使用 iter 和 next 方法構建自己的迭代器。迭代器在python中無處不在。它們優雅地實現在迴圈,推導,生成器等中,但隱藏在明顯的視覺中。python中的迭代器只是乙個可以迭代的物件。乙個將一次返回資料的物件或乙個元素。從...