Python Quest

Track 2 · Lesson 10 of 11

None and dynamic typing

Use None for a value that is missing, see how variable names refer to objects, and check types with type() and isinstance().

About 30 minBeginner4 exercisesFree

You will be able to

  • Use None to mark a value that does not exist yet, and test for it with `is None`
  • Explain that a variable is a name that refers to an object, and predict what happens after `a = b`
  • Describe dynamic typing: the same name can refer to values of different types over time
  • Inspect a value's type with `type()` and `type(x).__name__`
  • Check whether a value is of a given type with `isinstance()`

A clinic's booking system records each patient's next appointment. A patient who has never booked has no appointment date at all. What should the program store for them? Not 0 — that looks like a real number. Not "" — that looks like text someone forgot to type. Python has a dedicated value for "there is nothing here": None.

In this lesson you'll meet None, then look more closely at what a variable really is. You'll see that a variable is a name attached to a value, that the same name can be attached to values of different types as a program runs, and how to ask Python what type a value has.

None means "no value"

None is a special value, written with a capital N and no quotes. It has its own type, NoneType, and there is only one None in the whole program. You use it when a value is missing, unknown or not decided yet.

To check whether a variable holds None, use the operator is: x is None gives True or False. Its opposite is x is not None. Python style guides recommend is None rather than == None because None is a single, unique object, and is asks "is this exactly that object?".

A customer without a discount code
discount_code = None

print(discount_code)
print(type(discount_code))
print(discount_code is None)
print(discount_code is not None)

Try it: Change None to "SPRING10" and run it again. Watch how the last two lines swap.

None is not zero and not an empty string. It is its own thing, so arithmetic with it fails. If a value might be None, you have to give it a real value before you calculate with it.

None cannot take part in arithmetic
bonus = None
salary = 8500

print(salary + bonus)

Try it: Replace None with 0 and run it again. Now the calculation works, but notice you have changed the meaning from 'unknown' to 'no bonus'.

You have already met None without noticing. Functions that do a job but have no result to give back, such as print(), return None. Try predicting this one.

Predict the output

result = print("Saving invoice")
print(result)

Variables are names that refer to objects

Every value in Python — a number, a string, None — is an object stored in memory. A variable is a name that refers to an object, like a label tied to it. The assignment price = 40 creates the object 40 and ties the name price to it.

When you write old_price = price, Python does not copy anything. It ties a second name to the same object. If you then write price = price + 5, Python builds a new object, 45, and moves the label price to it. The name old_price still refers to 40.

Reassigning one name does not change another
price = 40
old_price = price      # two names, one object
price = price + 5      # price now refers to a new object, 45

print("price:", price)
print("old_price:", old_price)

Try it: Add the line old_price = 0 at the end and print both again. Which one changes?

Predict the output

city = "Jeddah"
home = city
city = "Dammam"
print(city)
print(home)
print(home is city)

Dynamic typing

In some languages you must declare that a variable will always hold, say, a whole number. Python doesn't work that way. The value has a type; the name does not. A name can refer to a string now and a float a moment later. This is called dynamic typing.

type(x) tells you the type of the value x currently refers to. It prints as <class 'str'>; if you want only the short name, use type(x).__name__, which gives the string "str".

One name, three types
reading = input("Temperature: ")
print(reading, type(reading).__name__)

reading = float(reading)
print(reading, type(reading).__name__)

reading = round(reading)
print(reading, type(reading).__name__)
Input given to the program: "21.6"

Try it: Change the input to 18 and run it. Which lines look the same, and which show the type changing?

Dynamic typing is convenient, but it means you have to keep track of what a name refers to. The classic bug is forgetting that input() gives a string: "120" + "5" is "1205", not 125, and Python won't stop you, because adding two strings is perfectly legal.

Checking types with isinstance()

isinstance(value, type) answers "is this value of that type?" with True or False. You can also pass several types in parentheses to accept any of them: isinstance(x, (int, float)) is True for any whole or decimal number.

Asking about types
quantity = 12
unit_price = 7.5
label = "12"

print(isinstance(quantity, int))
print(isinstance(unit_price, int))
print(isinstance(unit_price, (int, float)))
print(isinstance(label, int))

Try it: Add print(isinstance(None, int)) and print(type(None).__name__). What do they show?

Guided practice · ●difficulty 1 of 5 · about 4 min

A customer with no card yet

A café registers new customers. A brand-new customer has no loyalty card yet, so the program should record that the card is missing using None.

Write a program that:

  1. Reads the customer's name with input() (no prompt text inside the parentheses — the tests type the values for you) and removes surrounding spaces. Store it in customer.
  2. Sets loyalty_card to None.
  3. Sets has_card to loyalty_card is not None.
  4. Prints three lines.

For the input Hana Saleh the output is:

Customer: Hana Saleh
Card: None
Has card: False

Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.

Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type

Output

Run your code to see its output, or Check to test it against the requirements.

The solution becomes available after you pass, or after all three hints and two checks.

Challenge · ●●difficulty 2 of 5 · about 6 min

Follow a value through its types

A courier bills parcels by the whole kilogram. Write a program that reads a parcel weight with input() (no prompt text — the tests type the values for you) and shows how the value changes type at each step. Create these variables, in order:

VariableValue
rawthe input with surrounding spaces removed (a string)
weightraw converted to a float
billed_kgweight rounded to a whole number with round() (an int)
labelthe text of billed_kg followed by kg, e.g. "3 kg"

Then print each variable, an arrow and the short name of its type (use type(x).__name__). For the input 2.6:

2.6 -> str
2.6 -> float
3 -> int
3 kg -> str

For the input 3 the second line is 3.0 -> float.

Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.

Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type

Output

Run your code to see its output, or Check to test it against the requirements.

The solution becomes available after you pass, or after all three hints and two checks.

Edge cases · ●●difficulty 2 of 5 · about 5 min

A whole-number price is still a float

A shop's price checker reads a price with input() (no prompt text — the tests type the values for you) and converts it with float(), so that prices like 7.25 work. It then reports what kind of value it holds. Create:

  • price — the input converted to a float
  • is_int — isinstance(price, int)
  • is_float — isinstance(price, float)
  • is_number — whether price is an int or a float, using one isinstance() call with both types

and print:

Price: 7.25
int: False
float: True
number: True

Watch the edge case: when someone types a whole number like 15, the price must still be a float (Price: 15.0), because the program converted it with float().

Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.

Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type

Output

Run your code to see its output, or Check to test it against the requirements.

The solution becomes available after you pass, or after all three hints and two checks.

Debugging · ●●difficulty 2 of 5 · about 5 min

Fix the growing stock count

A warehouse program reads the current stock of a product and the number of units in a new delivery, each on its own line, and prints the new stock. Staff report a strange result: with a stock of 120 and a delivery of 5, the screen shows

New stock: 1205

instead of New stock: 125. Find and fix the bug. After your fix, stock must hold a whole number (an int), and the program should still read the values with input() without prompt text.

Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.

Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type

Output

Run your code to see its output, or Check to test it against the requirements.

The solution becomes available after you pass, or after all three hints and two checks.

Summary

  • None is Python's value for 'nothing here'. Test for it with is None or is not None.
  • A variable is a name that refers to an object; b = a gives the same object a second name, and reassigning one name leaves the other alone.
  • Python is dynamically typed: values have types, names don't, so a name can refer to a str now and an int later.
  • type(x) shows a value's type (type(x).__name__ gives the short name); isinstance(x, int) or isinstance(x, (int, float)) checks it.