You are here: Home ‣ Dive Into Python 3 ‣
Difficulty level: ♦♦♢♢♢
❝ Wonder is the foundation of all philosophy, inquiry its progress, ignorance its end. ❞
— Michel de Montaigne
Cast aside your first Python program for just a minute, and let’s talk about datatypes. In Python, every variable has a datatype, but you don’t need to declare it explicitly. Based on each variable’s original assignment, Python figures out what type it is and keeps tracks of that internally.
Python has many native datatypes. Here are the important ones:
True or False.
1 and 2), floats (1.1 and 1.2), fractions (1/2 and 2/3), or even complex numbers (i, the square root of -1).
Of course, there are a lot more types than these seven. Everything is an object in Python, so there are types like module, function, class, method, file, and even compiled code. You’ve already seen some of these: modules have names, functions have docstrings, &c. You’ll learn about classes in [FIXME xref] and files in [FIXME xref].
Strings and bytes are important enough — and complicated enough — that they get their own chapter. Let’s look at the others first.
⁂
Booleans are either true or false. Python has two constants, True and False, which can be used to assign boolean values directly. Expressions can also evaluate to a boolean value. In certain places (like if statements), Python expects an expression to evaluate to a boolean value. These places are called boolean contexts. You can use virtually any expression in a boolean context, and Python will try to determine its truth value. Different datatypes have different rules about which values are true or false in a boolean context. (This will make more sense once you see some concrete examples later in this chapter.)
For example, take this snippet from humansize.py:
if size < 0:
raise ValueError('number must be non-negative')
size is an integer, 0 is an integer, and < is a numerical operator. The result of the expression size < 0 is always a boolean. You can test this yourself in the Python interactive shell:
>>> size = 1 >>> size < 0 False >>> size = 0 >>> size < 0 False >>> size = -1 >>> size < 0 True
⁂
Numbers are awesome. There are so many to choose from. Python supports both integers and floating point numbers. There’s no type declaration to distinguish them; Python tells them apart by the presence or absence of a decimal point.
>>> type(1) ① <class 'int'> >>> 1 + 1 ② 2 >>> 1 + 1.0 ③ 2.0 >>> type(2.0) <class 'float'>
type() function to check the type of any value or variable. As you might expect, 1 is an int.
int to an int yields an int.
int to a float yields a float. Python coerces the int into a float to perform the addition, then returns a float as the result.
As you just saw, some operators (like addition) will coerce integers to floating point numbers as needed. You can also coerce them by yourself.
>>> float(2) ① 2.0 >>> int(2.0) ② 2 >>> int(2.5) ③ 2 >>> int(-2.5) ④ -2 >>> 1.12345678901234567890 ⑤ 1.1234567890123457 >>> type(1000000000000000) ⑥ <class 'int'>
int to a float by calling the float() function.
float to an int by calling int().
int() function will truncate, not round.
int() function truncates negative numbers towards 0. It’s a true truncate function, not a a floor function.
☞Python 2 had separate types for
intandlong. Theintdatatype was limited bysys.maxint, which varied by platform but was usually232-1. Python 3 has just one integer type, which behaves mostly like the oldlongtype from Python 2. See PEP 237 for details.
You can do all kinds of things with numbers.
>>> 11 / 2 ① 5.5 >>> 11 // 2 ② 5 >>> −11 // 2 ③ −6 >>> 11.0 // 2 ④ 5.0 >>> 11 ** 2 ⑤ 121 >>> 11 % 2 ⑥ 1
/ operator performs floating point division. It returns a float even if both the numerator and denominator are ints.
// operator performs a quirky kind of integer division. When the result is positive, you can think of it as truncating (not rounding) to 0 decimal places, but be careful with that.
// operator rounds “up” to the nearest integer. Mathematically speaking, it’s rounding “down” since −6 is less than −5, but it could trip you up if you expecting it to truncate to −5.
// operator doesn’t always return an integer. If either the numerator or denominator is a float, it will still round to the nearest integer, but the actual return value will be a float.
** operator means “raised to the power of.” 112 is 121.
% operator gives the remainder after performing integer division. 11 divided by 2 is 5 with a remainder of 1, so the result here is 1.
☞In Python 2, the
/operator usually meant integer division, but you could make it behave like floating point division by including a special directive in your code. In Python 3, the/operator always means floating point division. See PEP 238 for details.
Python isn’t limited to integers and floating point numbers. It can also do all the fancy math you learned in high school and promptly forgot about.
>>> import fractions ① >>> x = fractions.Fraction(1, 3) ② >>> x Fraction(1, 3) >>> x * 2 ③ Fraction(2, 3) >>> fractions.Fraction(6, 4) ④ Fraction(3, 2)
fractions module.
Fraction object and pass in the numerator and denominator.
Fraction object. 2 * (1/3) = (2/3)
Fraction object will automatically reduce fractions. (6/4) = (3/2)
You can also do basic trigonometry in Python.
>>> import math >>> math.pi ① 3.1415926535897931 >>> math.sin(math.pi / 2) ② 1.0 >>> math.tan(math.pi / 4) ③ 0.99999999999999989
math module has a constant for π, the ratio of a circle’s circumference to its diameter.
math module has all the basic trigonometric functions, including sin(), cos(), tan(), and variants like asin().
tan(π / 4) should return 1.0, not 0.99999999999999989.
You can use numbers in a boolean context, such as an if statement. Zero values are false, and non-zero values are true.
>>> def is_it_true(anything): ① ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true(1) ② yes, it's true >>> is_it_true(-1) yes, it's true >>> is_it_true(0) no, it's false >>> is_it_true(0.1) ③ yes, it's true >>> is_it_true(0.0) no, it's false >>> import fractions >>> is_it_true(fractions.Fraction(1, 2)) ④ yes, it's true >>> is_it_true(fractions.Fraction(0, 1)) no, it's false
0 is false.
0.0 is false. Be careful with this one! If there’s the slightest rounding error (not impossible, as you saw in the previous section) then Python will be testing 0.0000000000001 instead of 0 and will return True.
Fraction(0, n) is false for all values of n. All other fractions are true.
⁂
Lists are Python’s workhorse datatype. When I say “list,” you might be thinking “array whose size I have to declare in advance, that can only contain items of the same type, &c.” Don’t think that. Lists are much cooler than that.
☞A list in Python is like an array in Perl 5. In Perl 5, variables that store arrays always start with the
@character; in Python, variables can be named anything, and Python keeps track of the datatype internally.
☞A list in Python is much more than an array in Java (although it can be used as one if that’s really all you want out of life). A better analogy would be to the
ArrayListclass, which can hold arbitrary objects and can expand dynamically as new items are added.
Creating a list is easy: use square brackets to wrap a comma-separated list of values.
>>> a_list = ['a', 'b', 'mpilgrim', 'z', 'example'] ① >>> a_list ['a', 'b', 'mpilgrim', 'z', 'example'] >>> a_list[0] ② 'a' >>> a_list[4] ③ 'example' >>> a_list[-1] ④ 'example' >>> a_list[-3] ⑤ 'mpilgrim'
a_list[0].
a_list[4], because lists are always zero-based.
a_list[-1].
a_list[-n] == a_list[len(a_list) - n]. So in this list, a_list[-3] == a_list[5 - 3] == a_list[2].
Once you’ve defined a list, you can get any part of it as a new list. This is called slicing the list.
>>> a_list ['a', 'b', 'mpilgrim', 'z', 'example'] >>> a_list[1:3] ① ['b', 'mpilgrim'] >>> a_list[1:-1] ② ['b', 'mpilgrim', 'z'] >>> a_list[0:3] ③ ['a', 'b', 'mpilgrim'] >>> a_list[:3] ④ ['a', 'b', 'mpilgrim'] >>> a_list[3:] ⑤ ['z', 'example'] >>> a_list[:] ⑥ ['a', 'b', 'mpilgrim', 'z', 'example']
a_list[1]), up to but not including the second slice index (in this case a_list[3]).
a_list[0:3] returns the first three items of the list, starting at a_list[0], up to but not including a_list[3].
0, you can leave it out, and 0 is implied. So a_list[:3] is the same as a_list[0:3], because the starting 0 is implied.
a_list[3:] is the same as a_list[3:5], because this list has five items. There is a pleasing symmetry here. In this five-item list, a_list[:3] returns the first 3 items, and a_list[3:] returns the last two items. In fact, a_list[:n] will always return the first n items, and a_list[n:] will return the rest, regardless of the length of the list.
a_list[:] is shorthand for making a complete copy of a list.
There are four ways to add items to a list.
>>> a_list = ['a'] >>> a_list = a_list + [2.0, 3] ① >>> a_list ['a', 2.0, 3] >>> a_list.append(True) ② >>> a_list ['a', 2.0, 3, True] >>> a_list.extend(['four', 'e']) ③ >>> a_list ['a', 2.0, 3, True, 'four', 'e'] >>> a_list.insert(1, 'a') ④ >>> a_list ['a', 'a', 2.0, 3, True, 'four', 'e']
+ operator concatenates lists. A list can contain any number of items; there is no size limit (other than available memory). A list can contain items of any datatype; they don’t all need to be the same type. Here we have a list containing a string, a floating point number, and an integer.
append() method adds a single item to the end of the list. (Now we have four different datatypes in the list!)
extend() method takes one argument, a list, and appends each of the items of the argument to the original list.
insert() method inserts a single item into a list. The first argument is the index of the first item in the list that will get bumped out of position. List items do not need to be unique; for example, there are now two separate items with the value 'a', a_list[0] and a_list[1].
Let’s look closer at the difference between append() and extend().
>>> a_list = ['a', 'b', 'c'] >>> a_list.extend(['d', 'e', 'f']) ① >>> a_list ['a', 'b', 'c', 'd', 'e', 'f'] >>> len(a_list) ② 6 >>> a_list[-1] 'f' >>> a_list.append(['g', 'h', 'i']) ③ >>> a_list ['a', 'b', 'c', 'd', 'e', 'f', ['g', 'h', 'i']] >>> len(a_list) ④ 7 >>> a_list[-1] ['g', 'h', 'i']
extend() method takes a single argument, which is always a list, and adds each of the items of that list to a_list.
append() method takes a single argument, which can be any datatype. Here, you’re calling the append() method with a list of three items.
>>> a_list = ['a', 'b', 'new', 'mpilgrim', 'new'] >>> 'mpilgrim' in a_list ① True >>> a_list.index('mpilgrim') ② 3 >>> a_list.index('new') ③ 2 >>> 'c' in a_list ④ False >>> a_list.index('c') ⑤ Traceback (innermost last): File "<interactive input>", line 1, in ? ValueError: list.index(x): x not in list
in operator. It returns True if the value is in the list, or False if it is not. It will not tell you where in the list the value is.
index() method. By default it will search the entire list, although you can specify a second argument of the (0-based) index to start from, and even a third argument of the (0-based) index to stop searching.
False, because 'c' is not a value in a_list.
index() method finds the first occurrence of a value in the list. In this case, 'new' occurs twice in the list, in a_list[2] and a_list[4], but the index() method will return only the index of the first occurrence.
-1). While this may seem annoying at first, I think you will come to appreciate it. It means your program will crash at the source of the problem instead of failing strangely and silently later.
You can also use a list in a boolean context, such as an if statement.
>>> def is_it_true(anything):
... if anything:
... print("yes, it's true")
... else:
... print("no, it's false")
...
>>> is_it_true([]) ②
no, it's false
>>> is_it_true(['a']) ③
yes, it's true
>>> is_it_true([False]) ④
yes, it's true
⁂
One of Python’s most important datatypes is the dictionary, which defines one-to-one relationships between keys and values.
☞A dictionary in Python is like a hash in Perl 5. In Perl 5, variables that store hashes always start with a
%character. In Python, variables can be named anything, and Python keeps track of the datatype internally.
Creating a dictionary is easy. The syntax is similar to sets, but instead of values, you have key-value pairs. Once you have a dictionary, you can look up values by their key.
>>> a_dict = {"server":"db.diveintopython3.org", "database":"mysql"} ①
>>> a_dict
{'server': 'db.diveintopython3.org', 'database': 'mysql'}
>>> a_dict["server"] ②
'db.diveintopython3.org'
>>> a_dict["database"] ③
'mysql'
>>> a_dict["db.diveintopython3.org"] ④
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'db.diveintopython3.org'
'server' is a key, and its associated value, referenced by a_dict["server"], is 'db.diveintopython3.org'.
'database' is a key, and its associated value, referenced by a_dict["database"], is 'mysql'.
a_dict["server"] is 'db.diveintopython3.org', but a_dict["db.diveintopython3.org"] raises an exception, because 'db.diveintopython3.org' is not a key.
Dictionaries do not have any predefined size limit. You can add new key-value pairs to a dictionary at any time, or you can modify the value of an existing key. Continuing from the previous example:
>>> a_dict
{'server': 'db.diveintopython3.org', 'database': 'mysql'}
>>> a_dict["database"] = "blog" ①
>>> a_dict
{'server': 'db.diveintopython3.org', 'database': 'blog'}
>>> a_dict["user"] = "mark" ②
>>> a_dict ③
{'server': 'db.diveintopython3.org', 'user': 'mark', 'database': 'blog'}
>>> a_dict["user"] = "dora" ④
>>> a_dict
{'server': 'db.diveintopython3.org', 'user': 'dora', 'database': 'blog'}
>>> a_dict["User"] = "mark" ⑤
>>> a_dict
{'User': 'mark', 'server': 'db.diveintopython3.org', 'user': 'dora', 'database': 'blog'}
'user', value 'mark') appears to be in the middle. In fact, it was just a coincidence that the items appeared to be in order in the first example; it is just as much a coincidence that they appear to be out of order now.
user key back to "mark"? No! Look at the key closely — that’s a capital U in "User". Dictionary keys are case-sensitive, so this statement is creating a new key-value pair, not overwriting an existing one. It may look similar to you, but as far as Python is concerned, it’s completely different.
Dictionaries aren’t just for strings. Dictionary values can be any datatype, including integers, booleans, arbitrary objects, or even other dictionaries. And within a single dictionary, the values don’t all need to be the same type; you can mix and match as needed. Dictionary keys are more restricted, but they can be strings, integers, and a few other types. You can also mix and match key datatypes within a dictionary.
In fact, you’ve already seen a dictionary with non-string keys and values, in your first Python program.
SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}
Let's tear that apart in the interactive shell.
>>> SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
... 1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}
>>> len(SUFFIXES) ①
2
>>> SUFFIXES[1000] ②
['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
>>> SUFFIXES[1024] ③
['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']
>>> SUFFIXES[1000][3] ④
'TB'
len() function gives you the number of items in a dictionary.
1000 is a key in the SUFFIXES dictionary; its value is a list of eight items (eight strings, to be precise).
1024 is a key in the SUFFIXES dictionary; its value is also a list of eight items.
SUFFIXES[1000] is a list, you can address individual items in the list by their 0-based index.
You can also use a dictionary in a boolean context, such as an if statement.
>>> def is_it_true(anything):
... if anything:
... print("yes, it's true")
... else:
... print("no, it's false")
...
>>> is_it_true({}) ①
no, it's false
>>> is_it_true({'a': 1}) ②
yes, it's true
⁂
NoneNone is a special constant in Python. It is a null value. None is not the same as False. None is not 0. None is not an empty string. Comparing None to anything other than None will always return False.
None is the only null value. It has its own datatype (NoneType). You can assign None to any variable, but you can not create other NoneType objects. All variables whose value is None are equal to each other.
>>> type(None) <class 'NoneType'> >>> None == False False >>> None == 0 False >>> None == '' False >>> None == None True >>> x = None >>> x == None True >>> y = None >>> x == y True
None In A Boolean ContextIn a boolean context, None is false and not None is true.
>>> def is_it_true(anything):
... if anything:
... print("yes, it's true")
... else:
... print("no, it's false")
...
>>> is_it_true(None)
no, it's false
>>> is_it_true(not None)
yes, it's true
⁂
fractions module
math module
© 2001–9 Mark Pilgrim