2017-05-10 2 views
2

Ich habe dieses Stück Code, um einen Wert aus einem Dictionary-ObjektZugriff ein Wörterbuch Wert mit dynamischem Pfad in Python mit

extracted_value = response_content["retrievePolicyBillingSummariesResponse"]["billingSummaries"]["policyBillingSummary"][0]["billingSummary"]["lastPayment"]["status"] 
extracted_value = response_content["retrievePolicyBillingSummariesResponse"]["billingSummaries"]["policyBillingSummary"][0]["billingSummary"]["bill"]["dueDate"] 

Dies sind nur zwei Proben zu extrahieren, aber ich habe ein Dutzend von diesem mit verschiedenen Schlüsseln/Pfadkombinationen. Wie kann ich nenne nur diese ein Modul mit und tun so etwas wie dieses

def get_value_from_content (response_content, my_path): 
    # how can I use the value in my_path as the key instead of this hard coded path ? 
    extracted_value = response_content["retrievePolicyBillingSummariesResponse"]["billingSummaries"]["policyBillingSummary"][0]["billingSummary"]["lastPayment"]["status"] 
    #extracted_value = response_content using my_path is what I would like to do 
    return extracted_value 

#I get this from a REST API call but skipping the code here and just hard coding to ask the question here 
response_content = {u'retrievePolicyBillingSummariesResponse': {u'billingSummaries': {u'policyBillingSummary': [{u'policy': {u'status': u'A', u'policyNumber': u'xyz123', u'writingCompany': u'FBI', u'renewalFlag': u'false', u'convertedRenewalOffer': u'false', u'termExpirationDate': u'2017-06-26', u'lineOfBusiness': u'PC', u'termEffectiveDate': u'2016-06-26', u'riskState': u'CA', u'insureds': {u'namedInsuredSummary': [{u'preferredPostalAddress': {u'streetAddressLine': u'1 disney', u'cityName': u'palo alto', u'zipCode': u'94100', u'isoRegionCode': u'CA'}, u'name': {u'lastName': u'DOE', u'fullName': u'john doe', u'firstName': u'john'}}]}, u'additionalInterests': {u'additionalInterest': [{u'billTo': u'N', u'name': {u'partyType': u'Organization'}}]}, u'type': u'PA', u'statusDescription': u'Active', u'dataSource': u'from_heaven'}, u'billingSummary': {u'paymentRestriction': u'false', u'nextInstallmentAmount': u'0.00', u'bill': {u'installmentNumber': u'1', u'statementDate': u'2016-06-26', u'paymentPlan': u'Direct', u'installmentAmount': u'12.00', u'totalBillAmountDue': u'1.76', u'previousBalance': u'0.00', u'dueDate': u'2016-06-26', u'billingPlan': u'ANN'}, u'lastPayment': {u'status': u'A'}, u'currentBalance': u'16.66', u'payOffAmount': u'15.66', u'isRestrictedToPay': u'false'}}]}}} 

my_path = '["retrievePolicyBillingSummariesResponse"]["billingSummaries"]["policyBillingSummary"][0]["billingSummary"]["lastPayment"]["status"]' 
get_extracted_item = get_value_from_content(response_content,my_path) 

my_path = '["retrievePolicyBillingSummariesResponse"]["billingSummaries"]["policyBillingSummary"][0]["billingSummary"]["bill"]["dueDate"]' 
get_extracted_item = get_value_from_content(response_content,my_path) 
+0

was ist mit dem Modul, das Sie vorgeschlagen haben nicht funktioniert, wie Sie wollen es zu? – davedwards

+0

mit String-Pfad wie dieser ist keine gute Lösung, da es geparst oder ausgewertet werden muss, wenn es einfach geändert werden kann in Liste der Schlüssel/Indizes mit Iterieren durch sie –

+0

