【问题标题】:How to check if a python function uses a while loop? [duplicate]如何检查python函数是否使用while循环? [复制]
【发布时间】:2020-09-03 07:35:42
【问题描述】:
def foo():
    while <condition>:
        do something

def bar():
    for i in range(5):
        do something

假设我在上面的文件名test.py 中定义了两个函数。 python中有没有办法编写具有以下行为的函数?

import test

def uses_while(fn: Callable) -> bool:
    (what goes here?)

>>> uses_while(test.foo)
True
>>> uses_while(test.bar)
False

我基本上需要以编程方式检查函数是否使用了 while 循环,而无需手动检查代码。我曾想过使用 pdb.getsourcelines(),但是如果里面有 cmets 或带有单词“while”的字符串,那将不起作用。有什么想法吗?

【问题讨论】:

  • 我认为您可以过滤掉在 forwhile 之前包含任何非空白字符的任何源代码行,尽管挑战在于如何处理多行字符串.
  • 为什么要这样做?你能提供一些背景信息吗?
  • 是的,谢谢!我为 while 循环搜索了很长时间,但我没有想到要搜索 for 循环。
  • @Chris_Rands,是的,这是因为我正在构建一些测试来标记学生提交的内容,他们需要使用 while 循环作为标准的一部分。
  • @HHC 小心,因为他们可以添加 while True: break 并使用 for 循环,它会通过你的测试。

标签: python python-3.x unit-testing automated-tests bytecode


【解决方案1】:
import ast
import inspect
from typing import Callable

def uses_while(fn: Callable) -> bool:
    nodes = ast.walk(ast.parse(inspect.getsource(fn)))
    return any(isinstance(node, ast.While) for node in nodes)

在 Python 3.9+ 上,您必须将其更改为 from collections.abc import Callable

【讨论】:

  • 请注意,这将专门解析正在运行的 Python 版本;支持多个版本将更具挑战性。
  • @sabik 不需要为我的用例支持多个函数,但我假设 for 和 while 循环语法在 3.x 版本中不会有太大变化,如果有的话跨度>
  • @HHC 我认为问题在于,如果他们使用 3.8 中的某些东西,并且您在 3.6 中运行您的标记软件,ast 包可能会在他到达他没有的那部分时失败了解
  • @Adirio 打标软件运行的 python 版本与学生使用的相同,所以这不是问题。无论如何,我们不会使用比学生更低的版本来避免此类问题。
【解决方案2】:

我写了一个简单的函数,它可以检查作为参数给出的函数是否包含一个while循环:

import inspect

def test_while(func):
  flag = False

  body = inspect.getsourcelines(func)
  string = ''.join(body[0]).replace(' ', '')
  splited = string.split('\n')
  
  for chain in splited:
    if len(chain) > 0 and chain[0] is not '#':
      if chain.startswith('while'):
        flag = True

  return flag

【讨论】:

  • 如果有print("Please wait while calculating...")这样的行怎么办?
  • 我删除了缩进,所以我只需要检查 while 语句是否在链的开头,而不是简单地检查 while 语句是否在链中,我编辑我的答案
  • 这仍然可以用多行字符串来欺骗......
  • 使用字符串解析很难做到这一点。下一个挑战将是"""This is a while loop""",在while 之前有一个回车。
  • 是的,那是真的......哼哼,反正我不认为这是这样做的方法
猜你喜欢
  • 2022-07-06
  • 2022-01-27
  • 2016-02-13
  • 2013-05-09
  • 2015-04-22
  • 2016-10-04
  • 2021-09-09
  • 2018-09-08
  • 1970-01-01
相关资源
最近更新 更多