Python 在with语句中隐藏post函数调用

Python 在with语句中隐藏post函数调用,python,python-3.x,with-statement,raii,Python,Python 3.x,With Statement,Raii,我有一个函数f,它返回两个参数。在这个函数之后,我使用第一个参数。我需要第二个函数将东西与另一个函数g粘合在一起。因此,我的代码如下所示: a, b = f() # do stuff with a g(b) 这是非常重复的,所以我想我可以使用类似RAII的方法。但是,由于我不知道对象何时会消亡,并且我的主要目标是消除重复代码,因此我使用了with语句: with F() as a: # do stuff with a 就这样。基本上,我围绕这个函数创建了一个对象F,提供了\uuuuu

我有一个函数
f
,它返回两个参数。在这个函数之后,我使用第一个参数。我需要第二个函数将东西与另一个函数
g
粘合在一起。因此,我的代码如下所示:

a, b = f()
# do stuff with a
g(b)
这是非常重复的,所以我想我可以使用类似RAII的方法。但是,由于我不知道对象何时会消亡,并且我的主要目标是消除重复代码,因此我使用了
with
语句:

with F() as a:
    # do stuff with a
就这样。基本上,我围绕这个函数创建了一个对象
F
,提供了
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
函数(显然还有
\uuuuuuuuuuuuuuuuuuuuuuuuuuu

然而,我仍然想知道这是否是正确的“Pythonic”方法来处理这个问题,因为
with
语句是用来处理异常的。尤其是这个
\uuuuuuuuuuuuuuuuuuuuuuuuuu
函数有三个参数,我现在不使用它们

编辑(进一步解释):
每当我调用
f()
时,我都需要使用
b
执行一些操作。这两者之间发生了什么并不重要。我把它表示为
g(b)
。正是这一点,我隐藏在with语句中。因此,程序员不必在每次调用
f()
后反复键入
g(b)
,这可能会变得非常混乱和混乱,因为
#do stuff with a
可能会变得冗长

对于阅读您的代码的其他人(或6个月后的您),上下文管理器可能会暗示资源的创建/初始化和关闭/删除,我会非常小心重新使用该习惯用法

您可以使用组合,而不是上下文管理器:

def func(a, b):
    # do stuff with a & optionally b

def new_f(do_stuff):
    a, b = f()
    do_stuff(a, b)
    g(b)


new_f(func)

对于阅读您的代码的其他人(或6个月后的您),上下文管理器可能会暗示资源的创建/初始化和关闭/删除,我会非常小心重新使用该习惯用法

您可以使用组合,而不是上下文管理器:

def func(a, b):
    # do stuff with a & optionally b

def new_f(do_stuff):
    a, b = f()
    do_stuff(a, b)
    g(b)


new_f(func)

使用
contextlib
模块是一种略为类似python的方法。您可以使用
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

from contextlib import contextmanager

def g(x):
    print "printing g(..):", x

def f():
    return "CORE", "extra"

@contextmanager
def wrap():
    a, b = f()
    try:
        yield a
    except Exception as e:
        print "Exception occurred", e
    finally:
        g(b)
if __name__ == '__main__':
    with wrap() as x:
        print "printing f(..):", x
        raise Exception()
输出:

$ python temp.py
printing f(..): CORE
Exception occurred
printing g(..): extra

使用
contextlib
模块是一种略为类似python的方法。您可以使用
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

from contextlib import contextmanager

def g(x):
    print "printing g(..):", x

def f():
    return "CORE", "extra"

@contextmanager
def wrap():
    a, b = f()
    try:
        yield a
    except Exception as e:
        print "Exception occurred", e
    finally:
        g(b)
if __name__ == '__main__':
    with wrap() as x:
        print "printing f(..):", x
        raise Exception()
输出:

$ python temp.py
printing f(..): CORE
Exception occurred
printing g(..): extra


是不是很重复?不清楚问题是什么,也不清楚为什么您认为上下文管理器是最佳解决方案。如果您经常使用该代码,请将其设置为带有参数
a
b
的函数。如果中间的位发生了变化,所以你认为你不能提取它,那么在调用<代码> g < />代码之前,添加一个新的参数,该函数是调用<代码> A<代码>(注意函数在Python中是第一类)。你能举一个不那么抽象的例子来说明你想要达到的目标吗?
g
是做什么的?你能确切地解释一下它是如何重复的吗?另外,您目前如何在with语句中使用
b
?就我个人而言,我更喜欢将
结合使用来处理类似于资源的东西。另一种选择是使用装饰器。到底什么是
g
?如果抛出异常,是否仍会发生这种情况?如果它不应该发生,是否应该进行其他类型的清理呢?我扩展了我的解释<代码>g
是必需的,无论发生什么。但目前我没有任何例外。好吧,你仍然没有解释这些
f
g
是什么,但是从你给我们的信息来看,这听起来像是上下文管理器的一个相当标准的案例。这是非常重复的吗?不清楚问题是什么,也不清楚为什么您认为上下文管理器是最佳解决方案。如果您经常使用该代码,请将其设置为带有参数
a
b
的函数。如果中间的位发生了变化,所以你认为你不能提取它,那么在调用<代码> g < />代码之前,添加一个新的参数,该函数是调用<代码> A<代码>(注意函数在Python中是第一类)。你能举一个不那么抽象的例子来说明你想要达到的目标吗?
g
是做什么的?你能确切地解释一下它是如何重复的吗?另外,您目前如何在with语句中使用
b
?就我个人而言,我更喜欢将
结合使用来处理类似于资源的东西。另一种选择是使用装饰器。到底什么是
g
?如果抛出异常,是否仍会发生这种情况?如果它不应该发生,是否应该进行其他类型的清理呢?我扩展了我的解释<代码>g
是必需的,无论发生什么。但目前我没有任何例外。好吧,你仍然没有解释这些
f
g
是什么,但从你给我们的信息来看,这听起来像是一个相当标准的上下文管理器案例。这很好,但遗憾不是一个选项,因为我需要更一般。将其视为复杂的
do_stuff
,它不能用一个函数来处理。您总是可以将多个调用拉入一个函数中。良好命名和文档化的函数比大型代码块更好。这很好,但遗憾的是,这不是一个选项,因为我需要更加通用。将其视为复杂的
do_stuff
,它不能用一个函数来处理。您总是可以将多个调用拉入一个函数中。良好命名和文档化的函数比大块代码要好。我想你把
@contextmanager
装饰器放错了函数。是的,这正是我想要的。但如果我(将来)需要处理异常,我需要我自己的具有退出和进入功能的高级类,对吗?不。检查我的更新上面。您也可以使用try来包围yield,除了finally块:)虽然它使代码读起来很好,但它很容易被误解,因为您并不是真正创建并关闭资源