22

Is there a Pythonic way to grab a property if an object exists on one line of code? Currently in the code below if someone passes in a None type object the code will break, so I need some clean way to check that it is not None, but on one line of code. C# has the ?. syntax that works really well, so looking for something like that.

class MyClass:
    def __init__():
        self.my_property = "Hello, World!"

def print_class_property(myClassInstance):
    print(myClassInstance???.my_property) # Here is where I need something inline
CamJohnson26
  • 1,119
  • 1
  • 15
  • 40
  • 1
    Why one line? Just because something terse doesn't make it better. Anyway, you can use `getattr`. – Christian Dean Sep 06 '17 at 23:46
  • If someone passes None to your `print_class_property`, that's their bug, not yours. That said, Python doesn't have a null-coalescing operator or anything like that. – user2357112 Sep 06 '17 at 23:46
  • Because these objects are properties on a list of objects and I have to do this check about 20 times. I can do a null check everytime but it feels like Python should have something. – CamJohnson26 Sep 06 '17 at 23:47
  • getattr won't work because it assumes the object already exists – CamJohnson26 Sep 06 '17 at 23:48
  • 1
    @CamJohnson26 See my answer. – Christian Dean Sep 06 '17 at 23:48
  • @CamJohnson26 `getattr` has a `default` argument. Usually in Python, you would probably just use `try: ... except AttributeError` That would be considered [*Pythonic*](https://stackoverflow.com/questions/11360858/what-is-the-eafp-principle-in-python) – juanpa.arrivillaga Sep 06 '17 at 23:51
  • 3
    why not `b = a.attr if a is not None else 'some default value'`? – khachik Sep 06 '17 at 23:55
  • or if you don't mind all false values then you can use `b = a and a.attr or None` – khachik Sep 06 '17 at 23:56
  • @khachik i think the reason is a.attr may not have yet existed causing a keyerror – Kamel Nov 18 '19 at 05:30

1 Answers1

40

You can use the built-in function getattr. It allows an optional third argument that will be returned if the object passed in doesn't have the specified attribute. From the docs:

getattr(object, name[, default])

Return the value of the named attribute of object. name must be a string. If the string is the name of one of the object’s attributes, the result is the value of that attribute. For example, getattr(x, 'foobar') is equivalent to x.foobar. If the named attribute does not exist, default is returned if provided, otherwise AttributeError is raised.

Bold emphasis mine.

>>> getattr(None, 'attr', 'default')
'default'

Here's an example pertaining more to your problem:

>>> class Class:
    def __init__(self):
        self.attr = 'attr'

        
>>> def func(obj):
    return getattr(obj, 'attr', 'default')

>>> func(Class())
'attr'
>>> func(None)
'default'

As @juanpa.arrivillaga said in the comments, another common idiom when dealing with cases such as this is to use try/except. See What is the EAFP principle in Python?.

Community
  • 1
  • 1
Christian Dean
  • 22,138
  • 7
  • 54
  • 87