Python - 如何抽象通用 starting/ending 代码

Python - how to abstract common starting/ending code

我有一堆方法,看起来都像这样:

def myFunc():
    ...
    {initialise stuff}
    {do stuff}
    {finalise stuff}
    ...

其中 {initialise stuff}{finalise stuff} 对于每种方法 相同 ,并且 {do stuff} 可以使用 {initialise stuff} 中定义的变量。

为了避免重复,我想把{initialise stuff}{finalise stuff}放在一个单独的方法中,可以从myFunc()内部调用。所以,像这样:

def wrap(innerMethod):
    vars = {initialise stuff}
    innerMethod(vars)
    {finalise stuff}

def myFunc():
    ...
    wrap(lambda vars :
        {do stuff}
    )
    ...

不幸的是,Python 中似乎有 (除非最近 2 年才添加此功能)。因此,如果 {do stuff} 比单行长,这似乎不起作用。我可以将 {do stuff} 放入一个单独的方法中,但我不想这样做,因为:

有没有其他方法把{initialise stuff}{finalise stuff}放到一个单独的方法中?

您可以尝试 functools.wrapsdecorator:

import functools

def mywrapper(f):
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        print("{initialize_stuff}")
        result = f(*args, **kwargs)
        print("{finalize_stuff}")
        return result
    return wrapper

@mywrapper
def myFunc():
    print("{innerMethod}")

输出:

>>> myFunc()
{initialize_stuff}
{innerMethod}
{finalize_stuff}

Context managers 提供最佳解决方案 - 感谢@user2357112 的建议。

from contextlib import contextmanager

@contextmanager
def wrap():
  {initialise stuff}
  yield {stuff-to-return-to-method}
  {finalise stuff}

def myFunc():
  with wrap() as vars:
    {do stuff}

您甚至可以将参数传递给 wrap 并在初始化中使用它们。

如果你想要 {finalise stuff} 到 运行 即使包装代码抛出异常(你通常希望使用上下文管理器),你应该将 yield 包装在 try 并将定稿放在 finally:

@contextmanager
def wrap():
  {initialise stuff}
  try:
    yield {stuff-to-return-to-method}
  finally:
    {finalise stuff}