Is there a Python equivalent to the C# ?. and ?? operators?
Asked Answered
T

2

14

For instance, in C# (starting with v6) I can say:

mass = (vehicle?.Mass / 10) ?? 150;

to set mass to a tenth of the vehicle's mass if there is a vehicle, but 150 if the vehicle is null (or has a null mass, if the Mass property is of a nullable type).

Is there an equivalent construction in Python (specifically IronPython) that I can use in scripts for my C# app?

This would be particularly useful for displaying defaults for values that can be modified by other values - for instance, I might have an armor component defined in script for my starship that is always consumes 10% of the space available on the ship it's installed on, and its other attributes scale as well, but I want to display defaults for the armor's size, hitpoints, cost, etc. so you can compare it with other ship components. Otherwise I might have to write a convoluted expression that does a null check or two, like I had to in C# before v6.

Tronna answered 16/9, 2016 at 15:16 Comment(5)
You'll be using a ternary operator in place of thoseTrev
One important thing to remember is that you shouldn't try to make one language conform to your ideologies you got from another. Python has its own way of doing things like this. I suggest looking into one-line if/else statements.Priceless
@PM2Ring: the C# code doesn't either.Elisabeth
Also see Is there a Python equivalent of the C# null-coalescing operator?, and PEP 505 which discusses adding such operators to Python 3.6 (unlikely now that 3.6 is in beta)Elisabeth
This is even more useful whan dealing with methods rather than attributes, as it faciltates a quite succinct fluent style of writing code, without the None test making the code verbose and repetative. I hope PEP505 gets more time in the future.Otoplasty
E
19

No, Python does not (yet) have NULL-coalescing operators.

There is a proposal (PEP 505 – None-aware operators) to add such operators, but no consensus exists wether or not these should be added to the language at all and if so, what form these would take.

From the Implementation section:

Given that the need for None -aware operators is questionable and the spelling of said operators is almost incendiary, the implementation details for CPython will be deferred unless and until we have a clearer idea that one (or more) of the proposed operators will be approved.

Note that Python doesn't really have a concept of null. Python names and attributes always reference something, they are never a null reference. None is just another object in Python, and the community is reluctant to make that one object so special as to need its own operators.

Until such time this gets implemented (if ever, and IronPython catches up to that Python release), you can use Python's conditional expression to achieve the same:

mass = 150 if vehicle is None or vehicle.Mass is None else vehicle.Mass / 10
Elisabeth answered 16/9, 2016 at 15:35 Comment(4)
Yep, I was thinking of something like that; was just hoping there'd be a more concise way! I wonder what's so controversial about the "spelling" of operators?Tronna
@ekolis: the most controversial part is wether or not to elevate None to a level where it gets dedicated operators. Then there are parsing and precedence issues to consider where these operators would really clash with the rest of the language.Elisabeth
I was thinking I could write a function similar to the "if" function in Excel, but I don't think I could write it as ifnone(vehicle, vehicle.Mass, 150) because vehicle.Mass would have to be evaluated first which would cause vehicle to be dereferenced even if it's None, right? I suppose I could pass in a lambda but that would be almost as complicated as the if statement you suggested...Tronna
@ekolis: yup, the argument expressions are executed before the ifnone() function is called, as Python would pass in the result of each expression. You could make the second operand an attribute name (a string) and use getattr(firstargument, secondargument) in the function to resolve that, perhaps?Elisabeth
L
0

The Python equivalent is probably to just do it yourself if you want it:

class Nullsafe:
    def __init__(self, obj):
        self.obj = obj
    def __repr__(self):
        return f"{type(self).__name__}({self.obj!r})"
    def __getattr__(self, attr):
        return type(self)(getattr(self.obj, attr, None))
    def get(self, default=None):
        return default if self.obj is None else self.obj
>>> Nullsafe(range(5)).stop.get("900")
5
>>> Nullsafe(range(5)).start.bogominaxed.doubly.get("No such attribute!")
'No such attribute!'

Wrap __call__, __getitem__, etc. too as needed.

Loleta answered 29/11, 2023 at 2:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.