Explain Codes LogoExplain Codes Logo

Null object in Python

python
singleton
best-practices
sentinels
Alex KataevbyAlex Kataev·Sep 7, 2024
TLDR

In Python, None serves as the "null" equivalent, signifying the absence of a value. To check if an object equals None, use is:

if obj is None: print("Houston, we have a None!")

You can assign None to indicate no value:

obj = None

The None object is prevalent in Python to indicate a 'no value' state, and it's the default guest when a function forgets to send a return invite.

Comprehending 'None' and Identity comparison

Python's None isn't quite your garden-variety null; it's actually a singleton instance of the built-in NoneType class. A singleton is so exclusive, only one instance of it can exist in your Python universe, and that's where the is operator steals the show:

# This will always be True, 'None' is the ForeverAlone meme of Python assert (value is None) == (value is None)

This is preferred over using == for comparison, which checks for value equality but might get loose with definitions and mistakenly treat something as equivalent to None.

Special conditions and Sentinels

In certain scenarios, you might need a custom sentinel that operates similarly to None, especially when differentiating between "no value" and "value not provided." It's like ordering a pizza:

_NOT_PROVIDED = object() def order_pizza(topping=_NOT_PROVIDED): if topping is _NOT_PROVIDED: topping = "smack your lips for extra cheese!"

While creating custom sentinels, tread carefully; remember, with great power comes great responsibility to avoid confusion. Don't hesitate to check out the Python documentation on 'None' before inviting custom logic to your party.

None, NaN and Other's distant cousin

In Python, None is the Jekyll to float('nan')'s Hyde. Where None openly accepts "no value," float('nan') is more veiled, representing "not a number" in numerical computations. It's a family affair:

import pandas as pd # Who'll show up to the party - 'None' or 'NaN'? df = pd.DataFrame({'col': [None, float('nan'), 1, 2]}) print(df['col'].apply(pd.isnull)) # True for both 'None' and 'NaN'!

When dealing with floating point numbers, a nifty trick to check for NaN employs a detective with trust issues:

import math a = float('nan') print(a != a) # Trust no one, not even oneself.

Avoiding ambiguity and stepping in pitfalls

When faced with potentially unassigned variables, strategically planting flags in your code can prevent ambiguity. Rather than living on the edge with if my_string == "":, check its length:

if len(my_string) == 0: print("This string is as empty as my coffee cup on a Monday morning.")

This highlights the chalk and cheese difference between an unassigned variable (None) and an empty string. Be the Sherlock of your code by investigating potentially unassigned variables, and you'll sidestep bugs that hide in plain sight.

The Art of checking for 'None'

Choosing to write explicit None checks in the life of Python programming is not only a style guide—it's a statement of intent:

# With no explicit None check if value: # Is value a boolean or packed with boolean fury? # With an explicit None check if value is not None: # Behold, we're ensuring value exists or awaits assignment

When it comes to function arguments, use default values like salt on a steak—just enough but not too much. Consider using None judiciously to denote a default state awaiting computation.