递归函数打印但不返回

时间:2016-12-11 08:23:59

标签: python recursion

我有一个函数,它接受一个键并遍历嵌套的dicts,无论其深度如何都返回值。但是,我只能获得打印的值,而不是返回。我已经阅读了有关此问题的其他问题,并尝试了1.实现yield 2.将值附加到列表然后返回列表。

def get_item(data,item_key):
    # data=dict, item_key=str
    if isinstance(data,dict):
        if item_key in data.keys():
            print data[item_key]
            return data[item_key]
        else:
            for key in data.keys():
                # recursion
                get_item(data[key],item_key)

item = get_item(data,'aws:RequestId')
print item

示例数据:

data = OrderedDict([(u'aws:UrlInfoResponse', OrderedDict([(u'@xmlns:aws', u'http://alexa.amazonaws.com/doc/2005-10-05/'), (u'aws:Response', OrderedDict([(u'@xmlns:aws', u'http://awis.amazonaws.com/doc/2005-07-11'), (u'aws:OperationRequest', OrderedDict([(u'aws:RequestId', u'4dbbf7ef-ae87-483b-5ff1-852c777be012')])), (u'aws:UrlInfoResult', OrderedDict([(u'aws:Alexa', OrderedDict([(u'aws:TrafficData', OrderedDict([(u'aws:DataUrl', OrderedDict([(u'@type', u'canonical'), ('#text', u'infowars.com/')])), (u'aws:Rank', u'1252')]))]))])), (u'aws:ResponseStatus', OrderedDict([(u'@xmlns:aws', u'http://alexa.amazonaws.com/doc/2005-10-05/'), (u'aws:StatusCode', u'Success')]))]))]))])

执行时,会打印所需的值,但不会返回:

>>>52c7e94b-dc76-2dd6-1216-f147d991d6c7
>>>None

发生了什么事?为什么函数在找到它时不会破坏并返回值?

3 个答案:

答案 0 :(得分:3)

一个简单的修复,你必须找到一个返回值的嵌套dict。您不需要显式使用else子句,因为if会返回。您也不需要致电.keys()

def get_item(data, item_key):
    if isinstance(data, dict):
        if item_key in data:
            return data[item_key]

        for key in data:
            found = get_item(data[key], item_key)
            if found:
                return found
    return None  # Explicit vs Implicit

>>> get_item(data, 'aws:RequestId')
'4dbbf7ef-ae87-483b-5ff1-852c777be012'

python的设计原则之一是EAFP(比请求更容易请求宽恕),这意味着异常比其他语言更常用。以上用EAFP设计改写:

def get_item(data, item_key):
    try:
        return data[item_key]
    except KeyError:
        for key in data:
            found = get_item(data[key], item_key)
            if found:
                return found
    except (TypeError, IndexError):
        pass
    return None

答案 1 :(得分:1)

正如其他人评论的那样,你也需要在else块中使用return语句。你有两个if块,所以你需要两个return语句。这是执行您可能需要的代码

from collections import OrderedDict

def get_item(data,item_key):
    result = []
    if isinstance(data, dict):
        for key in data:
            if key == item_key:
                print data[item_key]
                result.append(data[item_key])
            # recursion
            result += get_item(data[key],item_key)
        return result
    return result

答案 2 :(得分:0)

如果else块找到它,则需要返回该值。

我对您的代码进行了一些其他细微更改。你不需要做

if item_key in data.keys():

相反,你可以简单地做

if item_key in data:

同样,你不需要

for key in data.keys():

您可以直接遍历dict(或从dict派生的任何类)迭代其键:

for key in data:

这是我的代码版本,应该在Python 2.7和Python 3上运行。

from __future__ import print_function
from collections import OrderedDict

def get_item(data, item_key):
    if isinstance(data, dict):
        if item_key in data:
            return data[item_key]

        for val in data.values():
            v = get_item(val, item_key)
            if v is not None:
                return v

data = OrderedDict([(u'aws:UrlInfoResponse', 
    OrderedDict([(u'@xmlns:aws', u'http://alexa.amazonaws.com/doc/2005-10-05/'), (u'aws:Response', 
    OrderedDict([(u'@xmlns:aws', u'http://awis.amazonaws.com/doc/2005-07-11'), (u'aws:OperationRequest', 
    OrderedDict([(u'aws:RequestId', u'4dbbf7ef-ae87-483b-5ff1-852c777be012')])), (u'aws:UrlInfoResult', 
    OrderedDict([(u'aws:Alexa', 
    OrderedDict([(u'aws:TrafficData', 
    OrderedDict([(u'aws:DataUrl', 
    OrderedDict([(u'@type', u'canonical'), ('#text', u'infowars.com/')])), 
        (u'aws:Rank', u'1252')]))]))])), (u'aws:ResponseStatus', 
    OrderedDict([(u'@xmlns:aws', u'http://alexa.amazonaws.com/doc/2005-10-05/'), 
        (u'aws:StatusCode', u'Success')]))]))]))])

item = get_item(data, 'aws:RequestId')
print(item)

<强>输出

4dbbf7ef-ae87-483b-5ff1-852c777be012

请注意,如果None测试失败,或者isinstance(data, dict)循环无法返回,则此函数返回for。通常一个好主意是确保递归函数中的每个可能的返回路径都有一个明确的return语句,因为这样可以更清楚地发生了什么,但恕我直言,可以将这些返回隐含在这个相当简单的函数中。 / p>