Python Context Manager для восстановления значения переменной? - PullRequest
0 голосов
/ 14 декабря 2018

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

x = 5
with Restorer(x):
   x = 6
   ...
print(x)

Вывод будет: 5

Ответы [ 4 ]

0 голосов
/ 14 декабря 2018

Это больше связано с областью имен, чем с переменными.

Вы можете создать область, создав функцию с поведением для блока:

def behaviour():
    x = 6
    ...

x = 5
behaviour()
print(x)

Вывод:

5

В качестве альтернативы, вы можете просто ввести новое имя:

x = 5
y = 6
...
print(x)

Вывод:

5
0 голосов
/ 14 декабря 2018

Используя contextlib.contextmanager, вы можете переназначить x на его первоначальное значение после оператора yield:

import contextlib

x = 5
@contextlib.contextmanager
def Restorer(val):
  yield 
  global x
  x = val

print(x)
with Restorer(x):
  x = 6
  print('in contextmanager:', x)

print('outside contextmanager', x)

Вывод:

5
in contextmanager: 6
outside contextmanager 5
0 голосов
/ 14 декабря 2018

Вы можете использовать оператор class, чтобы ввести временную "область видимости":

x = 5
class Foo:
    print(x)
    x = 6
    print(x)
print(x)

Это "работает", потому что Foo не устанавливает истинно новую область, то есть первую print(x) ссылается на текущее имя в области действия x, но присваивается во временной запретной зоне для подготовки к созданию атрибута класса с тем же именем, и этот атрибут используется для оставшейся части тела.Однако этого, на мой взгляд, достаточно для имитации того, что вы просите.

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

0 голосов
/ 14 декабря 2018

Это возможно только при определенных обстоятельствах.Обычно менеджер контекста получает только значение (фактически ссылку) x.Он не получает доступа к самой переменной.

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

with Restorer('x'):

Тогда восстановитель может быть что-то вроде (проверка ошибок опущена):

class Restorer:

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

    def __enter__(self):
        self.oldValue = globals()[self.varName]

    def __exit__(self, exc_type, exc_val, exc_tb):
        globals()[self.varName] = self.oldValue
...