9

Coming from Swift I'm having a bit of a hard time working with .None type of Python. I have a few functions which might return None if the object I'm looking for is not found in the array.

Then I have to nest my code as follows:

varA = self.getVariableByName(Variables.varA) 
if varA is None: 
    varB = self.getVariableByName(Variables.varB)
    varC = self.getVariableByName(Variables.varC) 
    if varB is not None and varC is not None: 
        # Do something with varB and varC 

In Swift I used to be able to bind the variables in the if statement

let f = getVariableByName
if f(Variables.varA) == nil, let varB = f(Variables.varB), let varC = f(Variables.varC) {
    // Do something with varB and varC
}

What is a more 'pythonic' way of dealing with None?

Emptyless
  • 2,964
  • 3
  • 20
  • 30
  • 3
    It somewhat depends what you want to "do" with `varB` and `varC`… `try: ... except TypeError: ...` could be a pythonic approach. – deceze Jun 13 '17 at 12:18
  • I just want to have the code nested as little as possible and use as few lines as possible. Most of the time when using the same function to retrieve variables it can be shortened but I have no idea how to do it in Python (binding in if-statements not a possibility). As for what varB and varC, these 2 will combine some of there properties to make a simulated varA but I left the implementation/variable names out to get it straight to the point of the question – Emptyless Jun 13 '17 at 12:22
  • 1
    Looking at what you are doing, it appears this might be a case for overloading the `[ ]` and `in` operators and implement the `__getitem__` and `__contains__` methods in your class. – cdarke Jun 13 '17 at 12:23
  • 1
    @cdarke: Perfect! I found this link to complement your suggestion: https://stackoverflow.com/questions/2217001/override-pythons-in-operator – Emptyless Jun 13 '17 at 12:27
  • check this it might give you an explanation. https://stackoverflow.com/questions/19473185/what-is-a-none-value – skr Jun 13 '17 at 12:35
  • This is one of the things I really wish Python could do! – brandonscript Apr 06 '21 at 05:51

4 Answers4

7

You can use the walrus operator (:=) from python 3.8 and upwards to make the assignment statement into an expression. Then you can check whether the assignment resulted in None within the if statement to decide whether to continue or not.

if (var_a := self.get_variable_by_name(Variables.var_a)) is not None:
    var_b = self.get_variable_by_name(Variables.var_b)
    var_c = self.get_variable_by_name(Variables.var_c)
    if var_b is not None and var_c is not None:
        # Do stuff...
Ted Klein Bergman
  • 9,146
  • 4
  • 29
  • 50
6

you can use the ":=" operator:

if varB := getVariableByName(Variables.varB):
    pass
luisbunuel
  • 294
  • 3
  • 5
  • 3
    This answer lacks informations about the used operator ("walrus operator"/"assignment expression operator", from Python 3.8+). Ted Klein Bergman's answer below provides such knowledge. – vmonteco Jan 27 '22 at 14:19
1

I believe the nicest way to handle this case is exception handling. E.g. make self.getVariableByName raise an Exception if the element is not found. Then you could do:

try:
    varA = self.getVariableByName(Variables.varA)
except RuntimeError:
    varB = self.getVariableByName(Variables.varB)
    varC = self.getVariableByName(Variables.varC)
    # do something with varB and varC

to get the equivalent of your Swift example.

If you cannot/do not want to change self.getVariableByName, the best you can do is:

f = self.getVariableByName
if f(Variables.varA):
    varB, varC = f(Variables.varB), f(Variables.varC)
    if not (varB is None or varC is None):
        # do something with varB and varC
Michael
  • 657
  • 5
  • 22
Nablezen
  • 362
  • 2
  • 10
  • An if-let statement automatically unpacks an `Optional` in Swift, varB and varC are optionals of type `Variable?`. If either of them is of the `.None` type (nill) the if-statement is not executed. Therefore if you are inside the if body varB and varC must have a value. – Emptyless Jun 13 '17 at 12:37
-1
if not hasattr(Variables, 'varA'):
  varB = Variables.varB

but sure varB can be missing to, so it's good to check if there is such attribute or to use getattr() with default value or to catch AttributeError exception.

RandomB
  • 3,367
  • 19
  • 30