Dmitry Belaventsev
Dmitry Belaventsev

Reputation: 6657

Dictionary get method behaviour

I have the following dictionary:

dic = {"a": "first", "b": "second"}

and it's ok, when I do the following:

print dic.get("a")
print dic.get("a", "asd")
print dic.get("a", dic.get("c"))

but when I use this method like this:

print dic.get("a", dic.get("c").split(" ",1)[0])

I receive the following error:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'split'

I dont't understand the last case. The second argument calculated (dic.get("c") should be None - it's ok), but there is a key "a" in dictionary and first argument shouldn't fire calculating of the second argument.

How I can fix this? And why it happened?

TIA!

Upvotes: 1

Views: 245

Answers (4)

kindall
kindall

Reputation: 184250

As others have explained, Python (like most other languages outside the functional family) evaluates all arguments of a function before calling it. Thus, dic.get("c") is None when key "c" doesn't exist in the dictionary and None has no .split() method, and this evaluation happens regardless of whether (and in fact before) the get succeeds or fails.

Instead, use a short-circuiting Boolean operator or a conditional expression.

# if dic.get["a"] is always truthy when it exists
dic.get("a") or dic.get("c", "").split(" ", 1)[0]

# if dic["a"] could be non-truthy, e.g. empty string
dic["a"] if "a" in dic else dic.get("c", "").split(" ", 1)[0]

Upvotes: 2

Geoff Reedy
Geoff Reedy

Reputation: 36041

Maybe you just have typo and meant

print dic.get("a", dic.get("c")).split(" ",1)[0]

That is you meant to split the result of the outer dic.get not the inner one.

Upvotes: 3

Brendan Long
Brendan Long

Reputation: 54262

dic.get("c")

Your dictionary doesn't contain "c", so it returns None.

dic.get("c").split(" ",1)[0]

Since we know that dic.get("c") is None:

None.split(" ",1)[0]

None has no split method, so that's why you get that error.

The arguments are all evaluated before they're passed to the method.

Upvotes: 2

Mark Byers
Mark Byers

Reputation: 838686

The second argument is always evaluated whether or not it is used.

To fix it you can catch the exception that is raised when an item is not found instead of using get.

try:
    result = dic['a']
except KeyError:
    result = dic['c'].split(' ', 1)[0]
print result

Upvotes: 3

Related Questions