目次
1. 終わりに
function 5
五、带参数的装饰器
六、使用类作为装饰器
七、内置装饰器
7.1 @classmethod
7.2 @staticmethod
7.3 @property
ホームページ バックエンド開発 Python チュートリアル Pythonのデコレーターの知識ポイントをまとめます。

Pythonのデコレーターの知識ポイントをまとめます。

Jun 17, 2022 pm 01:50 PM
python

この記事では、python に関する関連知識を提供します。主に、クロージャ、デコレータ、複数のデコレータの使用、パラメータなど、デコレータに関する関連問題を紹介します。デコレータとその他の内容については、以下で見てみましょう。 . 皆様のお役に立てれば幸いです。

Pythonのデコレーターの知識ポイントをまとめます。

推奨される学習: Python ビデオ チュートリアル

1. 終わりに

Decorator とは何かを理解するには (デコレータ) では、まず クロージャ (クロージャ) の概念を知る必要があります。

クロージャ (クロージャ関数または閉じた関数とも呼ばれます) は、一般的に、関数がオブジェクトとして返され、外部変数も同伴すると、クロージャが形成されます。

Hello World の印刷を例として、ネストされた関数の構造がどのようになるかを見てみましょう:

def print_msg(msg):

    def printer():
        print(msg)

    printer()print_msg('Hello World')# Hello World
ログイン後にコピー
Execution

print_msg('Hello World') printer()を実行したこと、つまりprint(msg)を実行したことと同じなので、Hello Worldが出力されます。

これがクロージャである場合にどのような構造になるかを見てみましょう:

def print_msg(msg):

    def printer():
        print(msg)

    return printer


my_msg = print_msg('Hello World')my_msg()# Hello World
ログイン後にコピー
この例の

printer 関数はクロージャです。

Execution

print_msg('Hello World') は実際には次のような関数を返します。これは外部変数を同伴します 'Hello World':

def printer():
    print('Hello World')
ログイン後にコピー
したがって、

my_msg の呼び出しは、printer() の実行と同じです。


では、関数がクロージャ関数であるかどうかを判断するにはどうすればよいでしょうか?クロージャ関数の

__closure__ 属性は、すべてのセル オブジェクトを格納するためのタプルを定義します。各セル オブジェクトは、すべての外部変数をクロージャに格納します。通常の関数の __closure__ 属性は None です。

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>,)
ログイン後にコピー

outer 関数はクロージャではなく、inner 関数はクロージャであることがわかります。

クロージャによって運ばれる外部変数を表示することもできます:

print(inner.__closure__[0].cell_contents)# Hello World
ログイン後にコピー

ここまでお話しましたが、クロージャは何に役立つのでしょうか?クロージャの存在意義は、外部変数(プライベートグッズ)を運ぶことにあり、プライベートグッズを持たない場合は、通常の関数と変わりません。

クロージャの利点は次のとおりです:

    ローカル変数は共有したり長期間保存したりすることができませんが、グローバル変数は変数汚染を引き起こす可能性があります。地球規模の汚染。
  • クロージャーを使用すると、関数内のローカル変数の値を常にメモリ内に残すことができ、外部関数の呼び出し後に自動的にクリアされなくなります。
2. デコレータ

まず、そのようなシナリオを考えてみましょう。以前に作成した関数が 4 つの関数を実装していると仮定します。簡単にするために、

print ステートメントを使用して、それぞれの特定の関数を表します:

def module():
    print('功能1')
    print('功能2')
    print('功能3')
    print('功能4')
ログイン後にコピー
さて、何らかの理由で、

関数 5module 関数に追加する必要があります。これは次のように変更できます。

def module():
    print('功能1')
    print('功能2')
    print('功能3')
    print('功能4')
    print('功能5')
ログイン後にコピー
しかし、実際のビジネスでは、このような変更を直接行うのは危険なことがよくあります (保守が困難になります)。では、

元の関数を変更せずに新しい関数を追加するにはどうすればよいでしょうか?

以前のクロージャの知識を使用することを考えたかもしれません:

def func_5(original_module):

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

    return wrapper
ログイン後にコピー

func_5 は、関数が主に function 5## を実装するために使用されることを意味します。 # 、次に module を渡して効果を観察します: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">new_module = func_5(module)new_module()# 功能1# 功能2# 功能3# 功能4# 功能5</pre><div class="contentsignin">ログイン後にコピー</div></div> 新しいモジュール:

new_module

function 5 # を実装していることがわかります。 ##。 上記の例では、関数

func_5
はデコレータであり、元のモジュールを装飾します (新しい関数を追加します)。

