2016-12-11 6 views
0

Ich habe eine Funktion, die einen Schlüssel übernimmt und geschachtelte Dicts durchläuft, um den Wert unabhängig von seiner Tiefe zurückzugeben. Ich kann jedoch nur den Wert zum Drucken erhalten, nicht zurückgeben. Ich habe die anderen Fragen zu diesem Thema gelesen und habe versucht 1. Ertrag zu implementieren 2. den Wert an eine Liste anzufügen und dann die Liste zurückzugeben.Rekursive Funktion druckt, gibt aber keine zurück

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 

Beispieldaten:

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')]))]))]))]) 

Wenn ich ausführen, um den gewünschten Wert druckt, aber nicht zurück:

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

Was geschieht? Warum bricht die Funktion nicht ab und gibt den Wert zurück, wenn sie gefunden wird?

+0

Sie müssen in Ihrer 'else' Klausel zurückgeben. – AChampion

+0

@AChampion Ich versuchte das- noch gibt 'None' zurück, und druckt nicht einmal den Wert –

+0

Lesen Sie hierzu: http://StackOverflow.com/Questions/11356168/Return-in-Recursive-Funktion – MYGz

Antwort

3

Eine einfache Lösung, Sie müssen ein verschachteltes Diktat finden, das einen Wert zurückgibt. Sie müssen nicht explizit eine else-Klausel verwenden, da die if zurückgibt. Sie brauchen auch nicht .keys() nennen:

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' 

Eines der Gestaltungsprinzipien von Python ist EAFP (einfacher für Vergebung als Erlaubnis bitten zu), was bedeutet, dass Ausnahmen werden häufiger verwendet als in anderen Sprachen. Das oben mit EAFP Design umgeschrieben:

+0

Nizza. Versuchte zu verstehen, @Mohammad Yusuf Ghazi Link, aber das dient als eine viel einfachere Erklärung. Vielen Dank –

0

Wie andere Leute kommentiert, müssen Sie Return-Anweisung in anderen Blöcken auch. Sie haben zwei if-Blöcke, so dass Sie zwei weitere Return-Anweisungen benötigen. Hier ist Code, der das tut, was Sie

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 
0

Ihr else Block den Wert muss zurückkehren wollen, wenn er sie findet.

Ich habe noch ein paar kleinere Änderungen an Ihrem Code vorgenommen. Sie brauchen nicht

if item_key in data.keys(): 

Statt zu tun, Sie einfach

if item_key in data: 

Ähnlich tun können, brauchen Sie nicht

for key in data.keys(): 

Sie können eine dict direkt iterieren (oder jede Klasse, die von einem dict abgeleitet ist), um über ihre Schlüssel zu iterieren:

for key in data: 

Hier ist meine Version des Codes, die auf Python 2.7 sowie 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) 

Ausgang

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

Beachten Sie, dass diese Funktion None wenn der isinstance(data, dict) Test nicht wieder ausgeführt werden soll, oder wenn die for Schleife nicht zurückkehrt. Es ist im Allgemeinen eine gute Idee, sicherzustellen, dass jeder mögliche Rückweg in einer rekursiven Funktion eine explizite return-Anweisung hat, da dies klarer macht, was passiert, aber IMHO ist es ok, diese Rückkehr implizit in dieser ziemlich einfachen Funktion zu lassen.

Verwandte Themen