Python装饰器用于简单递归?在标准库中还是其他地方?

6
我希望你能帮我找到一个Python装饰器,可以让函数变成递归的。我发现我经常要写这样的函数:
def xyz(data):
    if not isinstance(data, TypeThatDenotesSingularity):
        return map(xyz, data)
    return singular_xyz(data)

我想在标准库中一定有一个装饰器可以稍微简化一下表示方法:

@recursive(TypeThatDenotesSingularity)
def xyz(data):
    return singular_xyz(data)

我一直在搜索,但似乎没有取得任何进展。也许我缺少一些必要的术语?

谢谢你指引我正确的方向!


(Note: No changes were made to the HTML tags.)

+1 是因为我自己写过这种代码很多次。不过有更好的检查基本情况的方式(例如,使用变量类)。我怀疑标准库中没有任何内容。也许在 functools 中可以找到... (编辑:我已经检查了,不是这种情况) - user395760
有时这是最佳选择的情况,但如果我最终这样做了,通常是因为代码写得不够仔细。在调用函数的位置,应该明确无歧义地表明您是否拥有一个集合或单个项,因此您可以在该端编写适当的代码。如果某些东西既可以是单个的,也可以是多个的,请不要特别处理单个项,而是将其放在长度为1的集合中。 - Thomas K
@Thomas K:我不同意。你在概括。 - Tim Molendijk
Numpy有一个用于数组广播的装饰器,可能已经足够了:http://stackoverflow.com/questions/3443234/array-broadcasting-with-numpy/3443301#3443301 - Beni Cherniavsky-Paskin
@Tim:嗯,是的。我说过有些情况下它很有用,也许你的情况就是其中之一。但如果你发现自己经常这样做,那么值得考虑的是这不是“唯一明显的方法”。当我发现自己写这样的代码时,我通常会意识到有更好的方法。 - Thomas K
@Thomas:有些数据结构确实需要递归处理,比如树形结构(XML)。 - user395760
2个回答

3
这个怎么样呢:
def recursive(stop_type):
    def _inner(func):
        def _recursive(data, *args, **kw):
            if not isinstance(data, stop_type):
                return map(_recursive, data)
            return func(data, *args, **kw)
        return _recursive
    return _inner

如果使用@recursive(MySingularType),其工作原理如下所述:

  1. 在函数装饰时,使用参数stop_type调用递归函数。
  2. 递归函数返回闭包_inner
  3. 立即使用要装饰的函数调用_inner,同样是在编译时进行。
  4. _inner返回闭包_recursive,现在这个新函数是在调用装饰后的函数时被调用的函数。

现在,当您调用函数时:_recursive会被调用。如果类型匹配,则返回函数结果。否则,无限地映射另一个对_recursive的调用(真正的说法是,一直映射到StackOverflowium)。

注意: 如果装饰的函数始终只接收单个值,则可以省略*args**kwargs


很酷。但你知道有没有包含其中之一的库吗?我讨厌维护专有的工具集。 - Tim Molendijk

1

我不知道装饰器,但如果你发现自己一遍又一遍地重写相同的模式,你可以用一个类来实现它。

class Recursive(object):
    def __init__(self, check_type, singular):
        self.check_type = check_type
        self.singular = singular

    def __call__(self, data):
        if not isinstance(data, self.check_type):
            return map(self, data)
        return self.singular(data)

你不需要一个类。只有极少数(相当复杂)的生成器需要整个类来进行合理化。大多数都可以像这个一样,很好地编写成闭包。 - user395760
类,闭包,它们的区别主要在于语法。 - nmichaels
1
是的,我可以自己编写一个。但我更愿意重用一些经过验证的代码,而不是将另一个责任块堆叠到自己的堆上。 - Tim Molendijk
@Tim:啊,我错过了你在寻找库中的内容。阅读理解差。糟糕! - nmichaels
我认为在__init__中你忘记了 self.singular = singular - AFoglia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接