もちろん、Python にはより簡潔な記述方法 (構文シュガーと呼ばれる) があり、@ 記号をデコレーター関数の名前とともに使用し、それを関数の定義に配置することができます。装飾済み 上:

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
ログイン後にコピー

これに基づいて、次のように、元の関数を変更せずにタイミング タスク (元の関数の実行時間の計算) を完了できます。実際、

my_list
はリストではありません。直接印刷すると、

None

と表示されます。これは、

wrapper 関数が戻り値を設定しないためです。 make_list の戻り値を取得する必要がある場合は、wrapper 関数を次のように変更できます:

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
ログイン後にコピー
3. 複数のデコレータを使用します module 新しく追加された

function 5

function 6 (番号順) を実行したい場合はどうすればよいでしょうか? 幸いなことに、Python では複数のデコレータを同時に使用できます:

def wrapper():
    import time
    tic = time.time()
    a = func()
    toc = time.time()
    print('程序用时: {}s'.format(toc - tic))
    return a
ログイン後にコピー
上記のプロセスは実際には次と同等です:
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
ログイン後にコピー
さらに、次のことに注意してください。複数のデコレータを使用する場合 デコレータを装飾する場合、

関数定義に最も近いデコレータが最初に関数を装飾します

装飾順序を変更すると、出力結果も変わります:

def module():
    print('功能1')
    print('功能2')
    print('功能3')
    print('功能4')new_module = func_6(func_5(module))new_module()
ログイン後にコピー
4 . パラメータ付きの装飾された関数

装飾された関数にパラメータがある場合、デコレーターを構築する方法は?

次のような関数を考えてみましょう:

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视频教程

以上がPythonのデコレーターの知識ポイントをまとめます。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

mysqlは支払う必要がありますか mysqlは支払う必要がありますか Apr 08, 2025 pm 05:36 PM

MySQLには、無料のコミュニティバージョンと有料エンタープライズバージョンがあります。コミュニティバージョンは無料で使用および変更できますが、サポートは制限されており、安定性要件が低く、技術的な能力が強いアプリケーションに適しています。 Enterprise Editionは、安定した信頼性の高い高性能データベースを必要とするアプリケーションに対する包括的な商業サポートを提供し、サポートの支払いを喜んでいます。バージョンを選択する際に考慮される要因には、アプリケーションの重要性、予算編成、技術スキルが含まれます。完璧なオプションはなく、最も適切なオプションのみであり、特定の状況に応じて慎重に選択する必要があります。

インストール後にMySQLの使用方法 インストール後にMySQLの使用方法 Apr 08, 2025 am 11:48 AM

この記事では、MySQLデータベースの操作を紹介します。まず、MySQLWorkBenchやコマンドラインクライアントなど、MySQLクライアントをインストールする必要があります。 1. mysql-uroot-pコマンドを使用してサーバーに接続し、ルートアカウントパスワードでログインします。 2。CreatedAtaBaseを使用してデータベースを作成し、データベースを選択します。 3. createTableを使用してテーブルを作成し、フィールドとデータ型を定義します。 4. INSERTINTOを使用してデータを挿入し、データをクエリし、更新することでデータを更新し、削除してデータを削除します。これらの手順を習得することによってのみ、一般的な問題に対処することを学び、データベースのパフォーマンスを最適化することでMySQLを効率的に使用できます。

MySQLダウンロードファイルが破損しており、インストールできません。修復ソリューション MySQLダウンロードファイルが破損しており、インストールできません。修復ソリューション Apr 08, 2025 am 11:21 AM

mysqlダウンロードファイルは破損していますが、どうすればよいですか?残念ながら、MySQLをダウンロードすると、ファイルの破損に遭遇できます。最近は本当に簡単ではありません!この記事では、誰もが迂回を避けることができるように、この問題を解決する方法について説明します。それを読んだ後、損傷したMySQLインストールパッケージを修復するだけでなく、将来の行き詰まりを避けるために、ダウンロードとインストールプロセスをより深く理解することもできます。最初に、ファイルのダウンロードが破損した理由について話しましょう。これには多くの理由があります。ネットワークの問題は犯人です。ダウンロードプロセスの中断とネットワーク内の不安定性は、ファイル腐敗につながる可能性があります。ダウンロードソース自体にも問題があります。サーバーファイル自体が壊れており、もちろんダウンロードすると壊れています。さらに、いくつかのウイルス対策ソフトウェアの過度の「情熱的な」スキャンもファイルの破損を引き起こす可能性があります。診断問題:ファイルが本当に破損しているかどうかを判断します

