Skip to content

Namespace and Context Manager

Namespace and Context manager - Простір імен та Контекстний менеджер

Контекстний менеджер (Context manager)

У Python є оператор with. Код всередині нього виконується з особливістю: перед та після нього гарантовано спрацьовують події входу до блоку with та виходу з нього (навіть у випадку коли з'являється виняток). Об'єкт, який визначає цю логіку, називається контекстним менеджером (context manager).

Події входу і виходу з блоку визначені методами __enter__ і __exit__. Перший спрацьовує в той момент, коли виконання програми переходить всередину with. Метод може повернути значення, яке буде доступне вкладеному коду всередині блоку with.

__exit__ спрацьовує при виході з блоку, включаючи випадок виникнення виключення. У цьому випадку в метод буде передано трійку значень (exc_class, exc_instance, traceback).

Найпоширеніший контекстний менеджер - це клас, створений функцією open. Він гарантує, що файл буде закрито навіть у випадку виникнення помилки всередині блоку.

Слід намагатися виходити з контекстного менеджера якомога швидше, щоб звільнити контекст та ресурси.

with open('file.txt') as f:
    data = f.read()
process_data(data)

Приклад реалізації власного контекстного менеджера на основі класу

class MyOpen:
    def __init__(self, filename):
        self.filename = filename
    def __enter__(self):
        self.file = open(self.filename)
        return self.file
    def __exit__(self, exc_type, exception, traceback):
        self.file.close()

>>> with open('test.txt', 'w') as file:
...     file.write('Hello World!')

Приклад реалізації власного контекстного менеджера з використанням вбудованої бібліотеки contextlib:

from contextlib import contextmanager

@contextmanager
def printable():
    print('enter')
    try:
        yield
    finally:
        print('exit')

Контекстні менеджери також можна використовувати для тимчасової заміни параметрів, змінних середовища, транзакцій БД.

Що таке простори імен в Python? LEGB

Простір імен (namespace) - це система імен, яка використовується для забезпечення унікальності найменування всіх об'єктів в програмі з метою уникнення можливих конфліктів. У Python ці простори імен реалізовані як словники з ім'ям у якості ключа та об'єктом в якості значення. В результаті різні простори можуть давати своїм об'єктам однакові імена.

LEGB визначає порядок, у якому інтерпретатор Python шукає значення для змінних. Спочатку він шукає у локальній області видимості, потім в області навколишньої функції (якщо це вкладена функція), потім в глобальній області видимості та нарешті в вбудованій області видимості. Цей порядок забезпечує правильність виконання коду та можливість використання змінних у правильних контекстах.

Простори імен в Python зберігаються подібно словнику, де ключем є простір імен, а значенням - адреса об'єкта. Існують 4 типи просторів імен в Python: - Вбудований простір імен (Built-in) - це набір вбудованих функцій Python та вбудованих імен для різних типів виключень. Доступний, коли Python працює. - Глобальний простір імен (Global) - це набір імен різних імпортованих пакетів/модулів, які в даний момент використовуються в проекті. Глобальний простір імен створюється при імпорті пакета в скрипт, і він доступний до тих пір, поки скрипт не завершить виконання. - Вкладені простори імен (Enclosing) - Ці простори імен знаходяться на вищому рівні або в зовнішній функції. - Локальний простір імен (Local) - це набір імен, які є локальними для функції. Локальний простір імен тимчасово створюється під час виклику функції та очищується при поверненні з неї.

Основні особливості просторів імен в Python: - Локальний та глобальний простори імен: Кожна функція в Python має свій власний локальний простір імен, де зберігаються її локальні змінні. Крім того, є глобальний простір імен для всієї програми, де зберігаються змінні, функції та інші об'єкти, доступні на рівні програми. - Вкладені простори імен: Функції можуть бути вкладені одна в одну, і кожна з них має свій власний локальний простір імен. Вкладені функції мають доступ до змінних своїх батьківських функцій. - Будь-який об'єкт має свій простір імен: Крім функцій, простори імен також відносяться до класів, модулів та пакетів. Кожен з цих об'єктів має свій власний простір імен для зберігання своїх членів (атрибутів, методів тощо). - Простір імен - це словник: Фактично, простір імен можна уявити як словник, де ключами є імена об'єктів, а значеннями - відповідні об'єкти. Для отримання доступу до об'єкта в просторі імен використовується його ім'я. - Конфлікти імен: Важливо уникати конфліктів імен, особливо в глобальному просторі імен, щоб уникнути непередбачених проблем. Імена мають бути унікальними в межах свого простору імен.

Що таке локальні та глобальні змінні в Python? global, nonlocal

Глобальні змінні - змінні, оголошені поза функцією або в глобальному просторі, називаються глобальними змінними. Ці змінні можуть бути доступні будь-якою функцією в програмі.

Локальні змінні - будь-яка змінна, оголошена всередині функції, відома як локальна змінна. Ця змінна присутня в локальному просторі, а не в глобальному.

a = 2
def add():
    b = 3
    c = a + b
    print(c)
add()  # 5

if, for, while не мають власного скоупу (області видимості) - змінні будуть доступні після виконання

  • global: Ключове слово global дозволяє звертатися до глобальних змінних всередині функцій та змінювати їх значення. Глобальні змінні оголошуються на рівні програми та є видимими в усій програмі.
  • nonlocal: Ключове слово nonlocal дозволяє звертатися до локальних змінних в зовнішніх функціях (батьківських функціях) з внутрішніх функцій (вкладених функцій). Це дозволяє змінювати значення змінних у батьківській функції з внутрішньої функції.

global використовується для роботи з глобальними змінними, а nonlocal - для роботи з локальними змінними у вкладених функціях.

>>> def function():
...     global x
...     x = 'global assigned inside function'
...     print (x)
...
>>> function()
global assigned inside function
>>> x
'global assigned inside function'
>>>
>>> def outer():
...     x = "x assigned inside outer"
...     def inner():
...         nonlocal x
...         x = "x assigned inside inner"
...         print("inner():", x)
...     inner()
...     print("outer():", x)
...
>>> outer()
inner(): x assigned inside inner
outer(): x assigned inside inner
>>>

Links