可以控制在python中如何执行函数吗?

可以控制在python中如何执行函数吗?,python,python-3.x,function,Python,Python 3.x,Function,我知道python非常灵活,几乎可以允许用户想要的任何东西。然而,我从来没有见过也没有听说过这样的功能,在网上也找不到任何相关的东西:有可能一步一步地执行一个函数变量吗 def example_function(): print("line 1") # stuff print("line 2") # stuff return(3) def step_by_step_executor(fn): while fn.has_next_step(): print(fn.

我知道python非常灵活,几乎可以允许用户想要的任何东西。然而,我从来没有见过也没有听说过这样的功能,在网上也找不到任何相关的东西:有可能一步一步地执行一个函数变量吗

def example_function():
  print("line 1")
  # stuff
  print("line 2")
  # stuff
  return(3)

def step_by_step_executor(fn):
  while fn.has_next_step():
    print(fn.current_step)
    fn.execute_step()
  return fn.return

step_by_step_executor(example_function) 
# print("line 1")
# line 1
# stuff
# print("line 2")
# line 2
# stuff
# return(3)
# returns 3
我想我可以通过组合使用
inspect
exec
和可能的
\uuuuuuu call\uuuuuuuu
来实现类似的功能,但我想看看是否已经有了这样的名称和实现

示例用例:

@do_y_instead_of_x
def some_function():
  do stuff
  do x
  do more
some_function()
# does stuff
# does y
# does more

@update_progress_bar_on_loops
def some_other_function():
  do stuff
  for x in range...:
     ...
  do more
some_other_function()
# does stuff
# initializes a progress bar, reports whats going on, does the loop
# does more
怎么样?它比人们想象的要多,可以用来从根本上表示协同路由和排序,这一特性可能比构建迭代器更基本。你的例子是:

def example_function():
    print("line 1")
    yield
    print("line 2")
    yield
    print("line 3")
    return 3

def step_by_step_executor(fn):
    res = fn()
    while True:
        try:
            print(next(res))
        except StopIteration as e:
            retval = e.value
            break
    return retval

print(step_by_step_executor(example_function))
导致

line 1
None
line 2
None
line 3
3
因为生成器的返回值是作为所引发的停止迭代的值给出的。如果您选择间歇性地
生成
值(而不是空白的
生成
),您也将看到在每次迭代中打印的值


出现此类代码的一个常见位置是
contextmanager
装饰器,该装饰器用于通过一系列输入和退出步骤将生成器转换为上下文管理器。

您可以创建一个Python调试器
pdb.pdb
实例,并向其传递一个实现
写入的自定义类文件对象方法有选择地输出调试器输出的代码部分,以及
readline
方法始终向调试器发送
n
(缩写为
next
)命令。由于调试器总是两次输出从函数返回的行,第二次输出的前一行是
--Return--
行,因此可以使用标志来避免输出冗余的返回行:

import pdb

class PdbHandler:
    def __init__(self):
        self.returning = False

    def write(self, buffer):
        if buffer == '--Return--':
            self.returning = True

        # each line of code is prefixed with a '-> '
        _, *code = buffer.split('\n-> ', 1)
        if code:
            if self.returning:
                self.returning = False
            else:
                print(code[0])

    def readline(self):
        return 'n\n'

    def flush(self):
        pass

def example_function():
    print("line 1")
    print("line 2")
    return (3)

handler = PdbHandler()
print('returns', pdb.Pdb(stdin=handler, stdout=handler).runcall(example_function))
这将产生:

print("line 1")
line 1
print("line 2")
line 2
return (3)
returns 3

不确定python是否有类似于其内置的功能,但我认为“executor”是该机制的常用名称。可能很难找到一个好的参考,因为这个问题实际上非常普遍,不同的应用程序以不同的方式解决它。这个问题的理论答案可能是一个序列/控制/列表单子。调试器可能?使用Tcl/expect脚本驱动您正在描述的函数。将函数设为生成器,并在需要“停止”时生成值。@blhsing
pdb.runcall
看起来它是专门用于调试的。我不确定这是否会带来任何性能缺陷。(当我开始编码时,我会检查并考虑这是一个可能的解决方案),这会导致重复的收益率,并且我将不能传递任何函数(函数特别需要在每秒行中有一个收益率)。这将限制它对来自第三方库的函数的使用,例如(参见示例用例)使用
inspect.getsource(f)
并添加所述收益率,然后使用上述步骤执行器执行结果。有点老套。使用调试器可能是有意义的。如果要实现我自己,我想获取源代码并对每一行使用exec,但只要您能够充分控制参数的范围,这就行了。这根本不是一个安全的解决方案。除非您完全解析代码,否则当一行是多行语句的一部分时,您将很难识别插入
yield
语句的“行”的结尾。