MySQLはダウンロード後にインストールできません MySQLはダウンロード後にインストールできません Apr 08, 2025 am 11:24 AM

MySQLのインストール障害の主な理由は次のとおりです。1。許可の問題、管理者として実行するか、SUDOコマンドを使用する必要があります。 2。依存関係が欠落しており、関連する開発パッケージをインストールする必要があります。 3.ポート競合では、ポート3306を占めるプログラムを閉じるか、構成ファイルを変更する必要があります。 4.インストールパッケージが破損しているため、整合性をダウンロードして検証する必要があります。 5.環境変数は誤って構成されており、環境変数はオペレーティングシステムに従って正しく構成する必要があります。これらの問題を解決し、各ステップを慎重に確認して、MySQLを正常にインストールします。

MySQLインストール後に開始できないサービスのソリューション MySQLインストール後に開始できないサービスのソリューション Apr 08, 2025 am 11:18 AM

MySQLは開始を拒否しましたか?パニックにならないでください、チェックしてみましょう!多くの友人は、MySQLのインストール後にサービスを開始できないことを発見し、彼らはとても不安でした!心配しないでください、この記事はあなたがそれを落ち着いて対処し、その背後にある首謀者を見つけるためにあなたを連れて行きます!それを読んだ後、あなたはこの問題を解決するだけでなく、MySQLサービスの理解と問題のトラブルシューティングのためのあなたのアイデアを改善し、より強力なデータベース管理者になることができます! MySQLサービスは開始に失敗し、単純な構成エラーから複雑なシステムの問題に至るまで、多くの理由があります。最も一般的な側面から始めましょう。基本知識:サービススタートアッププロセスMYSQLサービススタートアップの簡単な説明。簡単に言えば、オペレーティングシステムはMySQL関連のファイルをロードし、MySQLデーモンを起動します。これには構成が含まれます

高負荷アプリケーションのMySQLパフォーマンスを最適化する方法は? 高負荷アプリケーションのMySQLパフォーマンスを最適化する方法は? Apr 08, 2025 pm 06:03 PM

MySQLデータベースパフォーマンス最適化ガイドリソース集約型アプリケーションでは、MySQLデータベースが重要な役割を果たし、大規模なトランザクションの管理を担当しています。ただし、アプリケーションのスケールが拡大すると、データベースパフォーマンスのボトルネックが制約になることがよくあります。この記事では、一連の効果的なMySQLパフォーマンス最適化戦略を検討して、アプリケーションが高負荷の下で効率的で応答性の高いままであることを保証します。実際のケースを組み合わせて、インデックス作成、クエリ最適化、データベース設計、キャッシュなどの詳細な主要なテクノロジーを説明します。 1.データベースアーキテクチャの設計と最適化されたデータベースアーキテクチャは、MySQLパフォーマンスの最適化の基礎です。いくつかのコア原則は次のとおりです。適切なデータ型を選択し、ニーズを満たす最小のデータ型を選択すると、ストレージスペースを節約するだけでなく、データ処理速度を向上させることもできます。

MySQLインストール後にデータベースのパフォーマンスを最適化する方法 MySQLインストール後にデータベースのパフォーマンスを最適化する方法 Apr 08, 2025 am 11:36 AM

MySQLパフォーマンスの最適化は、インストール構成、インデックス作成、クエリの最適化、監視、チューニングの3つの側面から開始する必要があります。 1。インストール後、INNODB_BUFFER_POOL_SIZEパラメーターやclose query_cache_sizeなど、サーバーの構成に従ってmy.cnfファイルを調整する必要があります。 2。過度のインデックスを回避するための適切なインデックスを作成し、説明コマンドを使用して実行計画を分析するなど、クエリステートメントを最適化します。 3. MySQL独自の監視ツール(ShowProcessList、ShowStatus)を使用して、データベースの健康を監視し、定期的にデータベースをバックアップして整理します。これらの手順を継続的に最適化することによってのみ、MySQLデータベースのパフォーマンスを改善できます。

mysqlはインターネットが必要ですか? mysqlはインターネットが必要ですか? Apr 08, 2025 pm 02:18 PM

MySQLは、基本的なデータストレージと管理のためにネットワーク接続なしで実行できます。ただし、他のシステムとのやり取り、リモートアクセス、または複製やクラスタリングなどの高度な機能を使用するには、ネットワーク接続が必要です。さらに、セキュリティ対策(ファイアウォールなど)、パフォーマンスの最適化(適切なネットワーク接続を選択)、およびデータバックアップは、インターネットに接続するために重要です。

See all articles