Rumah >pembangunan bahagian belakang >Tutorial Python >Ringkaskan mata pengetahuan penghias dalam Python

Ringkaskan mata pengetahuan penghias dalam Python

WBOY
WBOYke hadapan
2022-06-17 13:50:402397semak imbas

Artikel ini membawakan anda pengetahuan yang berkaitan tentang python, yang terutamanya memperkenalkan isu yang berkaitan dengan penghias, termasuk penutupan, penghias, menggunakan berbilang penghias dan penghias serta kandungan lain, mari kita lihat di bawah Saya harap ia akan membantu semua orang.

Ringkaskan mata pengetahuan penghias dalam Python

Pembelajaran yang disyorkan: tutorial video python

1

(penghias), kita perlu tahu dulu konsep

penutupan (penutupan). Penutupan, juga dikenali sebagai fungsi penutupan atau fungsi tertutup Dalam istilah awam, apabila fungsi dikembalikan sebagai objek dan juga melibatkan pembolehubah luaran, penutupan terbentuk.

Mengambil percetakan Hello World sebagai contoh, mari kita lihat dahulu bagaimana struktur fungsi bersarang sepatutnya kelihatan:

Melaksanakan

adalah bersamaan dengan melaksanakan
def print_msg(msg):

    def printer():
        print(msg)

    printer()print_msg('Hello World')# Hello World
. Iaitu,

dilaksanakan, jadi print_msg('Hello World') akan menjadi output. printer()print(msg)Mari kita lihat jenis strukturnya jika ia adalah penutupan: Hello World

Fungsi
def print_msg(msg):

    def printer():
        print(msg)

    return printer


my_msg = print_msg('Hello World')my_msg()# Hello World
dalam contoh ini ialah penutupan.

printerMelaksanakan

sebenarnya mengembalikan fungsi seperti berikut, yang memasukkan pembolehubah luaran
:

print_msg('Hello World')'Hello World'Jadi memanggil

adalah bersamaan dengan melaksanakan
def printer():
    print('Hello World')
.

my_msgprinter()Jadi bagaimana untuk menentukan sama ada fungsi ialah fungsi penutupan? Atribut

bagi fungsi penutupan mentakrifkan tuple untuk menyimpan semua objek sel Setiap objek sel menyimpan semua pembolehubah luaran dalam penutupan. Atribut
bagi fungsi normal ialah

. __closure____closure__NoneDapat dilihat bahawa fungsi

bukanlah penutup, tetapi fungsi
def outer(content):

    def inner():
        print(content)

    return innerprint(outer.__closure__)
    # Noneinner = outer('Hello World')print(inner.__closure__)
    # (<cell at 0x0000023FB1FD0B80: str object at 0x0000023FB1DC84F0>,)
ialah penutup.

outerKita juga boleh melihat pembolehubah luaran yang dibawa oleh penutupan: inner

Setelah berkata begitu banyak, apakah kegunaan penutupan? Maksud kewujudan penutupan ialah ia membawa pembolehubah luaran (barang persendirian) Jika ia tidak membawa barang persendirian, maka ia tidak berbeza dengan fungsi biasa.
print(inner.__closure__[0].cell_contents)# Hello World

Kelebihan penutupan adalah seperti berikut:

Pembolehubah setempat tidak boleh dikongsi dan disimpan untuk masa yang lama, manakala pembolehubah global mungkin menyebabkan pencemaran berubah-ubah boleh menjimatkan pembolehubah untuk jangka masa yang lama masa tanpa menyebabkan pencemaran global.

    Penutupan membenarkan nilai pembolehubah tempatan dalam fungsi sentiasa disimpan dalam ingatan dan tidak akan dikosongkan secara automatik selepas fungsi luaran dipanggil.
  • 2. Penghias
Mula-mula kita pertimbangkan senario sedemikian Anggapkan bahawa fungsi yang ditulis sebelum ini telah melaksanakan 4 fungsi Untuk memudahkan, kami menggunakan pernyataan

untuk Mewakili setiap khusus fungsi:

printSekarang, atas sebab tertentu, anda perlu menambah

baharu pada fungsi
def module():
    print('功能1')
    print('功能2')
    print('功能3')
    print('功能4')
Anda boleh mengubah suainya seperti ini:

module 功能5Tetapi dalam perniagaan sebenar, selalunya berbahaya untuk membuat pengubahsuaian sedemikian secara langsung (ia akan menjadi sukar untuk dikekalkan). Jadi

bagaimana untuk menambah fungsi baharu padanya tanpa mengubah suai fungsi asal?
def module():
    print('功能1')
    print('功能2')
    print('功能3')
    print('功能4')
    print('功能5')

