0

I am trying to get this attribute which is very deeply nested.

The problem is that some of the values on the way tends to be None.

here is how I did it (the wrong way).

def name(x):
    x = x["relay_rendering_strategy"]
    if x:
        x = x["view_model"]
        if x:
            x = x["profile"]
            if x:
                x = x["event_place"]
                if x:
                    x = x["contextual_name"]
                    if x:
                        return x.lower()
    return ''
data = [x for x in get_events() if name(x) == 'ved siden af']

In kotlin there is a nice syntax like this:

val name = first?.second?.third?.andSoFourth ?: ''

Is there a similar awesome way you can do it in python???

mama
  • 2,046
  • 1
  • 7
  • 24
  • 1
    You could just try the nested lookup in a single statement, wrap it in a try/except and returning your default in the except? – Iain Shelvington Nov 19 '21 at 17:30
  • You might want to check out this answer: https://stackoverflow.com/questions/64285182/optional-chaining-in-python The Kotlin syntax you're referencing is called "optional chaining", and this post discusses a few ways to achieve that effect in Python – austin-schick Nov 19 '21 at 17:31

2 Answers2

3

You can do something similar with dict.get and default values:

def name(x):
    return x.get("relay_rendering_strategy", {}).get("view_model", {}).get("profile", {}).get("event_place", {}).get("contextual_name", "").lower()

Or use a simple try-except:

def name(x):
    try:
        return x["relay_rendering_strategy"]["view_model"]["profile"]["event_place"]["contextual_name"].lower()
    except KeyError:
        return ""

Or simply keep the nesting level down with a loop to be more DRY:

def name(x):
    for k in ("relay_rendering_strategy","view_model","profile","event_place","contextual_name"):
        if k not in x:
            return ""
        x = x[k]
    return x.lower()
user2390182
  • 72,016
  • 6
  • 67
  • 89
3

In python, it is better to ask forgiveness than permission.

Using try/except (as suggested by @Iain Shelvington).

def name(x):
    try:
        return x["relay_rendering_strategy"]["view_model"]["profile"]["event_place"]["contextual_name"].lower()
    except (KeyError, AttributeError):
        return ""
Andrew McClement
  • 1,171
  • 5
  • 14