1

In Ruby an empty array returns a nil if the first element is accessed:

2.1.2 :005 > arr = []
  => [] 
2.1.2 :006 > arr.first
  => nil 
2.1.2 :007 > arr[0]
  => nil 

I know Python lists are not exactly the same as Ruby arrays, but if you try the equivalent action, you get an error:

>>> l = []
>>> l[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>

How can I instead of an error get a False or None value?

Ideally I'd like an assignment like this to resolve to None / False if the function call returns nothing, but with an inline check rather than a if block.

tp_journal = self.pool.get('account.journal').browse(cr, uid, tp_ids, context=context)[0]
2
  • Use a try ... except clause. Commented Sep 16, 2014 at 14:12
  • 1
    ((expression) or [None])[0] would be a simple hack to achieve that. Commented Sep 16, 2014 at 14:14

2 Answers 2

4

There is no simple way to achieve what you want. The list operations raise an error, period.

However you can work around by:

  • Accessing something else when the list is empty
  • Not using indexing

In the first case you can use the fact that empty lists are false and hence (expression) or [None] will evaluate to [None] when the expression returns an empty list, and hence:

((expression) or [None])[0]

The alternative is to avoid using indexing but using iteration and next to get the first element:

next(iter(expression), None)

Unfortunately you must explicitly call iter to get a list iterator.

To extend these methods to any index you can use slicing instead of simple indexing:

((expression)[index:] or [None])[0]

Or:

next(islice(expression, index, None), None)
# or
next(iter(expression[index:]), None)

(where islice is itertools.islice).

This works because slicing doesn't raise errors for out-of-bounds indexes.


Hoever my preferred alternative would be to use a function, if you use that often in your code:

def get_with_default(seq, index):
    try:
        return seq[index]
    except LookupError:
        return None
Sign up to request clarification or add additional context in comments.

Comments

1

Perhaps you could make use of the short-circuiting nature of the or operator.

seq = [23,42]
print (seq or [None])[0]
#result: 23

seq = []
print (seq or [None])[0]
#result: None

In the above code, seq or [None] evaluates to seq if seq contains any elements, and it evaluates to [None] if seq is empty. Then [0] accesses the first element of whichever list is returned.

2 Comments

I think the asker wants this to work for any index that would raise an IndexError, not just for empty lists. At least, that's how it works in Ruby.
arr.first or arr[0] was what I put. @Max you have more clearly expressed what I was trying to say.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.