Question: try this:

```
d = {"One":1,"Two":2,"Three":3}
d.get("Two", Print("Fail"))

```

Expected Output:

> 
> 
> > 
> > 2
> > 
> > 
> > 
> 
> 
> 

Actual Output:

> 
> 
> > 
> > Fail
> > 
> > 
> > 2
> > 
> > 
> > 
> 
> 
> 

Anyone know why the right hand argument of this expression is eagerly evaluated? What's the point of processing the right hand argument if there's a chance it's not returned? 

Is there a logic to this I'm missing?

Answer: 
It's always evaluated because any functions has to be resolved *before* the return value can be sent to `get`.

Instead, you supply a default *value* to use if the key is not present, or if you need to check multiple keys to get a value, the `get` call will return `None`:

```
val = d.get("Two")

if val is None:
    print("Fail..")

```

This is similar to:

```
if 'Two' not in d:
    print("Fail..")

```

If you don't want to provide a default value, the first example can still be useful if you have multiple possible values to check - chaining `.get` calls or having multiple `if .. is None: ..` checks all the way down.
Here's the logic.

```py
x = d.get("b", expensiveComputation())

```

This is computed like so:

* Compute `"b"`, its value is the first argument to `.get`.
* Call `expensiveComputation()`, its value is the second argument to `.get`.
* Call `.get` with these two arguments
* Assign the returned value to `x`.

If you want short-circuiting, Python is very ergonomic.

```py
x = d.get("a") or expensiveComputation()

```

This is computed like so:

* Compute `"a"`, its value is the first and only argument to `.get`.
* Call `.get` with the one argument.
* Since it's an `or` operator which requires Booleans, call `bool()` on the returned value.
* *If* the result is `True`, use the value returned by `.get`, *else* call `expensiveComputation()`, and use the value returned by it.
* Assign that to `x`.

Of course, not only `None` is falsy, so are empty lists, empty strings, etc; if such falsy objects may occur among your values, this is not what you want.

Python 3.8 [introduces assignment expressions](https://docs.python.org/3/whatsnew/3.8.html#assignment-expressions) so that you could still write one-liners like so:

```py
x if ((x := d.get("a")) is not None) else expensiveComputation()

```

Here `expensiveComputation()` will only run if `d` does not have a value for `"a"`. But this arguably balances on the verge of unreadable.