繁体   English   中英

为具有递归的嵌套函数获取 functionType 的 python 函数

[英]getting a python function of functionType for a nested function with recursion

我正在尝试对嵌套函数(函数内的函数)进行单元测试,我正在使用来自以下链接的代码(“嵌套”是函数名称),它将提供闭包并返回一个可从测试中调用的有效函数。 它适用于简单的功能。 我试图让它适用于递归函数。

例如:我试图为“innerfunction”获取一个有效的函数,它在 co_freevars 中有一个条目为“innerfunction”。

我想为“内部函数”获取一个函数(我相信是 FunctionType)作为可调用的。 为了得到这个,我需要用一个带有“内部函数”的FunctionType的元组来调用FunctionType。 这变成了递归的“依赖”。 我怎样才能解决这个为“闭包”发送的参数的依赖关系

功能为

def toplevelfunction():
    def innerfunction(a):
        print ('val of a is ', a)
        if a > 0:
            innerfunction(a -1)
    innerfunction(10)

我正在使用的原始代码:

def freeVar(val):
  def nested():
    return val
  return nested.__closure__[0]

codeAttribute = '__code__' if sys.version_info[0] == 3 else 'func_code'

def nested(outer, innerName, **freeVars):
  if isinstance(outer, (types.FunctionType, types.MethodType)):
    outer = outer.__getattribute__(codeAttribute)
  for const in outer.co_consts:
    if isinstance(const, types.CodeType) and const.co_name == innerName:
      return types.FunctionType(const, globals(), None, None, tuple(
          freeVar(freeVars[name]) for name in const.co_freevars))

https://code.activestate.com/recipes/580716-unit-testing-nested-functions/

如何添加对闭包的支持,以便以下工作:

func = 嵌套(顶层函数,'内部函数')

功能(5)

将返回错误需要一个长度为 1 的闭包。添加一个引用“const”的闭包表明它是 CodeType 而不是 FunctionType。 在阅读完文档后,添加一个闭包值来引用自身似乎很棘手。

我确实发现内部函数为:

 {code} <code object innerfunction at 0x104b9bc00, file "/<filedirectory>/handle_results.py", line 44>
 co_argcount = {int} 1
 co_cellvars = {tuple} <class 'tuple'>: ()
 co_code = {bytes} b"t\x00\x00d\x01\x00|\x00\x00\x83\x02\x00\x01|\x00\x00d\x02\x00k\x04\x00r'\x00\x88\x00\x00|\x00\x00d\x03\x00\x18\x83\x01\x00\x01d\x00\x00S"
 co_consts = {tuple} <class 'tuple'>: (None, 'val of a is ', 0, 1)
 co_filename = {str} '/<fildirectory>/handle_results.py'
 co_firstlineno = {int} 44
 co_flags = {int} 19
 co_freevars = {tuple} <class 'tuple'>: ('innerfunction ',)
 co_kwonlyargcount = {int} 0
 co_lnotab = {bytes} b'\x00\x01\r\x01\x0c\x01'
 co_name = {str} 'innerfunction '
 co_names = {tuple} <class 'tuple'>: ('print',)
 co_nlocals = {int} 1
 co_stacksize = {int} 3
 co_varnames = {tuple} <class 'tuple'>: ('a',)

感谢您向我暗示您在问题中链接到的我的 ActiveState 配方的此限制!

您尝试对本地递归函数进行单元测试; 我的最小示例如下所示:

def f(x):
  def fac(n):
    return fac(n-1) * n if n > 1 else 1
  print "Faculty of", x, "is", fac(x)

因此,在单元测试中,您要测试内部函数fac() 简单地应用我的食谱会导致此错误:

nestedFac = nested(f, 'fac')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in nested
  File "<stdin>", line 7, in <genexpr>
KeyError: 'fac'

这是因为fac是内部函数中使用的标识符,您必须指定内部函数中使用的每个标识符的值。 可调用标识符也不例外:

nestedFac = nested(f, 'fac', fac=None)

这将fac设置为值None并且对nested的调用不再失败。

不幸的是,生成的函数将在您调用它时尝试调用None(...)

nestedFac(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in fac
TypeError: 'NoneType' object is not callable

您需要将函数本身作为fac的值传递以避免这种情况。 不幸的是,当您调用nested()时,您还没有它。 可以像这样重复包装:

nestedFac = nested(f, 'fac', fac=None)
nestedFac = nested(f, 'fac', fac=nestedFac)
nestedFac = nested(f, 'fac', fac=nestedFac)
nestedFac = nested(f, 'fac', fac=nestedFac)

这会将您的递归深度限制为您应用的包装数量:

nestedFac(2)
2
nestedFac(3)
6
nestedFac(4)
24
nestedFac(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in fac
  File "<stdin>", line 3, in fac
  File "<stdin>", line 3, in fac
  File "<stdin>", line 3, in fac
TypeError: 'NoneType' object is not callable

为避免这种情况,您可以将本地函数作为代理传递:

def q(*args, **kwargs):
  return nestedFac(*args, **kwargs)
nestedFac = nested(f, 'fac', fac=q)

或者作为lambda

nestedFac = nested(f, 'fac', fac=lambda *args, **kwargs:
    nestedFac(*args, **kwargs))

或者对于只有一个参数的特殊情况:

nestedFac = nested(f, 'fac', fac=lambda n: nestedFac(n))

不过,对nested()配方的扩展自动执行此操作将是更好的方法。 随意分叉配方并添加这个方面! :-)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM