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块:)虽然它使代码读起来很好,但它很容易被误解,因为您并不是真正创建并关闭资源