python: элегантный способ борьбы с блокировкой переменной?

У меня есть код, который выглядит примерно так:

def startSearching(self): self.searchingLock.acquire() searching = self.searching if self.searching: self.searchingLock.release() self.logger.error("Already searching!") return False self.searching = True self.searchingLock.release() #some more init code, then start the thread which #constantly checks self.searching to determine when to stop 

Однако это отвратительно. множество приобретений и выпусков. это выглядит красивее:

 def startSearching(self): with self.searchingLock: if self.searching: self.logger.error("Already searching!") return False self.searching = True #some more init code, then start the thread which #constantly checks self.searching to determine when to stop 

но это удерживает блокировку дольше, чем это строго необходимо, особенно если self.logger.error занимает некоторое время (например, если он записывает на диск, что он делает). есть ли какая-либо промежуточная точка между удерживанием замка как можно меньше, но с более красивым кодом?

    Возможно, вам нужно отделить эту логику так:

     def initSearch(self): with self.searchingLock: if self.searching : raise SearchingError('AlreadySearching') self.searching = True def startSearching(self): try: self.initSearch() except SearchingError as error : self.logger.error(error.message) return False #some more init code, then start the thread which #constantly checks self.searching to determine when to stop 

    Кроме того, вы говорите своему searchingLock о причине его автоматического выпуска.

    Как насчет переноса переменной & блокировки в класс:

     class LockedVariable(object): def __init__(self, value, lock=None): self._value = value self._lock = lock if lock else threading.RLock() self._locked = false: @property def locked(self): return self._locked def assign(self, value): with self: self._value = value def release(): self._locked = False return self._lock.release() def __enter__(self): self._lock.__enter__() self._locked = True return self._value def __exit__(self, *args, **kwargs): if self._locked: self._locked = False return self._lock.__exit__(*args, **kwargs) 

    И используйте как это:

     locked_dict = LockedVariable({}) with locked_dict as value: value['answer'] = 42 if locked_dict.locked: locked_dict.release() print 'eureka! :)' return if locked_dict.locked: print 'bahh! :(' 

    Комментарий:

    Я иногда использую boost :: shared_ptr с пользовательским удалением, чтобы достичь того же, т.е. возвращать разблокированную переменную, выпущенную, когда она выходит за рамки.

    Это сэкономит вам один « self.searchingLock.release() « Угадайте, что это не очень пифонично или что-то еще, но это делает работу

     def startSearching(self): self.searchingLock.acquire() already_searching = self.searching self.searching = True # Since it'll be true in both scenarios self.searchingLock.release() if already_searching: self.logger.error("Already searching!") return not already_searching