Beachten Sie, dass [Using eval ist eine schlechte Praxis] (http://stackoverflow.com/questions/1832940/is-using-eval-in-python-a-bad-practice). – Kanak

Antwort

-1

Was ist eine rekursive Funktion?

def get_value(response, index): 
    if len(index) > 1: 
     return get_value(response[index[0]], index[1:]) 
    else: 
     return response[index[0]] 

index = ["retrievePolicyBillingSummariesResponse", "billingSummaries", "policyBillingSummary", 0, "billingSummary", "lastPayment", "status"] 

get_value(response_content, index) 
0

Was ist eine iterative Lösung, wie folgt:

response_content = {u'retrievePolicyBillingSummariesResponse': {u'billingSummaries': {u'policyBillingSummary': [{u'policy': {u'status': u'A', u'policyNumber': u'xyz123', u'writingCompany': u'FBI', u'renewalFlag': u'false', u'convertedRenewalOffer': u'false', u'termExpirationDate': u'2017-06-26', u'lineOfBusiness': u'PC', u'termEffectiveDate': u'2016-06-26', u'riskState': u'CA', u'insureds': {u'namedInsuredSummary': [{u'preferredPostalAddress': {u'streetAddressLine': u'1 disney', u'cityName': u'palo alto', u'zipCode': u'94100', u'isoRegionCode': u'CA'}, u'name': {u'lastName': u'DOE', u'fullName': u'john doe', u'firstName': u'john'}}]}, u'additionalInterests': {u'additionalInterest': [{u'billTo': u'N', u'name': {u'partyType': u'Organization'}}]}, u'type': u'PA', u'statusDescription': u'Active', u'dataSource': u'from_heaven'}, u'billingSummary': {u'paymentRestriction': u'false', u'nextInstallmentAmount': u'0.00', u'bill': {u'installmentNumber': u'1', u'statementDate': u'2016-06-26', u'paymentPlan': u'Direct', u'installmentAmount': u'12.00', u'totalBillAmountDue': u'1.76', u'previousBalance': u'0.00', u'dueDate': u'2016-06-26', u'billingPlan': u'ANN'}, u'lastPayment': {u'status': u'A'}, u'currentBalance': u'16.66', u'payOffAmount': u'15.66', u'isRestrictedToPay': u'false'}}]}}} 

my_path = [ 
    "retrievePolicyBillingSummariesResponse", 
    "billingSummaries", 
    "policyBillingSummary", 
    0, 
    "billingSummary", 
    "lastPayment", 
    "status" 
] 

def get_value_from_content(extraction, my_path): 
    for el in my_path: 
     if isinstance(extraction, dict): 
      extraction = extraction.get(el, extraction) 
     else: 
      extraction = extraction[el] 
    return extraction 

extraction = get_value_from_content(response_content, my_path) 
print(extraction) 

Die Funktion get_value_from_content noch kürzer sein kann als zuvor, dh

def get_value_from_content(extraction, my_path): 
    for el in my_path: 
     extraction = extraction[el] 
    return extraction 

Diese letzte Version von get_value_from_content ist dennoch mehr anfällig für das Auslösen von Ausnahmen, wenn eine, z habe die Verkettung von Pfadkomponenten falsch gelesen. Es bleibt somit zu prüfen, ob das String-Objekt my_path menschlich oder maschinell hergestellt ist.

In beiden Fällen wird "A" zurückgegeben. Getestet in Python 2 und 3. Beachten Sie auch, dass ich eine iterative Lösung gegenüber einem rekursiven seit the former is usually faster than the latter. Zwischen 20% and 40% faster in the present case.

Das gesagt, dies nicht die Frage, da my_path ist ursprünglich kein Listenobjekt, sondern ein String-Objekt. Um die Frage zu adressieren, würde man zuerst diese Zeichenfolge in eine Liste von Schlüsseln/Indizes konvertieren und sie dann wie oben beschrieben verarbeiten. Oder, wie es bei @Minji der Fall ist, könnte man die integrierte Python-Funktion eval verwenden. Auch wenn diese Funktion a bad practice heißt, frage ich mich, inwieweit die Verwendung von eval in dieser Situation nicht als der beste Weg beschrieben werden kann. kleine Utility-Funktion zu schreiben, wie

def extract_from_dictionary(dictionary, *keys_or_indexes): 
    value = dictionary 
    for key_or_index in keys_or_indexes: 
     value = value[key_or_index] 
    return value 

-1

eval() interpretiert einen String als Code

def get_value_from_content (response_content, my_path): 
    # string is arguments name 
    item = "response_content" + my_path 
    return eval(item) 
+0

Danke, das Problem behoben ... –

+0

nicht in der Lage, für zwei Antworten upvote ... aber Danke für die Antwort ! –

2

vor allem wird es einfacher sein, wie wir aus Ihrem Beispiel sehen kann, gibt ein Objekt namens billingSummary das erscheint in den erforderlichen Pfaden, so können wir mit

def get_billing_summary(response_content): 
    return extract_from_dictionary(
     response_content, 
     "retrievePolicyBillingSummariesResponse", 
     "billingSummaries", 
     "policyBillingSummary", 
     0, 
     "billingSummary") 
vermeiden

dann können wir einfach

def get_value_from_content(response_content, *keys): 
    billing_summary = get_billing_summary(response_content) 
    extracted_value = extract_from_dictionary(billing_summary, 
               *keys) 
    return extracted_value 

schreiben und benötigten Objekte erhalten wie

last_payment_status = get_value_from_content(response_content, 
              "lastPayment", 
              "status") 
bill_due_date = get_value_from_content(response_content, 
             "bill", 
             "dueDate") 
print("last_payment_status:", last_payment_status) 
print("bill_due_date:", bill_due_date) 

gibt uns

last_payment_status: A 
bill_due_date: 2016-06-26 
+0

das sieht gut aus, für die nächsten Tage werde ich eval() benutzen und nächste Woche auf diese Route umziehen. Hoffentlich kann ich mit Fragen zur Klärung zurückkommen, sobald ich dies eingeweicht habe - :) –

+0

Sie sind willkommen –

+0

Gibt es eine Möglichkeit, den Inhalt der Antwort auf eine schöne Weise zu sehen? Ich meine, leicht lesbares Format .. genau wie Json Verschönerungen? Ich kann dies nicht in einem besseren Format mit einem Json Beautifier aufgrund der Listen dazwischen sehen .. nicht benötigt programmgesteuert, aber einfach so, um zu versuchen, Dienstprogramme für andere Antworten zu erstellen? (Die mit einer anderen Struktur) –

Verwandte Themen