Семантика проектирования контекстного менеджера
with WorkerContext():
worker = Worker()
thread = Thread()
thread.bind(worker)
thread.start()
# Worker class' run method
class Worker:
def run(self):
# Should this code be inside WorkerContext?
В моем WorkerContext, который основан на классе AbstractContext, метод экземпляра() позволяет получить текущий экземпляр контекста даже после вызывается __exit__() контекстного менеджера. Я хочу, чтобы worker.run() мог получить доступ к экземпляру контекста через WorkerContext.instance() во время его выполнения.
Однако в соответствии с контекстом Python семантики менеджера, после вызова __exit__() считается, что менеджер контекста завершил работу, и, как правило, экземпляр больше не является действительным. Мой вопрос: должен ли я намеренно нарушать семантику контекстного менеджера Python, чтобы экземпляр контекста оставался доступным после __exit__()?
Был бы этот дизайн разумным или он мог бы ввести потенциальные проблемы?
class AbstractContext(ABC):
"""
Base class for context managers.
Notes:
TODO: Support cross-process usage.
TODO: Support cross-machine usage.
TODO: Support cross-cluster usage.
"""
_global_stack = []
_lock = threading.Lock()
@classmethod
def instance(cls: type[T]) -> Optional[T]:
with cls._lock:
if not cls._global_stack:
return None
return next((ctx for ctx in reversed(cls._global_stack) if isinstance(ctx, cls)), None)
@classmethod
def stack(cls: type[T]) -> List[T]:
with cls._lock:
return [ctx for ctx in cls._global_stack if isinstance(ctx, cls)]
Или более дружелюбный способ описать проблему: является ли ее область действия динамической или статической, хотя это описание может быть немного неправильным, я считаю, что оно вполне отражает суть проблемы.< /p>
Когда я запускаю поток в WorkContext и выполняю его, я, естественно, думаю, что он выполняется в WorkContext, который является статическим.
Но на самом деле , он просто запускает поток, а затем завершает его, при этом внутренняя работа потока на самом деле не выполняется здесь, как мы могли бы себе представить. Я действительно не знаю, как здесь спроектировать его поведение.
Примечание: я не ищу конкретного решения, а скорее хочу понять, что представляет собой элегантный подход.
Я прикрепил контент и теперь это стало так:
worker = Worker()
thread = Thread()
thread.bind(worker)
worker.inject(WorkerContext())
thread.start()
class AbstractWorker:
def __init__(self):
self._injected_contexts = []
self._stack = contextlib.ExitStack()
def inject(self, *contexts: Context): # TODO: add ContextType
self._injected_contexts.extend(contexts)
def __enter__(self):
self._stack.__enter__()
for context in self._injected_contexts:
self._stack.enter_context(context)
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self._stack.__exit__(exc_type, exc_val, exc_tb)
return False
Подробнее здесь: https://stackoverflow.com/questions/790 ... n-mental-m
Должны ли мы нарушать семантику Python для создания функций, соответствующих человеческим ментальным моделям? ⇐ Python
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение