0

Sorry if the title is a bit unclear, I didn't know how to really summarize the issue.

If I some list of objects like this:

class Item:
    x = 0
    y = OptionalMember() # this can be None

class OptionalMember:
    z = 1

And I want to use a list comprehension to collect from a list of Item objects, but including the value z when y is present, otherwise just taking None. If y was always present, of course it would simply be

xs = [(item.x, item.y.z) for item in items]

but then

AttributeError: 'NoneType' object has no attribute 'z'

so how to do it?

Anonymous Entity
  • 3,254
  • 3
  • 27
  • 41

2 Answers2

2

You can add a valueIfTrue if confition else valueIfFalse inside the list comprehension

xs = [(item.x, item.y.z if item.y else None) for item in items]
azro
  • 53,056
  • 7
  • 34
  • 70
2

Another option is to use getattr and provide a default value as the third argument.

xs = [(item.x, getattr(item.y, "z", None)) for item in items]
gold_cy
  • 13,648
  • 3
  • 23
  • 45
  • That also works, but seems less readable and "pythonic" than the other answer. Is there some case where this is "better" or actually required? – Anonymous Entity Jun 06 '21 at 12:41
  • in your opinion how is this less Pythonic? they are in essence the same. you can read more here —> https://stackoverflow.com/a/19123719/6817835 – gold_cy Jun 06 '21 at 12:49
  • There **is** a case where you have to it like this: If `item.y` can be **undefined**, you will get an error when calling `if item.y` – edit: Sorry, I did a mistake here. In this case, you'd have to use `getattr` to get the `y` attribute from item, so `getattr(item, 'y', None)` so it's not necessarily useful here. – fsimonjetz Jun 06 '21 at 12:51
  • also the other answer since it tests the truthiness of the value would fail in the case where item.y is anything but None or the OptionallMapping object – gold_cy Jun 06 '21 at 12:59