4 ms·
def safe_navigation(obj, path: List[str], default=None): try: for key in path: obj = obj[key] return obj
by wodenokoto 3y ago
def safe_navigation(obj, path: List[str], default=None):
try:
for key in path:
obj = obj[key]
return obj
except KeyError:
return default
Yeah. I thought it would just be a try-except, but that turned out pretty ugly.
But really, how do you know if your path is missing or the object at the end of the path is None, without using exceptions for communicating this?
- o11c 3y agoI would write: def safe_navigation(obj: Any, *path: str, default: Any = None, strict: bool = False) -> Any: sentinel = object() if strict else None for key in path: obj = obj.get(key, sentinel) if obj is sentinel: return default return obj The only new disadvantage of this is that it only works on mappings and no longer works on sequences. But I really don't like having this much `Any`; it's generally a sign of poor design.
- ddejohn 3y agoI wouldn't call a function that mutates the input "safe navigation", personally :)
- o11c 3y agoEr, it doesn't? `.get()` (or `[]` in the original) doesn't change the object, and `obj =` only changes which object the local variable refers to? This isn't like C++ with its intrusive `=`.
- ddejohn 3y agoYou're right. Python is pass by reference and it's the reference being changed, not the object. This is what happens when you read code on the internet after drinks.
- ddejohn 3y agoThere's certainly humor in a function called "safe navigation" mutating the data structure I'm supposedly safely navigating through :D
- wodenokoto 3y agoI did type it on my phone, so I’m sure it needs a little correction (particularly the choice of exceptions is not optimal, I think) but feel free to run it in any recent python interpreter and return back with any mutation you see.
- wodenokoto 3y ago$ python3 Python 3.11.6 (main, Oct 2 2023, 20:46:14) [Clang 14.0.3 (clang-1403.0.22.14.1)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> from typing import List >>> def safe_navigation(obj, path: List[str], default=None): ... try: ... for key in path: ... obj = obj[key] ... return obj ... except KeyError: ... return default ... >>> obj = {1: {1: {1: 2}}} >>> safe_navigation(obj, [1,1,1]) 2 >>> obj {1: {1: {1: 2}}}
- dmr_92 3y agoI don't think this is correct . The name obj gets rebound, but the dictionary being traversed isn't mutated in any way.