Как добавить значения в список атомарно (при выходе), используя менеджер контекста? - PullRequest
0 голосов
/ 21 февраля 2020

Для начала я новичок в Python.

Я пытаюсь написать свой собственный менеджер контекста, который добавит значения в мой список при выходе. Я создал копию своего списка, но, похоже, это не работает должным образом.

Вот мой код:

import time
import copy

a = [1,2,3]


class contextmanager():
    def __init__(self, var):
        self.abc = var

    def current(self):

        b.append(98325)



        return b

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('Current list: {}'.format(self.current()))

with contextmanager(a) as t:
    time.sleep(1)
    b = copy.deepcopy(a)

    print("Changed list: {}".format(t.current()))
    time.sleep(2) 

Я хочу добавить значения при выходе , например:

ток - [1,2,3]

добавление - [4,5,6]

перед выходом - [1,2,3]

выход - [1,2,3,4,5,6]

но это не сработало, и я понял:

ток - [1,2,3,4,5,6]

добавление - [4,5,6]

выход - [1,2,3,4,5,6,4,5,6]

Что я делаю неправильно? Как я могу сделать это, чтобы это исправить? Я буду рад, если вы покажете мне, что мне нужно изменить в моем коде.

Кажется, я пока еще не знаю Python. Спасибо за любую вашу помощь.

Ответы [ 2 ]

1 голос
/ 21 февраля 2020

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

Я бы предложил следующий дизайн:

  • менеджер контекста принимает list в качестве параметра создания
  • предоставляет 2 метода:
    • append(val), которые подготавливают , добавляя val в список и возвращая себя, чтобы разрешить сцепление
    • appending(), который возвращает список элементов для добавления
  • подготовленные элементы добавляются только в том случае, если исключение не возникло

Возможная реализация:

class contextmanager():
    def __init__(self, var):
        self.orig = var
        self.cur = []

    def append(self, val):
        self.cur.append(val)
        return self

    def appending(self):
        return self.cur

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type is None:
            self.orig.extend(self.cur)

Пример использования:

a = [1,2,3]

print("initial", a)
with contextmanager(a) as t:
    t.append(4)
    print("appending", t.appending())
    t.append(5).append(6)
    print("appending", t.appending())

print("first pass", a)

try:
    with contextmanager(a) as t:
        t.append(7)
        t.append(8)
        print("appending", t.appending())
        raise Exception()
        t.append(9)
        print("appending", t.appending())
except Exception as e:
    print("Exception", e)

print("final", a)

, что дает:

initial [1, 2, 3]
appending [4]
appending [4, 5, 6]
first pass [1, 2, 3, 4, 5, 6]
appending [7, 8]
Exception 
final [1, 2, 3, 4, 5, 6]
0 голосов
/ 21 февраля 2020

Ваш код добавляется дважды. Ваше первое добавление находится в блоке операторов вашего Contextmanager (эта строка: print("Changed list: {}".format(t.current())))

Ваше второе добавление находится в методе __exit__, который вызывается после того, как Contextmanager проработал свой блок операторов.

Ваш код работает следующим образом:

создайте и заполните 1,2,3
contextmanager начинает работу:
-> глубокое копирование от a до b
-> первое добавление через t.current()
-> конец contextmanager -> call __exit__, где находится второе добавление.

надеюсь, это поможет вам лучше понять его.

...