日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python中的用法_Python中使用@的理解

發布時間:2025/3/19 python 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python中的用法_Python中使用@的理解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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)

'''輸出

fun

a的值為 None

fun

b的值為

'''

根據輸出可以看出,a=fun()是將函數fun的返回值(None)賦給a,而b=fun是將函數的地址賦給b,如果調用函數,需要b()

類似的,其他內置函數也可以通過這種方法,相當于起了一個同名的函數

>>>a = abs

>>>a(-1)

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()

25

在單步調試中可以發現,當讀到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):

def wrapper(*args, **kw):

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

return func(*args, **kw)

return wrapper

@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):

def wrapper():

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

return func()

return wrapper

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

帶參數的多次調用可以將之前的情況組合即可

總結

@行不帶參數

@XXX

def funXXX():

會被解釋成funXXX = XXX(funXXX)

如果@那行中帶參數,則被解釋成funXXX = XXX(@行的參數)(funXXX)

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

函數的內存地址,函數變量,函數的名稱的區別。默認情況下,函數變量指向函數的內存地址,但也可以被改變

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

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的python中的用法_Python中使用@的理解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。