Как мне вернуть интересные значения из оператора with?

StackOverflow https://stackoverflow.com/questions/877709

Вопрос

Есть ли лучший способ получить интересные значения от менеджера контекста, чем использование глобальных переменных?

@contextmanager
def transaction():
    global successCount
    global errorCount
    try:
        yield
    except:
        storage.store.rollback()
        errorCount += 1
    else:
        storage.store.commit()
        successCount += 1

Другие возможности:

  • одиночки

    какие-то глобалы...

  • кортеж в качестве аргумента контекстного менеджера

    делает функцию более специфичной для проблемы/менее многоразовой

  • экземпляр, который содержит определенные атрибуты в качестве аргумента для менеджера контекста

    те же проблемы, что и кортеж, но более разборчиво

  • вызвать исключение в конце контекстного менеджера, содержащего значения.

    действительно плохая идея

Это было полезно?

Решение

Видеть http://docs.python.org/reference/datamodel.html#context-managers

Создайте класс, который хранит счетчики успехов и ошибок и реализует __enter__ и __exit__ методы.

Другие советы

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

class transaction:
    def __init__(self):
        self.errorCount = 0
        self.successCount = 0  

    def __enter__(*args):
        pass  

    def __exit__(self, type, value, traceback):
        if type:
            storage.store.rollback()
            self.errorCount += 1
        else:
            storage.store.commit()
            self.successCount += 1

(type имеет значение None, если при вызове нет исключений. contextmanager)

И тогда вы, вероятно, уже где-то используете это, что вызовет contextmanager и запусти свой __exit__() код. Редактировать: Как прокомментировал Эли, создавайте новый экземпляр транзакции только тогда, когда вы хотите сбросить счетчики.

t = transaction()
for q in queries:
    with t:
        t.execute(q)

"кортеж как аргумент контекстному менеджеру

делает функцию более специфичной для проблемы/менее многоразовой"

ЛОЖЬ.

Это заставляет контекстный менеджер сохранять состояние.

Если вы не реализуете ничего большего, чем это, его можно будет использовать повторно.

Однако на самом деле вы не можете использовать кортеж, поскольку он неизменяем.Вам нужна изменяемая коллекция.На ум приходят словари и определения классов.

Следовательно, рекомендуемая реализация

«экземпляр, который содержит определенные атрибуты в качестве аргумента для менеджера контекста»

Все, что вам нужно, — это простое определение класса с двумя атрибутами.Однако статус вашей транзакции имеет состояние, и вам нужно где-то его сохранять.

class Counters(dict):
    SUCCEED= 0
    FAIL= 1
    def __init__( self ):
        self[ self.SUCCEED ]= 0
        self[ self.FAIL ]= 0 
    def increment( self, status ):
        self[status] += 1

class Transaction(object):
    def __init__( self, worker, counters ):
        self.worker= worker
        self.counters= counters
    def __enter__( self ):
        self.counters.status= None
    def process( self, *args, **kw ):
        status= self.worker.execute( *args, **kw )
        self.counters.increment( status )
    def __exit__( self ):
        pass

counts= Counters()
for q in queryList:
    with Transaction(execQuery,counts) as t:
        t.process( q )
print counts
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top