python装饰器为什么要双层嵌套函数
PHPz
PHPz 2017-04-18 09:41:45
0
6
841

今天学习了一下python的装饰器,比较难理解的是大家举最简单的装饰例子时都是双层嵌套:

但是单层函数,不也能实现装饰功能吗?python把装饰器设置成双层的目的是什么呢?@到底代表什么运作机制。

PHPz
PHPz

学习是最好的投资!

membalas semua(6)
刘奇

Seperti yang dinyatakan oleh beberapa pakar di atas, fungsi penghias (@tatabahasa) ialah:

@foo
def bar():
    ...

bersamaan dengan:

bar = foo(bar)

diterjemahkan ke dalam bahasa Cina ialah:

Gunakan fungsi yang diwakili oleh @ sebagai argumen untuk memanggil fungsi @ dan tetapkan nilai kepada nama fungsi @

yang diwakili oleh fungsi

Kerana tindakan ini hampir sama dengan hiasan (pengubahsuaian, pengembangan, pelarasan, sekatan...) asli bar, jadi ia dipanggil penghias:

Secara takrifan, penghias ialah fungsi yang mengambil fungsi lain dan memanjangkan gelagat fungsi terakhir tanpa mengubahnya secara eksplisit.

Walaupun

dikatakan sebagai hiasan, bar yang dilaksanakan bukan lagi orang yang sama seperti bar asal foo akan mengembalikan objek baru, biasanya fungsi, tetapi kemungkinan besar adalah benda yang dikembalikan tiada apa-apa pun

def foo(func):
    return None

@foo
def bar():
    ...
Dalam contoh di atas,

telah menjadi penghias yang sangat aneh, kerana apa yang dikembalikan adalah foo, yang bukan sahaja tidak mempunyai hiasan, tetapi juga memusnahkan fungsiNone

Berbalik kepada contoh yang anda berikan pada permulaan:

def foo(func):
    print('foo')
    func()

@foo
def func_a():
    print('func_a')

func_a()

anda tidak mempunyai pernyataan foo, yang bermaksud bahawa return akan mengembalikan foo Apa yang anda tulis pada dasarnya adalah pemusnah (gurau sahaja Kesan yang anda lihat hanyalah jangka pendek). ilusi. Itu kerana Apabila sintaks None dimainkan, sintaks @ dilaksanakan print

Tetapi anda boleh cuba memanggil

, anda akan mendapati bahawa ralat ditimbulkan, kerana func_a bukan fungsi sama sekali, dan sudah tentu kesan yang anda ingin capai tidak boleh digunakan semula func_a


Penghias tidak semestinya perlu menggunakan fungsi tempatan atau fungsi bersarang, tetapi kami biasanya membiarkan penghias mengembalikan fungsi. Lagipun, kita semua secara intuitif memikirkan fungsi yang dihias

Terdapat beribu-ribu penghias, dan sesetengahnya memang boleh menggunakan satu lapisan sarang, seperti mendaftar fungsi:

registry = []

def register(func):
    print('register {}'.format(func))
    registry.append(func)
    return func  # 還是應該要 return func
Sebabnya tindakan ini hanya perlu diproses sekali semasa dekorasi Anda tidak mahu mendaftarkannya setiap kali anda memanggil fungsi yang kami perlukan.

Tetapi untuk tindakan seperti

log pencetakan atau mengira masa dan lain-lain, kami masih perlu menggunakan teknik bersarang, kerana kami ingin mencetak dan mengira setiap kali kami memanggil fungsi need ialah fungsi baharu. Fungsi ini dicipta oleh fungsi tempatan, yang pasti akan menghasilkan lata dan bersarang Terdapat juga beberapa penghias yang lebih kompleks dengan parameter yang mungkin menggunakan lebih daripada dua peringkat bersarang

Ringkasan

Sama ada anda mahu bersarang atau tidak bergantung pada tujuan, tetapi pastikan anda ingat untuk mengembalikan fungsi selepas hiasan


Soalan yang saya jawab: Python-QA

迷茫

Mungkin anda semua tidak faham apa yang saya maksudkan. Idea saya ini agak mengelirukan Lapisan fungsi sudah mencukupi pada kehebatan corak reka bentuk ini. Kaedah penaakulan terbalik yang digunakan adalah untuk menjelaskan keperluan asas dan kemudian membuat alasan ke belakang untuk memahami mengapa setiap langkah ditulis sedemikian.

def outer(func):          #3.此处关键了,因为我们是倒推,下面的结构已经固定了,
    def inner(x):         #outer(f1)返回给f1的值,必须是一个函数!outer自己也是函数
        print('loding')   #可以返回自己嘛!但是注意哦,它已经有且必须有一个func参数,来传递原生函数名
        func(x)        #也就是f1函数名变量的入口,那么他返回给新的f1函数,就会使原生函数多个参数,
        print('Done')     #改变我们最初的目的,新f1与老f1调用方法要无区别,那么咋整
    return inner          #嵌套一个函数inner,他接收f1参数,外层outer接收函数名f1
def f1(x):                #至此装饰器是两层函数嵌套,当f1没有参数时,依然需要双层
    print('f1 func',x)    #因为必须返回一个函数,返回outer本身,就需要加func参数
@outer                    #而我们又追求不改变原生调用f1(),他是没有参数的
def f2(x):                #所以一个装饰器必须至少双层函数嵌套,第一层传递原生函数名
    print('f2 func',x)    #第二层执行装饰功能,这设计真是牛逼,逆推一晚上才有点理解。
@outer                   
def f3(x):
    print('f3 func',x)
                          #2.那么F1要指向一个新函数
                          #并且这个函数能被F2 F3都指向
f1  = outer(f1)              #所以它是一个可以传递函数名变量的函数
#f1 = outer(f1('tings'))  #ps:带上参数一起传递,这也是一种可能,但是没有价值,
                          #装饰器使用时每个都要写一遍,其实就已经不是原生方法调用了,
                          #因为要给语法糖@输送'things'参数,不符合我们初衷。
                          
f1('tings1')              #1.首先明确我们的根本需求,外部调用方法要完全相同,这也是装饰器的意义。
f2('tings2')
f3('tings3')
Ty80
    Penghias
  1. berlaku dalam 定义 dan bukannya fasa 执行

  2. Fungsi penghias outer mesti mengembalikan 被装饰的函数, ambil perhatian bahawa ia mesti mengembalikan 定义, bukan 调用

Penjelasan terperinci di tingkat bawah sangat bagus.

刘奇

Mesti ramai yang pernah kongsikan ini Saya juga pernah menulis blog sebelum ini

Penjelasan terperinci tentang penghias Python

PHPzhong
@foo
def bar()

Bersamaan dengan bar = foo(bar), faham sahaja ini

PHPzhong

Tingkat dua betul, fungsi sudah dilaksanakan apabila menetapkan nilai pada bar.

Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan