如何将对象工厂与contextlib一起使用

2024-06-16 16:09:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要写代码来处理不同的硬件设置。我不知道哪个硬件连接到我的系统。所以我使用一个对象工厂,它从硬件中读取一些标识符并返回一个专门的对象。我想将此方法与contextlib结合使用,但发现对象仍然存在于with块之外。在我的情况下,这是一个问题,因为我需要关闭连接到我的设备

我的问题的一个最简单的例子:

import contextlib

class Dog:
    def speak(self):
        print('wuff')

class Cat:
    def speak(self):
        print('miau')


@contextlib.contextmanager
def get_animal(n):
    print('buy animal')
    if n==0:
        yield Dog()
    else:
        yield Cat()
    print('lost animal')

if __name__ == "__main__":
    with get_animal(0) as animal:
        animal.speak()
    animal.speak()

这就产生了

> buy animal
> wuff
> lost animal
> wuff

如何修改此代码以使最终的animal.speak()导致错误?我知道我可以用del animal来释放动物,但一定有更优雅的方法


Tags: 对象方法代码self硬件defwithclass
1条回答
网友
1楼 · 发布于 2024-06-16 16:09:54

您对contextmanager装饰器的使用有点不合适,因为在with语句中没有迭代的方法使用get_animal()函数创建“上下文管理器”会执行迭代的一个步骤,这不会使上下文管理器工作


通常,上下文管理器装饰器应仅用于装饰返回生成器的函数:

The function being decorated must return a generator-iterator when called. This iterator must yield exactly one value, which will be bound to the targets in the with statement’s as clause, if any.

据我所知,唯一的方法是实现一个具有__enter____exit__的“神奇”方法的类:

class Dog(object):
    def __init__(self):
        self.active =  None
    def __enter__(self):
        self.active = True
    def __exit__(self, type, value, traceback):
        self.active = False
    def speak(self):
        if self.active:
            print('wuff')
        else:
            raise Exception('No context manager')

如果您这样做,那么您将得到预期的Exception

buy animal
Traceback (most recent call last):
  File "....py", line 42, in <module>
    animal.speak()
  File "...py", line 15, in speak
    raise Exception('No context manager')
Exception: No context manager

相关问题 更多 >