ホームページ  >  記事  >  バックエンド開発  >  Python プログラミング: コンテキスト マネージャーを簡単に理解する (コンテキスト マネージャー)

Python プログラミング: コンテキスト マネージャーを簡単に理解する (コンテキスト マネージャー)

PHPz
PHPz転載
2023-04-12 14:07:132282ブラウズ

はじめに

この記事は、Python コンテキスト管理の説明と応用に焦点を当てています。または、「より高速に、より経済的に」を理解し、習得し、応用するために、コード例、比較理解、学習を通じて。早速、始めましょう——

1. コンテキスト マネージャーとは

コンテキスト マネージャーは、コンテキスト マネージャーの実行時に作成されるコンテキスト マネージャーを定義するオブジェクトです。 with ステートメント。実行時コンテキスト。コンテキスト マネージャーは、コード ブロックが実行されるコンテキストの開始と終了を自動的に処理するランタイムです。コンテキスト マネージャーは通常、with ステートメントを使用して呼び出されますが、メソッドを直接呼び出して使用することもできます。

コンテキスト マネージャーの一般的な用途には、さまざまなグローバル状態の保存と復元、リソースのロックとロック解除、開いているファイルのクローズなどが含まれます。

この章では、Python でコンテキスト マネージャーを使用する方法と、コンテキスト マネージャーをカスタマイズする方法を学習します。

1.With ステートメント

with ステートメントは、コンテキスト マネージャーによって定義されたメソッド ラッピング ブロックの実行に使用されます。これにより、簡単に再利用できるよう、一般的な try...excel...finally の使用パターンをカプセル化できます。 with ステートメントは、従来の try...excel...finally ブロックと比較して、短くて再利用可能なコードを提供します。

Python 標準ライブラリでは、多くのクラスが with ステートメントをサポートしています。非常に一般的な例は、組み込みの open() 関数です。この関数は、with ステートメントを使用してファイル オブジェクトを処理するためのパターンを提供します。

次に、with ステートメントの一般的な構文を示します。

with expression as target:
# 使用target
# 来处理事情

open() 関数の使用例を見てみましょう。現在のプロジェクトのファイルフォルダーにテキストファイルがあります。ファイル名は color_names.txt で、これにはいくつかの色の名前が含まれています (テキスト コンテンツを自分で指定できます)。 open() 関数と with ステートメントを使用して、このファイルの内容を開いて印刷したいと考えています。コード例は次のとおりです。

import os
fileDirPath = os.getcwd()+os.sep+"ctxManager"+os.sep #自定义文件路径
# 指定文件路径和名称
path = fileDirPath+'files/color_names.txt'

# with 语句
with open(path, mode='r') as file:
# 读取文件内容
print(file.read())

プログラムを実行した場合の出力結果は次のとおりです。

red
orange
yellow
green
blue
white
black

上記のリストでは、with ステートメントの一般的な使用例が示されています。 open() 関数を使用して、指定されたパス (path) 上のファイルを開きます。open() 関数は、読み取り専用モードでファイル オブジェクトを返します。次に、コードはこのファイル オブジェクトを使用して、コード print(file.read()) を通じてその内容を読み取り、出力します。

上記の例は、コンテキスト マネージャーの一般的な使用法です。コンテキスト マネージャーをよりよく理解し、適用するには、読み続ける必要があります。

3. コンテキスト マネージャー プロトコル

コンテキスト マネージャー プロトコル (Context Manager Protocol) は、端的に言えば、コンテキスト マネージャーの処理メカニズム、または所定のプロトコル規格です。この部分は、Python Core Protocol にもあります。読書の自立のために、ここでもう一度話しましょう。

Python の with ステートメントは、コンテキスト マネージャーによって定義されるランタイム コンテキストの概念をサポートします。これは、ステートメント本体が実行される前に入力され、ステートメントの最後に終了する実行時コンテキストをユーザー定義クラスで定義できるようにする 1 対のメソッドによって実現されます。

前述のメソッドは、コンテキスト マネージャー プロトコルと呼ばれます。これら 2 つのメソッドを詳しく見てみましょう:

1) __enter__(self)

このメソッドは、現在のコンテキストに関連するランタイム コンテキストを入力するために with ステートメントによって呼び出されます。物体 。 with ステートメントは、このメソッドの戻り値を、ステートメントの as 句で指定されたターゲット (存在する場合) にバインドします。

上記の例で返されるコンテキスト マネージャーはファイル オブジェクトです。バックグラウンドでは、ファイル オブジェクトは __enter__() から自身を返し、open() を with ステートメント内のコンテキスト式として使用できるようにします。

