In JavaScript (and Node.js and TS), when we have an object A which has an attribute B, which has an attribute C, which has an attribute D and so on, we may use it like that:
const x = A?.B?.C?.D
Is there something similar in Python?
I want x to be None if any of A, B, C, or D is None. Actually, I need x = A.B.C.D or DEFAULT_VALUE
What I do today is very verbose:
x = None
if A is not None and A.B is not None and A.B.C is not None:
    x = A.B.C.D
Is there a one-line solution in Python?
I prefer an approach like this, but it is still very verbose and I repeat myself. Looking for DRY.
x = A and A.B and A.B.C and A.B.C.D or DEFAULT_VALUE
There is probably no such concise solution in Python. The most "pythonic" way would probably be to "ask for forgiveness rather than permission" (see the "EAFP" entry in the Python Glossary), i.e. to use a try-except statement that directly tries to access D (no need for intermediate checks) and that fails gracefully by providing the required DEFAULT_VALUE in the error case:
DEFAULT_VALUE = ...  # TODO: Provide default
try:
    x = A.B.C.D
except (NameError, AttributeError):
    x = DEFAULT_VALUE
You only need the NameError for the case that A might not exist at all. If you are sure that A exists (i.e. A has been defined and holds any value including None) you can drop it from the except clause.
I would define a function that allows you get the desired behavior in just one line:
def f(x, lst, default_val=None):
    for att in lst:
        if hasattr(x, attr):
            x = getattr(x, attr)
        else:
            return default_val
    return x
Now you can do things like this:
X = f(A, ['B', 'C', 'D'])
As suggested in the comments, if you don't need a default value, then you can just define the function as follows:
def f(x, lst):
    for att in lst:
        x = getattr(x, attr, None)
    return x
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With