Anda mungkin terfikir untuk menggunakan pengetahuan penutupan sebelumnya:

bermakna fungsi ini digunakan terutamanya untuk melaksanakan
def func_5(original_module):

    def wrapper():
        original_module()
        print('功能5')

    return wrapper
, kami akan seterusnya

Hantarkannya untuk melihat kesan: func_5功能5module Dapat dilihat bahawa modul baharu kami:

telah dilaksanakan
new_module = func_5(module)new_module()# 功能1# 功能2# 功能3# 功能4# 功能5
.

new_module功能5Dalam contoh di atas, fungsi

ialah penghias, yang menghiasi modul asal (menambah fungsi baharu padanya).

func_5Sudah tentu Python mempunyai cara penulisan yang lebih ringkas (dipanggil syntax sugar), kita boleh menggunakan simbol @ dengan nama fungsi penghias dan meletakkannya dalam definisi fungsi yang akan dihiasi Di Atas:

Berdasarkan ini, kita boleh menyelesaikan tugas pemasaan (mengira masa berjalan fungsi asal) tanpa mengubah suai fungsi asal, seperti berikut:
def func_5(original_module):

    def wrapper():
        original_module()
        print('功能5')

    return wrapper@func_5def module():
    print('功能1')
    print('功能2')
    print('功能3')
    print('功能4')module()# 功能1# 功能2# 功能3# 功能4# 功能5

Sebenarnya,

bukan senarai Cetakan langsung akan memaparkan
def timer(func):

    def wrapper():
        import time
        tic = time.time()
        func()
        toc = time.time()
        print('程序用时: {}s'.format(toc - tic))

    return wrapper@timerdef make_list():
    return [i * i for i in range(10**7)]my_list = make_list()# 程序用时: 0.8369960784912109s
Ini kerana fungsi

kami tidak menetapkan nilai pulangan. Jika anda perlu mendapatkan nilai pulangan my_list, anda boleh mengubah suai fungsi None seperti ini: wrappermake_listwrapper3 Gunakan berbilang penghias

def wrapper():
    import time
    tic = time.time()
    a = func()
    toc = time.time()
    print('程序用时: {}s'.format(toc - tic))
    return a
Jika kita ingin menambah a baharu

🎜> dan

(dalam susunan berangka), jadi apa yang perlu dilakukan?

moduleNasib baik, Python membenarkan penggunaan berbilang penghias pada masa yang sama: 功能5功能6

Proses di atas sebenarnya bersamaan dengan:

def func_5(original_module):
    def wrapper():
        original_module()
        print('功能5')
    return wrapperdef func_6(original_module):
    def wrapper():
        original_module()
        print('功能6')
    return wrapper@func_6@func_5def module():
    print('功能1')
    print('功能2')
    print('功能3')
    print('功能4')module()# 功能1# 功能2# 功能3# 功能4# 功能5# 功能6
Selain itu, ia perlu diingat bahawa, Apabila menggunakan berbilang penghias,

penghias yang paling hampir dengan definisi fungsi akan menghiasi fungsi terlebih dahulu

Jika kita menukar susunan hiasan, hasil output juga akan berubah:
def module():
    print('功能1')
    print('功能2')
    print('功能3')
    print('功能4')new_module = func_6(func_5(module))new_module()

4. Fungsi yang dihias mempunyai parameter

Jika fungsi yang dihias mempunyai parameter, bagaimana untuk membina penghias?
@func_5@func_6def module():
    print('功能1')
    print('功能2')
    print('功能3')
    print('功能4')module()# 功能1# 功能2# 功能3# 功能4# 功能6# 功能5

Pertimbangkan fungsi seperti ini:

def pide(a, b):
    return a / b

b=0 时会出现 ZeropisionError。如何在避免修改该函数的基础上给出一个更加人性化的提醒呢?

因为我们的 pide 函数接收两个参数,所以我们的 wrapper 函数也应当接收两个参数:

def smart_pide(func):
    def wrapper(a, b):
        if b == 0:
            return '被除数不能为0!'
        else:
            return func(a, b)
    return wrapper

使用该装饰器进行装饰:

@smart_pidedef pide(a, b):
    return a / bprint(pide(3, 0))# 被除数不能为0!print(pide(3, 1))# 3.0

如果不知道要被装饰的函数有多少个参数,我们可以使用下面更为通用的模板:

def decorator(func):
    def wrapper(*args, **kwargs):
        # ...
        res = func(*args, **kwargs)
        # ...
        return res  # 也可以不return
    return wrapper

五、带参数的装饰器