2)__exit__(self、exc_type、exc_value、traceback):

このメソッドは、実行が with コード ブロックを離れるときに呼び出されます。このオブジェクトに関連付けられたランタイム コンテキストを終了します。パラメータは、コンテキストを終了させる原因となった例外情報を記述します。コンテキストが例外なく終了した場合、3 つのパラメータはすべて None になります。

例外が提供され、メソッドで例外を抑制する (つまり、例外が伝播されるのを防ぐ) 場合は、True 値を返す必要があります。それ以外の場合、例外はこのメソッドを終了するときに通常どおり処理されます。 __exit__() メソッドは、True または False のブール値を返します。

コンテキスト マネージャー プロトコルのメソッドを使用して with ステートメントを実行するプロセスは次のとおりです。

with EXPRESSION as TARGET:
SUITE
  • コンテキスト式 (EXPRESSION) を計算してコンテキスト マネージャーを取得します。
  • 後で使用するためにコンテキスト マネージャーの __enter__() をロードします。
  • 後で使用するためにコンテキスト マネージャーの __exit__() をロードします。
  • コンテキスト マネージャーの __enter__() メソッドを呼び出します。
  • with ステートメントに TARGET が含まれている場合、__enter__() の戻り値がそれに代入されます。
  • 実行スイート (with ステートメントのスコープ内のコード ブロック)。
  • コンテキスト マネージャーの __exit__() メソッドを呼び出します。例外によってスイートが終了した場合、そのタイプ、値、およびトレースバックが引数として __exit__() に渡されます。それ以外の場合は、3 つの None パラメータが提供されます。

例外以外の何らかの理由でスイートが終了した場合、__exit__() の戻り値は無視され、後続のコード (存在する場合) の実行は、実行されている終了タイプの通常の位置で続行されます。 。

4. クラス形式のコンテキスト マネージャー

コンテキスト マネージャー プロトコルの背後にある基本的な考え方を理解したので、それをクラスに実装してみましょう。このクラスはコンテキスト マネージャーとなり、後ほど with ステートメントで使用します。

定义的上下文管理器类参考示例清单如下:

# 自定义上下文管理器类
class CustomContextManager:
# 初始化方法init -> 定义一些变量
def __init__(self, path, mode):
self.path = path
self.mode = mode
self.file = None

# __enter__ method -> open the file
def __enter__(self):
self.file = open(self.path, self.mode)
return self.file

# exit method to close the file

def __exit__(self, exc_type, exc_value,exc_traceback):
self.file.close()

我们的CustomContextManager类实现了成为上下文管理器的必要方法:__enter__和__exit__。

在__init__方法中,它定义了三个实例变量来存储路径、模式和文件对象。

在__enter__方法中,它使用内置的open()函数打开指定路径中的文件。由于open()函数返回file对象,我们将其赋值给self.file属性。

在__exit__方法中,我们将文件关闭:self.file.close()。

__exit__方法接受三个参数,它们是上下文管理器协议所需要的。

现在我们可以在with语句中使用自定义上下文管理器。

使用自定义的类上下文管理器的示例(和我们前面的示例雷同):

# 应用示例
import os
fileDirPath = os.getcwd()+os.sep+"ctxManager"+os.sep
# 在with语句中使用自定义上下文管理器
file_path = fileDirPath + 'files/color_names.txt'

with CustomContextManager(path=file_path, mode='r') as file:
#输出文件file内容
print(file.read())

运行输出结果这里不再赘述。简单解释一下代码。

上面清单中,在with语句中使用CustomContexManager类,通过它来读取文件内容并打印出来。下面是这个自定义上下文管理器幕后的故事:

1)在with行,调用类CustomContextManager的方_enter__法

2) __enter__方法打开文件并返回它。

3)我们将打开的文件简单地命名为file。

4)在with语句块中,读取文件内容并将其打印出来。

5)with语句自动调用__exit__方法。

6)__exit__方法关闭文件。

我们再来定义另一个上下文管理器类。这次我们想打印指定文件夹中的文件列表。

参考实现的代码清单如下:

class ContentList:
'''Prints the content of a directory'''

def __init__(self, directory):
self.directory = directory

def __enter__(self):
return os.listdir(self.directory)

def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is not None:
print("Error getting directory list.")
return True

# 输出项目目录下的内容
project_directory = '.'
with ContentList(project_directory) as directory_list:
print(directory_list)

