标签: contextmanager

如何在Python中将变量放在堆栈/上下文中

从本质上讲,我想在堆栈上放置一个变量,该变量可以通过堆栈下面的所有调用到达,直到块退出.在Java中,我将使用支持方法的本地静态线程解决此问题,然后可以从方法访问.

典型示例:您收到请求,并打开数据库连接.在请求完成之前,您希望所有代码都使用此数据库连接.完成并关闭请求后,关闭数据库连接.

我需要这个,是一个报告生成器.每个报告由多个部分组成,每个部分可以依赖于不同的计算,有时不同的部分部分依赖于相同的计算.由于我不想重复繁重的计算,我需要缓存它们.我的想法是用缓存装饰器装饰方法.缓存根据方法名称和模块创建一个id,它的参数,看它是否已经在堆栈变量中计算,并且如果没有则执行该方法.

我将通过展示我当前的实现来尝试清除.我想要做的是简化那些实现计算的代码.

首先,我有中央缓存访问对象,我称之为MathContext:

class MathContext(object):
    def __init__(self, fn): 
        self.fn = fn
        self.cache = dict()
    def get(self, calc_config):
        id = create_id(calc_config)
        if id not in self.cache:
            self.cache[id] = calc_config.exec(self)
        return self.cache[id]
Run Code Online (Sandbox Code Playgroud)

fn参数是创建上下文的文件名,从中可以读取数据以进行计算.

然后我们有Calculation类:

 class CalcBase(object):
     def exec(self, math_context):
         raise NotImplementedError
Run Code Online (Sandbox Code Playgroud)

这是一个愚蠢的斐波那契例子.这些方法实际上不是递归的,而是处理大量数据,但它可以演示如何依赖其他计算:

class Fibonacci(CalcBase):
    def __init__(self, n): self.n = n
    def exec(self, math_context):
        if self.n < 2: return 1
        a = math_context.get(Fibonacci(self.n-1))
        b = math_context.get(Fibonacci(self.n-2))
        return a+b
Run Code Online (Sandbox Code Playgroud)

我想要斐波那契,只是一种装饰方法:

@cache
def fib(n):
    if n<2: return 1
    return fib(n-1)+fib(n-2)
Run Code Online (Sandbox Code Playgroud)

使用math_context示例,当math_context超出范围时,它的缓存值也是如此.我想为装饰者做同样的事情.IE浏览器.在第X点,@ cache缓存的所有内容都是deveferrenced.

python thread-local contextmanager

2
推荐指数
1
解决办法
1710
查看次数

处置带有循环引用的对象

我的设计如下:

  • __main__ 引用 a
  • a 引用 b
  • b 引用 a
  • a 创建然后处理 __main__

因此,ab有循环参考.然而在del a我宁愿都ab处置.

我在很多地方看到使用Context Manager的建议,特别是with语句而不是__del__().但是我with在局部范围内看到的开始和结束的所有例子(例如某种方法)

这可以优雅地执行with吗?
有什么选择?

python with-statement circular-reference contextmanager

2
推荐指数
1
解决办法
233
查看次数

Return in finally block in python context manager

我最近在Python的with语句中遇到了一个奇怪的行为。我有一个代码,它使用 Python 的上下文管理器来回滚__exit__方法中的配置更改。经理return False在finally 块中有一个值__exit__。我在以下代码中隔离了这种情况 - 唯一的区别是 return 语句的缩进:

class Manager1(object):

    def release(self):
        pass # Implementation not important

    def rollback(self):
        # Rollback fails throwing an exception:
        raise Exception("A failure")

    def __enter__(self):
        print "ENTER1"

    def __exit__(self, exc_type, exc_val, exc_tb):
        print "EXIT1"
        try:
            self.rollback()
        finally:
            self.release()
            return False          # The only difference here!


class Manager2(object):

    def release(self):
        pass # Implementation not important

    def rollback(self):
        # Rollback fails throwing an exception:
        raise Exception("A failure")

    def __enter__(self):
        print …
Run Code Online (Sandbox Code Playgroud)

python with-statement contextmanager

2
推荐指数
1
解决办法
3569
查看次数

在contextmanager中使用yield两次

我试图用contextmanager隐藏一些try/except复杂性.这是一个简单的例子:

from contextlib import contextmanager
import mpd

mpdclient = mpd.MPDClient()
mpdclient.connect("localhost", 6600)

@contextmanager
def mpdcontext():
  try:
    yield
  except mpd.ConnectionError:
    mpdclient.connect("localhost", 6600)

with mpdcontext():
  mpdclient.status()

with mpdcontext():
  mpdclient.lsinfo()
Run Code Online (Sandbox Code Playgroud)

现在,正如我所理解的那样,在调用yield时执行with语句中的块.在我的情况下,如果这引发异常,我重新连接到mpd.重新连接后,我可以以某种方式再次执行with-block吗?

谢谢

python yield contextmanager mpd

2
推荐指数
1
解决办法
1494
查看次数

Python 上下文管理器如何尝试执行代码?

我正在尝试编写一个小型上下文管理器,它将尝试重复执行某些代码,直到代码正常工作或完成指定次数的尝试。我试图写这个,但在让上下文管理器在产生时处理问题时遇到了困难:

