En JavaScript, si no estoy seguro de si todos los elementos de la cadena existen o no están definidos, puedo hacer foo?.bar , y si bar no existe en foo , el intérprete lo cortocircuitará en silencio y no arrojará un error .
¿Hay algo similar en Python? Por ahora, lo he estado haciendo así:
if foo and foo.bar and foo.bar.baz: # do somethingMi intuición me dice que esta no es la mejor manera de verificar si todos los elementos de la cadena existen. ¿Hay una forma más elegante/Pythonic de hacer esto?
La forma más pitónica es:
try: # do something ... except (NameError, AttributeError) as e: # do something else ...Si es un diccionario, puede usar get(keyname, value)
{'foo': {'bar': 'baz'}}.get('foo', {}).get('bar')Combinar algunas de las otras respuestas en una función nos da algo que es fácil de leer y algo que se puede usar con objetos y diccionarios.
def optional_chain(root, *keys): result = root for k in keys: if isinstance(result, dict): result = result.get(k, None) else: result = getattr(result, k, None) if result is None: break return resultUsando esta función, simplemente agregaría las claves/atributos después del primer argumento.
obj = {'a': {'b': {'c': {'d': 1}}}} print(optional_chain(obj, 'a', 'b'), optional_chain(obj, 'a', 'z'))Nos da:
{'c': {'d': 1}} NonePuedes usar el Glom.
from glom import glom target = {'a': {'b': {'c': 'd'}}} glom(target, 'abc', default=None) # returns 'd'Combinando algunas cosas que veo aquí.
from functools import reduce def optional_chain(obj, keys): try: reduce(getattr, keys.split('.'), root) except AttributeError: return None optional_chain(foo, 'bar.baz') O en su lugar, extienda getattr para que también pueda usarlo como un reemplazo directo para getattr
from functools import reduce def rgetattr(obj, attr, *args): def _getattr(obj, attr): return getattr(obj, attr, *args) return reduce(_getattr, attr.split('.'), obj) Con rgetattr aún puede generar un AttributeError si la ruta no existe, y puede especificar su propio valor predeterminado en lugar de Ninguno.
Me gustan los lenguajes modernos como Kotlin que permiten esto:
foo?.bar?.bazRecientemente me divertí intentando implementar algo similar en python: https://gist.github.com/karbachinsky/cc5164b77b09170edce7e67e57f1636c
Desafortunadamente, el signo de interrogación no es un símbolo válido en los nombres de atributos en python, por lo que usé una marca similar de Unicode :)