glom
glom copied to clipboard
Safe navigation operator?
Have you considered adding a "safe navigation operator" to Glom?
It could be very elegant and powerful to use a target of a?.b?.c
, and it's a well established feature in several languages.
https://en.wikipedia.org/wiki/Safe_navigation_operator
Hmm, how would this differ from the current behavior of glom(target, 'a.b.c', default=None)
, for instance?
Also while it's apparently not the same as a null-coalescing operator (a fact I just learned thanks to you :) ), this may be relevant: http://glom.readthedocs.io/en/latest/faq.html#does-python-need-a-null-coalescing-operator
That looks like a decent replacement for my example and many other cases, but I have often done things like a.b?.c
in other languages. Currently I think you'd have to do something non-glom to express that?
It could also be nice to have a simple compact notation for the default=None
case.
i actually wrote this yesterday, using the unary invert ~
operator. it's basically just sugar around glom(target, T(...), default=None)
. example usage:
safe = U(obj)
value = ~safe.a.b[0].c
implementation:
class U(object):
def __init__(self, obj, t=glom.T, default=None):
self.obj = obj
self.t = t
self.default = default
def __getitem__(self, name):
return U(self.obj, self.t[name])
__getattr__ = __getitem__
def __invert__(self):
return glom.glom(self.obj, self.t, default=self.default)
note that this also changes attribute-style .
access to item access instead, like many templating languages. you can remove that by changing __getattr__ = __getitem__
to something like:
def __getattr__(self, name):
return U(self.obj, getattr(self.t, name))
Sorry, my opinions are stronger than my Python skills.
Is this code a way to make your own safe operator that works with glom?
yes. it's pretty much exactly what you asked for. :P
a.b?.c
could be implemented as glom(target, ('a.b', Coalesce('c', default=None)))
-- if I understand the intended semantics properly "error if a doesn't have a b attribute, but if b doesn't have a c return None instead"
Coalesce()
combined with tuple-chaining lets you fiddle "in the middle" of the operations; this is very wordy though
to go the other direction, if you has a?.b.c
is the intended behavior "if a doesn't have a b, immediately return None?" or "if a doesn't have b, substitute None then fail because None doesn't have a c?" -- that is, are the semantics exactly the same as get()?
oh! that reminds me, you can also do T.get()
or Call(getattr)
-- not that any of these are the same as having native support in Path
just other stuff in the neighborhood
this definitely bears more discussion, thank you very much for raising the issue :-)
yes. it's pretty much exactly what you asked for. :P
Unless I'm really confused, it's not the same as being able to write glom(data, 'a.b?.c')
, which is what I was suggesting.
Now, I'm not asking for anything. I just thought this could possibly be a nice feature idea for your library. If you don't think it is, you're most likely right!
Hey @snarfed, that's some pretty interesting shorthand! I'll have to keep invert in mind for future syntax enhancements :)
@larspetrus This is definitely an interesting case. I see the difference now, in the ability to control which segments are required, and which should be optionally traversed. Also, if Coalesce()
is the equivalent of a Python or
, then a safe navigation operator is sort of like saying output = a and a.b and a.b.c
.
Now, I'm not sure how often I've needed this fine-grained of control (i.e., at the sub-line level), but I'll keep an extra eye out going forward. If it seems like a powerful enough feature, you can bet it'll get integrated. Thanks!
Glad I could raise awareness :)