Exception RuntimeError: 'generator ignored GeneratorExit'
Run Code Online (Sandbox Code Playgroud)

我应该如何编码?

import contextlib
import random

def main():

    with nolube():
        print(1 / random.randint(0, 1))

@contextlib.contextmanager
def nolube(
    tries = None # None: try indefinitely
    ):
    """
    Create a context for trying something repeatedly.
    """
    tries_done = 0
    rekt = True
    if tries is None:
        while rekt is True:
            try:
                yield
                rekt = False
            except:
                tries_done += 1
                pass
    else:
        while rekt is True and tries_done <= tries:
            try:
                yield
                rekt = False
            except:
                tries_done += …
Run Code Online (Sandbox Code Playgroud)

python yield exception try-catch contextmanager

2
推荐指数
1
解决办法
3607
查看次数

python:`with open()`和未知数量的文件

说,我想打开一些文件并逐行处理.为了论证,让我们假设我想将每个文件中的第n行连接成一行并将其写入另一个文件.我不想让自己的记忆膨胀,所以我不想完全阅读它们.我不知道我的功能会有多少文件.

如果我知道文件的数量,我会做这样的事情:

with open(file_a) as in_a, open(file_b) as in_b, open(file_c, "w") as out:
    try:
        while True:
            line_a = next(in_a)
            line_b = next(in_b)
            out.write(line_a + line_b)
    except StopIteration:
        pass
Run Code Online (Sandbox Code Playgroud)

有没有办法用未知数量的输入(或其他上下文管理器)做类似的事情?

python contextmanager

2
推荐指数
1
解决办法
277
查看次数

上下文管理器可以在 Python 中多次运行包含的块吗?

作为一个基本示例,请想象以下内容:

with runFiveTimes:
    print("test")
Run Code Online (Sandbox Code Playgroud)

这在Python中可能吗?

(这个例子只是为了澄清问题,显然有更简单的方法来实现这个特定的例子)

python contextmanager

2
推荐指数
1
解决办法
1578
查看次数

如何在PyCharm中正确注释ContextManager?

我如何注释contextmanagerPyCharm 中a的yield类型,以便它正确猜测with子句中使用的值的类型-就像它猜测fcreated in with open(...) as f是文件一样?

例如,我有一个这样的上下文管理器:

@contextlib.contextmanager
def temp_borders_file(geometry: GEOSGeometry, name='borders.json'):
    with TemporaryDirectory() as temp_dir:
        borders_file = Path(dir) / name
        with borders_file.open('w+') as f:
            f.write(geometry.json)
        yield borders_file

with temp_borders_file(my_geom) as borders_f:
    do_some_code_with(borders_f...)
Run Code Online (Sandbox Code Playgroud)

如何让PyCharm知道每个这样borders_f创建的对象都是的pathlib.Path(从而启用上的Path方法的自动完成功能border_f)?当然,我可以像# type: Path在每条with语句之后一样发表评论,但是似乎可以通过适当地注释来完成temp_border_file

我试过Pathtyping.Iterator[Path]typing.Generator[Path, None, None]作为返回类型的temp_border_file,以及增加# type: Pathborders_file上下文管理的代码中,但似乎它并不能帮助。

typing contextmanager pycharm

2
推荐指数
2
解决办法
713
查看次数

Python:为什么我收到AttributeError:__enter__

我没有重新分配open关键字,但仍然收到此错误。有任何建议或指导来纠正我的错误吗?

 with tempfile.mkdtemp() as test_dir:
        print(test_dir)
Run Code Online (Sandbox Code Playgroud)

AttributeError: __enter__

我也是python的新手,我很难理解这些概念。

python temporary-directory attributeerror contextmanager

2
推荐指数
1
解决办法
1250
查看次数

上下文管理器的“打开工作”应该发生在 __init__ 还是 __enter__ 中?

我找到了下面的例子以下对象上下文管理器的File

\n
class File(object):\n    def __init__(self, file_name, method):\n        self.file_obj = open(file_name, method)\n    def __enter__(self):\n        return self.file_obj\n    def __exit__(self, type, value, traceback):\n        self.file_obj.close()\n
Run Code Online (Sandbox Code Playgroud)\n

在这里,管理器完成的工作(实际上是打开文件)发生在该__init__方法中。然而,在随附的文本中,他们建议文件打开应该发生在__enter__

\n
\n

让\xe2\x80\x99s 谈谈幕后发生的事情。

\n
    \n
  1. with 语句存储退出File类的
  2. \n
  3. 它调用输入File 类的
  4. \n
  5. 进入打开文件并返回它。
  6. \n
  7. 打开的文件句柄被传递给opened_file。
  8. \n
  9. 我们使用 .write() 写入文件。
  10. \n
  11. with 语句调用存储的退出方法。
  12. \n
  13. 出口关闭文件。
  14. \n
\n
\n

一般来说,哪种方法是正确的?似乎撤销的工作__exit__应该发生在__enter__,而不是__init__因为它们是通过上下文管理器机制 1:1 配对的,但这个例子让我感到怀疑。 …

python contextmanager

2
推荐指数
1
解决办法
1262
查看次数