>백엔드 개발 >파이썬 튜토리얼 >Python 프로그래밍: 컨텍스트 관리자(Context Manager)를 쉽게 이해하기

Python 프로그래밍: 컨텍스트 관리자(Context Manager)를 쉽게 이해하기

PHPz
PHPz앞으로
2023-04-12 14:07:132338검색

머리말

이 글은 Python 컨텍스트 관리에 대한 설명과 적용에 중점을 둡니다. 또는 코드 예제, 비교 이해 및 학습을 통해 "더 빠른 속도, 더 나은 경제"에 대한 이해, 숙달 및 적용을 달성합니다. 더 이상 고민하지 말고 시작해 보겠습니다.

1. 컨텍스트 관리자란 무엇입니까? 컨텍스트 관리자는 with 문을 실행할 때 설정될 런타임 컨텍스트를 정의하는 개체입니다. 컨텍스트 관리자는 코드 블록이 실행되는 컨텍스트에 대한 시작 및 종료를 자동으로 처리하는 런타임입니다. 컨텍스트 관리자는 일반적으로 with 문을 사용하여 호출되지만 메서드를 직접 호출하여 사용할 수도 있습니다.

컨텍스트 관리자의 일반적인 용도에는 다양한 전역 상태 저장 및 복원, 리소스 잠금 및 잠금 해제, 열린 파일 닫기 등이 포함됩니다.

이 장에서는 Python에서 컨텍스트 관리자를 사용하는 방법과 컨텍스트 관리자를 사용자 정의하는 방법을 알아봅니다.

1.With 문

with 문은 컨텍스트 관리자가 정의한 메서드 래퍼 블록의 실행에 사용됩니다. 이를 통해 쉽게 재사용할 수 있도록 일반적인 try...out...finally 사용 패턴을 캡슐화할 수 있습니다. with 문은 기존의 try...out...finally 블록에 비해 더 짧고 재사용 가능한 코드를 제공합니다.

Python 표준 라이브러리에서는 많은 클래스가 with 문을 지원합니다. 매우 일반적인 예는 with 문을 사용하여 파일 객체를 처리하기 위한 패턴을 제공하는 내장 open() 함수입니다.

다음은 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

Context Manager Protocol은 직설적으로 말하면 Context Manager의 처리 메커니즘, 즉 미리 정해진 프로토콜 표준입니다. 이 부분은 Python Core Protocol에서도 찾을 수 있습니다. 독서의 독립성을 위해 여기서 다시 이야기해 보겠습니다.

Python의 with 문은 컨텍스트 관리자가 정의한 런타임 컨텍스트 개념을 지원합니다. 이는 사용자 정의 클래스가 명령문 본문이 실행되기 전에 입력되고 명령문 끝에서 종료되는 런타임 컨텍스트를 정의할 수 있도록 하는 한 쌍의 메소드를 통해 수행됩니다.

앞서 언급한 방법을 컨텍스트 관리자 프로토콜이라고 합니다. 이 두 가지 메소드를 자세히 살펴보겠습니다.

1) __enter__(self)

이 메소드는 with 문에 의해 호출되어 현재 객체와 관련된 런타임 컨텍스트에 들어갑니다. with 문은 이 메서드의 반환 값을 문의 as 절에 지정된 대상(있는 경우)에 바인딩합니다.

위 예제에서 반환된 컨텍스트 관리자는 파일 개체입니다. 뒤에서는 파일 객체가 __enter__()에서 자신을 반환하여 open()이 with 문에서 상황별 표현으로 사용될 수 있도록 합니다.

2)__exit__(self, ex_type, ex_value, Traceback):

이 메서드는 실행이 with 코드 블록을 벗어날 때 호출됩니다. 이 개체와 관련된 런타임 컨텍스트를 종료합니다. 매개변수는 컨텍스트 종료를 발생시킨 예외 정보를 설명합니다. 예외 없이 컨텍스트가 종료되면 세 매개변수는 모두 None이 됩니다.

예외가 제공되고 메서드에서 예외를 억제(예: 전파 방지)하려는 경우 True 값을 반환해야 합니다. 그렇지 않으면 이 메서드를 종료할 때 예외가 정상적으로 처리됩니다. __exit__() 메서드는 True 또는 False일 수 있는 부울 값을 반환합니다.

컨텍스트 관리자 프로토콜의 메서드를 사용하여 with 문을 실행하는 과정은 다음과 같습니다.

with EXPRESSION as TARGET:
SUITE

컨텍스트 표현식(EXPRESSION)을 평가하여 컨텍스트 관리자를 얻습니다.
  • 나중에 사용할 수 있도록 컨텍스트 관리자의 __enter__()를 로드하세요.
  • 이후 사용을 위해 컨텍스트 관리자의 __exit__()를 로드하세요.
  • 컨텍스트 관리자의 __enter__() 메서드를 호출하세요.
  • TARGET이 with 문에 포함되면 __enter__()의 반환 값이 할당됩니다.
  • 실행 제품군(with 문의 범위에 있는 코드 블록).
  • 컨텍스트 관리자의 __exit__() 메서드를 호출하세요. 예외로 인해 스위트가 종료된 경우 해당 유형, 값 및 역추적은 __exit__()에 인수로 전달됩니다. 그렇지 않으면 세 개의 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 프로그래밍: 컨텍스트 관리자(Context Manager)를 쉽게 이해하기

代码清单

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

with 문에서는 funBasedContextManagers.txt라는 파일 이름으로 컨텍스트 관리자를 호출합니다. 컨텍스트 관리자는 쓰기 모드로 파일을 열고 파일 객체를 반환합니다. 간단히 file이라고 이름 붙입니다. 그런 다음 이 파일에 텍스트를 작성합니다. 기억하세요, 'w' 모드는 해당 파일이 존재하지 않으면 빈 파일을 생성합니다.

위 프로그램을 실행해 보세요. 해당 파일이 없으면 해당 이름의 파일이 생성되고 작성된 내용이 유지됩니다. 파일이 존재하는 경우 매번 소스 파일에 내용이 기록됩니다.

이와 같은 "마무리" 작업을 처리하려면 특히 데이터베이스 작업과 관련하여 컨텍스트 관리자를 사용하는 것이 편리합니다. 예를 들어 연결을 자동으로 닫도록 직접 래핑할 수 있습니다.

이 기사 요약

이번 호에서는 컨텍스트 관리자 생성 방법, 컨텍스트 관리자 프로토콜, 사용자 정의 클래스 형식 컨텍스트 관리자 및 기능적 컨텍스트 관리자 등 컨텍스트 관리자와 관련된 프로그래밍 콘텐츠를 소개했습니다. 관련 내용의 대부분을 실습 코드로 시연하고 설명합니다. 프로그래밍 기술을 향상시키고 싶다면 손으로 코드를 타이핑하는 것은 필수 요구 사항입니다.

위 내용은 Python 프로그래밍: 컨텍스트 관리자(Context Manager)를 쉽게 이해하기의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 51cto.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제