在代码清单中,我们定义了一个新的上下文管理器。这个类的名字是ContentList。为什么它是一个上下文管理器?因为它实现了上下文管理器协议(__enter__和__exit__方法)。

我们将目录路径作为类构造函数__init__方法中的参数。

在__enter__方法中,只需调用os模块中的listdir()方法,就可以获得该目录中的内容列表:os.listdir(self.directory)。然后返回这个列表。请注意,在这个上下文管理器中我们的__enter__方法返回一个列表。

在__exit__方法中,我们检查是否存在任何错误。如果我们的上下文管理器中有错误,exc_type、exc_val、exc_tb参数值将不会为None。因此,我们检查exc_type是否为None以打印错误文本。

在with语句中使用该上下文管理器。由于它返回一个列表对象,我们只需将返回值赋值给directory_list变量。在with语句的主体中,我们打印这个列表。运行程序后在输出中,可以看到项目目录中的内容列表。记住,"."表示当前目录,在我们的例子中是项目根目录(由于项目环境不同,输出内容可能也不一样)。

6. 函数形式上下文管理器

前文中,我们学习了如何使用类语法定义上下文管理器。但是有点繁琐和冗长。因为需要明确地实现__enter__和exit__方法,还需要处理可能的异常。所以希望Python中能有在创建上下文管理器更好的方法:基于函数的上下文管理器。

其实函数上下文管理器是使用生成器和contextlib.contextmanager装饰器的特殊函数。 contextlib.contextmanager装饰器负责实现上下文管理器协议。

下面就来定义一个函数型上下文管理器。

from contextlib import contextmanager

# 定义上下文管理器函数
@contextmanager
def function_based_context_manager():
print("进入上下文: __enter__")
yield "这是个基于上下文管理器的函数"
print("离开上下文: __exit__")

# with语句中使用上下文管理器函数
with function_based_context_manager() as yield_text:
print(yield_text)

运行程序输出结果类似如下:

进入上下文: __enter__
这是个基于上下文管理器的函数
离开上下文: __exit__

在上面代码中,我们定义了一个作为上下文管理器的自定义函数。contextmanager装饰器将常规函数转换为全堆栈上下文管理器(自动实现上下文管理器的协议)。如果你为函数提供了@contextmanager装饰器,就不需要担心实现__enter__和__exit__函数。

代码中的yield语句在基于类的上下文管理器中的__enter__方法中充当返回语句。由于我们使用了yield语句,故此,这个基于函数的上下文管理器也是生成器函数。

再来定义一个新的上下文管理器。这一次,它将以写的模式打开一个文件并添加一些文本。示例如下:

Python プログラミング: コンテキスト マネージャーを簡単に理解する (コンテキスト マネージャー)

代码清单

在清单中,我们定义了一个基于函数的上下文管理器。在try块中,它尝试打开指定路径中的文件,并指定了文件的默认编码集。如果它成功地打开它,那么它将生成(返回)file_object。在finally块中,我们检查是否有一个file_object要关闭。如果file_object不是None,则关闭file_object。

with ステートメントでは、funBasedContextManagers.txt というファイル名でコンテキスト マネージャーを呼び出します。コンテキスト マネージャーはファイルを書き込みモードで開き、ファイル オブジェクトを返します。これには単に file という名前を付けます。次に、このファイルにテキストを書き込みます。 「w」モードでは、そのようなファイルが存在しない場合は空のファイルが作成されることに注意してください。

上記のプログラムを実行すると、ファイルが存在しない場合は対応する名前のファイルが生成され、書き込まれた内容は保持されます。ファイルが存在する場合、その内容がその都度ソースファイルに書き込まれますので、この操作には注意してください。

このような「終了」作業を処理するには、特にデータベース操作に関してはコンテキスト マネージャーを使用すると便利です。たとえば、コンテキスト マネージャーを自分でラップして接続を自動的に閉じるなどできます。

この記事の概要

この号では、コンテキスト マネージャー、コンテキスト マネージャー プロトコル、カスタム クラス形式のコンテキスト マネージャー、関数型コンテキストの作成方法など、コンテキスト マネージャーに関連するプログラミング コンテンツを紹介しました。マネージャーなど関連するコンテンツのほとんどは、実用的なコードを使用してデモンストレーションおよび説明されています。プログラミング スキルを向上させたい場合は、手でコードを入力することが不可欠です。

以上がPython プログラミング: コンテキスト マネージャーを簡単に理解する (コンテキスト マネージャー)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事は51cto.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。