我们之前提到的装饰器都没有带参数,即语法糖 @decorator 中没有参数,那么该如何写一个带参数的装饰器呢?

前面实现的装饰器都是两层嵌套函数,而带参数的装饰器是一个三层嵌套函数。

考虑这样一个场景。假如我们在为 module 添加新功能时,希望能够加上实现该功能的开发人员的花名,则可以这样构造装饰器(以 功能5 为例):

def func_5_with_name(name=None):
    def func_5(original_module):
        def wrapper():
            original_module()
            print('功能5由{}实现'.format(name))
        return wrapper    return func_5

效果如下:

@func_5_with_name(name='若水')def module():
    print('功能1')
    print('功能2')
    print('功能3')
    print('功能4')module()# 功能1# 功能2# 功能3# 功能4# 功能5由若水实现

对于这种三层嵌套函数,我们可以这样理解:当为 func_5_with_name 指定了参数后,func_5_with_name(name='若水') 实际上返回了一个 decorator,于是 @func_5_with_name(name='若水') 就相当于 @decorator

六、使用类作为装饰器

将类作为装饰器,我们需要实现 __init__ 方法和 __call__ 方法。

以计时器为例,具体实现如下:

class Timer:

    def __init__(self, func):
        self.func = func    def __call__(self):
        import time
        tic = time.time()
        self.func()
        toc = time.time()
        print('用时: {}s'.format(toc - tic))@Timerdef make_list():
    return [i**2 for i in range(10**7)]make_list()# 用时: 2.928966999053955s

如果想要自定义生成列表的长度并获得列表(即被装饰的函数带有参数情形),我们就需要在 __call__ 方法中传入相应的参数,具体如下:

class Timer:

    def __init__(self, func):
        self.func = func    def __call__(self, num):

        import time
        tic = time.time()
        res = self.func(num)
        toc = time.time()
        print('用时: {}s'.format(toc - tic))

        return res@Timerdef make_list(num):
    return [i**2 for i in range(num)]my_list = make_list(10**7)# 用时: 2.8219943046569824sprint(len(my_list))# 10000000

如果要构建带参数的类装饰器,则不能把 func 传入 __init__ 中,而是传入到 __call__ 中,同时 __init__ 用来初始化类装饰器的参数。

接下来我们使用类装饰器来复现第五章节中的效果:

class Func_5:

    def __init__(self, name=None):
        self.name = name    def __call__(self, func):

        def wrapper():
            func()
            print('功能5由{}实现'.format(self.name))

        return wrapper@Func_5('若水')def module():
    print('功能1')
    print('功能2')
    print('功能3')
    print('功能4')module()# 功能1# 功能2# 功能3# 功能4# 功能5由若水实现

七、内置装饰器

Python中有许多内置装饰器,这里仅介绍最常见的三种:@classmethod@staticmethod@property

7.1 @classmethod

@classmethod 用于装饰类中的函数,使用它装饰的函数不需要进行实例化也可调用。需要注意的是,被装饰的函数不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,它可以来调用类的属性,类的方法,实例化对象等。

cls 代表类本身,self 代表实例本身。

具体请看下例:

class A:

    num = 100

    def func1(self):
        print('功能1')

    @classmethod
    def func2(cls):
        print('功能2')
        print(cls.num)
        cls().func1()A.func2()# 功能2# 100# 功能1

7.2 @staticmethod

@staticmethod 同样用来修饰类中的方法,使用它装饰的函数的参数没有任何限制(即无需传入 self 参数),并且可以不用实例化调用该方法。当然,实例化后调用该方法也是允许的。

具体如下:

class A:

    @staticmethod
    def add(a, b):
        return a + bprint(A.add(2, 3))# 5print(A().add(2, 3))# 5

7.3 @property

使用 @property 装饰器,我们可以直接通过方法名来访问类方法,不需要在方法名后添加一对 () 小括号。

class A:

    @property
    def printer(self):
        print('Hello World')a = A()a.printer# Hello World

除此之外,@property 还可以用来防止类的属性被修改。考虑如下场景

class A:

    def __init__(self):
        self.name = 'ABC'a = A()print(a.name)# ABCa.name = 1print(a.name)# 1

可以看出类中的属性 name 可以被随意修改。如果要防止修改,则可以这样做

class A:

    def __init__(self):
        self.name_ = 'ABC'

    @property
    def name(self):
        return self.name_
    
    
a = A()print(a.name)# ABCa.name = 1print(a.name)# AttributeError: can't set attribute

推荐学习:python视频教程

Atas ialah kandungan terperinci Ringkaskan mata pengetahuan penghias dalam Python. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:csdn.net. Jika ada pelanggaran, sila hubungi admin@php.cn Padam