David Amos Profile picture
Feb 8 β€’ 17 tweets β€’ 3 min read
A Tale of Two NaNs (A #Python 🧡)

(Plus a bonus experiment in Twitter fonts that may end disastrously)
NaNs are annoying.

You can’t tell if they’re in a list:

>>> πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€) πš’πš— [𝟷, 𝟸, πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€)]
π™΅πšŠπš•πšœπšŽ
You can end up with more than one NaN in a set:

>>> πš‚ = {𝟷, 𝟷, πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€), πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€)}
>>> πš‚
{𝟷, πš—πšŠπš—, πš—πšŠπš—}

But they also aren’t π˜ͺ𝘯 the set:

>>> πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€) πš’πš— πš‚
π™΅πšŠπš•πšœπšŽ
And if a NaN winds up as a dictionary key, well… it’s lost to the abyss πŸ•³

>>> 𝚍 = {πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€): 𝟷}
>>> 𝚍
{πš—πšŠπš—: 𝟷}

>>> # πšπšŠπš’πšœπšŽπšœ π™ΊπšŽπš’π™΄πš›πš›πš˜πš›
>>> 𝚍[πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€)]
(But you can keep adding NaN keys if you want to 🀫)

>>> 𝚍[πšπš•πš˜πšŠπš("πš—πšŠπš—")] = 𝟸
>>> 𝚍[πšπš•πš˜πšŠπš("πš—πšŠπš—")] = 𝟹
>>> 𝚍
{πš—πšŠπš—: 𝟷, πš—πšŠπš—: 𝟸, πš—πšŠπš—: 𝟹}
It’s all because of two key properties:

1️⃣ πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€) is not equal to itself:

>>> πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€) == πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€)
π™΅πšŠπš•πšœπšŽ

2️⃣ πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€) is not 𝐒𝐝𝐞𝐧𝐭𝐒𝐜𝐚π₯* to itself:

>>> πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€) πš’πšœ πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€)
π™΅πšŠπš•πšœπšŽ
*Two Python objects are 𝐒𝐝𝐞𝐧𝐭𝐒𝐜𝐚π₯ if they are located at the same memory address. Or, more precisely, the πš’πš() function returns the same value for both objects.
So what’s happening here?

Python checks two conditions when determining if an object is a member of a collection (i.e., list, set, dict keys):

1️⃣ Is the object identical to one of the objects in the collection?

2️⃣ Is the object equal (using ==) to an object in the collection?
If either one of those conditions is true, then the object is a member of the collection.

(See docs.python.org/3/reference/ex… if you want to nerd out over membership πŸ€“)

But neither of those conditions are ever true for πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€)!
That said, since πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€) is a floating point value β€” and thus immutable β€” there’s no problem using πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€) in a set or as a dictionary key.

I know, it can be kind of confusing.
Let’s add another NaN to the mix.

πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€) isn’t the only way to make a NaN object in Python.

No, I’m not talking about πš—πšžπš–πš™πš’.πš—πšŠπš—.

There’s also πš–πšŠπšπš‘.πš—πšŠπš—:

>>> πš’πš–πš™πš˜πš›πš πš–πšŠπšπš‘
>>> πš–πšŠπšπš‘.πš—πšŠπš—
πš—πšŠπš—
πš–πšŠπšπš‘.πš—πšŠπš— was added to Python in version 3.5, and here’s what the docs say about it:

β€œA floating-point β€˜not a number’ (NaN) value. Equivalent to the output of πšπš•πš˜πšŠπš(β€˜πš—πšŠπš—β€™).”

docs.python.org/3/library/math…
So, what do you think are the results of the following expressions?

1️⃣ πš–πšŠπšπš‘.πš—πšŠπš— == πš–πšŠπšπš‘.πš—πšŠπš—

2️⃣ πš–πšŠπšπš‘.πš—πšŠπš— πš’πšœ πš–πšŠπšπš‘.πš—πšŠπš—
If you answered π™΅πšŠπš•πšœπšŽ for 1️⃣, then congrats! You’re right! βœ…

But if you also answered π™΅πšŠπš•πšœπšŽ for 2️⃣, then you are incorrect ❌
Check out what happens when you use πš–πšŠπšπš‘.πš—πšŠπš— as a dictionary key:

>>> 𝚍 = {πš–πšŠπšπš‘.πš—πšŠπš—: 𝟷}
>>> 𝚍[πš–πšŠπšπš‘.πš—πšŠπš—]
𝟷

Sets also treat πš–πšŠπšπš‘.πš—πšŠπš— differently than πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€):

>>> {πš–πšŠπšπš‘.πš—πšŠπš—, πš–πšŠπšπš‘.πš—πšŠπš—, πš–πšŠπšπš‘.πš—πšŠπš—}
{πš—πšŠπš—}
Who knows what’s going on here? What’s the difference between πš–πšŠπšπš‘.πš—πšŠπš— and πšπš•πš˜πšŠπš(β€œπš—πšŠπš—β€)?

100 internet points to the first person with the right answer!
And if you want even more NaN craziness, check out the discussion thread from the Python issue tracker that led to the inclusion of πš–πšŠπšπš‘.πš—πšŠπš—.

For instance, did you know that there are 𝘴π˜ͺ𝘨𝘯𝘦π˜₯ NaNs? 🀯

bugs.python.org/issue23185

β€’ β€’ β€’

Missing some Tweet in this thread? You can try to force a refresh
γ€€

Keep Current with David Amos

David Amos Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

More from @somacdivad

Feb 9
Today's #JuliaLang doodle with Javis.jl is recreating a classic...
Look closely at the circles. Are the curving at all?

Here's the code:

(I'm sure there's a better way to do this, I just haven't completely figured out Javis yet!) Image
I think disks work better than circles for this:
Read 8 tweets
Feb 8
I've learning to make animations with Javis.jl and came up with this little doodle tonight. Nothing fancy, just getting my feet wet!
And here's the code: Image
Colors make it better
Read 5 tweets

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Don't want to be a Premium member but still want to support us?

Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal

Or Donate anonymously using crypto!

Ethereum

0xfe58350B80634f60Fa6Dc149a72b4DFbc17D341E copy

Bitcoin

3ATGMxNzCUFzxpMCHL5sWSt4DVtS8UqXpi copy

Thank you for your support!

:(