You are currently viewing Контекстный менеджер на Python

Контекстный менеджер на Python

Управление ресурсами : В любом языке программирования очень часто используются такие ресурсы, как файловые операции или подключения к базе данных. Но эти ресурсы ограничены в поставках. Поэтому основная проблема заключается в том, чтобы освободить эти ресурсы после использования. Если они не будут выпущены, это приведет к утечке ресурсов и может привести к замедлению или сбою системы. Было бы очень полезно, если бы у пользователя был механизм автоматической настройки и удаления ресурсов.В Python это может быть достигнуто за счет использования контекстных менеджеров, которые облегчают правильную обработку ресурсов. Наиболее распространенным способом выполнения файловых операций является использование с ключевым словом, как показано ниже:

# Python program showing
# a use of with keyword

with open("test.txt") as f:
	data = f.read()

Давайте возьмем пример управления файлами. При открытии файла используется файловый дескриптор, который является ограниченным ресурсом. Только определенное количество файлов может быть открыто процессом одновременно. Это демонстрирует следующая программа.

file_descriptors = []
for x in range(100000):
	file_descriptors.append(open('test.txt', 'w'))

Выход:

Traceback (most recent call last):
 File "context.py", line 3, in 
OSError: [Errno 24] Too many open files: 'test.txt'

Появилось сообщение об ошибке, в котором говорится, что открыто слишком много файлов. Приведенный выше пример представляет собой случай утечки файлового дескриптора. Это происходит потому, что слишком много открытых файлов, и они не закрыты. Могут возникнуть ситуации, когда программист может забыть закрыть открытый файл.

Управление ресурсами с помощью контекстного менеджера :

Предположим, что блок кода вызывает исключение или если он имеет сложный алгоритм с несколькими путями возврата, становится неудобно закрывать файл во всех местах.
Как правило, на других языках при работе с файлами try-except-finally используется для обеспечения закрытия файлового ресурса после использования, даже если есть исключение.Python предоставляет простой способ управления ресурсами: Контекстные менеджеры. Используется ключевое слово with. Когда он будет оценен, он должен привести к объекту, который выполняет управление контекстом. Контекстные менеджеры могут быть написаны с использованием классов или функций(с помощью декораторов).

Создание контекстного менеджера :

При создании контекстных менеджеров с использованием классов пользователю необходимо убедиться, что у класса есть методы: __enter__() and __exit__(). The __enter__() returns возвращает ресурс, которым необходимо управлять, а __exit__() ничего не возвращает, но выполняет операции очистки.
Во — первых, давайте создадим простой класс под названием Контекст менеджер чтобы понять основную структуру создания контекстных менеджеров с помощью классов, как показано ниже:

# Python program creating a
# context manager

class ContextManager():
	def __init__(self):
		print('init method called')
		
	def __enter__(self):
		print('enter method called')
		return self
	
	def __exit__(self, exc_type, exc_value, exc_traceback):
		print('exit method called')


with ContextManager() as manager:
	print('with statement block')

Выход:

init method called
enter method called
with statement block
exit method called

В этом случае создается объект ContextManager. Это присваивается переменной после ключевого слова as, т. е. менеджеру. При запуске вышеуказанной программы последовательно выполняются следующие действия:

  • __init__()
  • __enter__()
  • statement body (код внутри блока with)
  • __exit__() [параметры в этом методе используются для управления исключениями]

Управление файлами с помощью контекстного менеджера :

Давайте применим приведенную выше концепцию для создания класса, который помогает в управлении файловыми ресурсами.Класс FileManager помогает открывать файл, записывать/считывать содержимое и затем закрывать его.

# Python program showing
# file management using
# context manager

class FileManager():
	def __init__(self, filename, mode):
		self.filename = filename
		self.mode = mode
		self.file = None
		
	def __enter__(self):
		self.file = open(self.filename, self.mode)
		return self.file
	
	def __exit__(self, exc_type, exc_value, exc_traceback):
		self.file.close()

# loading a file
with FileManager('test.txt', 'w') as f:
	f.write('Test')

print(f.closed)

Выход:

True

Управление файлами с помощью контекстного менеджера и с помощью инструкции :

При выполнении с блок, следующие операции выполняются последовательно:

  • Файловый менеджер объект создается с помощью test.txt в качестве имени файла и w(запись) в качестве режима при выполнении метода __init__.
  • Метод __enter__ открывает test.txt файл в режиме записи(операция установки) и возвращает Файловый менеджер объект к переменной f.
  • Текст » Test’ записывается в файл.
  • Метод __exit__ позаботится о закрытии файла при выходе из с блоком(операция демонтажа).
    Когда печать(f.закрыто) выполняется, вывод является Правда в качестве Файловый менеджер уже позаботился о закрытии файла, что в противном случае необходимо было сделать явно.

Управление подключениями к базе данных с помощью контекстного диспетчера :

Давайте создадим простую систему управления подключениями к базе данных. Количество подключений к базе данных, которые могут быть открыты одновременно, также ограничено(как и файловые дескрипторы). Поэтому контекстные менеджеры полезны при управлении подключениями к базе данных, так как может быть вероятность того, что программист может забыть закрыть соединение.

# Python program shows the
# connection management
# for MongoDB

from pymongo import MongoClient

class MongoDBConnectionManager():
	def __init__(self, hostname, port):
		self.hostname = hostname
		self.port = port
		self.connection = None

	def __enter__(self):
		self.connection = MongoClient(self.hostname, self.port)
		return self

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

# connecting with a localhost
with MongoDBConnectionManager('localhost', '27017') as mongo:
	collection = mongo.connection.SampleDb.test
	data = collection.find({'_id': 1})
	print(data.get('name'))

Управление подключениями к базе данных с помощью контекстного диспетчера и оператора with :

При выполнении с блок, следующие операции выполняются последовательно:

  • A MongoDBConnectionManager объект создается с помощью localhost в качестве имени хоста и 27017 в качестве порта при выполнении метода __init__.
  • Метод __enter__ открывает соединение mongodb и возвращает Объект MongoDBConnectionManager в переменную монго.
  • Осуществляется доступ к тестовой коллекции в базе данных SampleDb, и документ с _id=1. Будет напечатано поле » Имя » документа.
  • Метод __exit__ позаботится о закрытии соединения при выходе из с блок(операция демонтажа).