There are a number of basic variable types in Python.
True
, False
Use #
to demarcate a comment, and use =
to assign a value to a variable, e.g,:
v = True # Boolean with value True
w = False # Boolean with value False
x = 5 # int
y = 5.0 # float
You can use print()
to display the value of a variable, or you can just type the variable and hit return:
print(v)
v
print(w)
print(x)
print(y)
Some variables are sequences of smaller units.
A simple way to create a string is with (single or double) quotation marks:
s = 'this is a string'
print(s)
A simple way to create a list is to put elements inside square brackets (separating elements with commas). The elements of a list can be any type of variable, and elements can be different types within a list.
l = [v,w,x,s]
print(l)
A simple way to create a tuple is to put elements inside parentheses (separating by commas). Elements can be any type of variable, and need not be the same type as each other.
t = (v,w,x,s)
print(t)
Strings, lists, and tuples support indexing and slicing, which means that you can pick out bits and pieces of these variables. Indexing means indicating a single element of a string/list/tuple, and slicing means indicating multiple elements.
Python uses zero-based indexing (i.e., it starts counting indices at 0). It is useful to think of indices pointing to the space between and to the left of elements. When slicing, the element indicated by the starting index is included in the slice, whereas the element indicated by the ending index is not included. The starting and ending indices are separated by a colon.
So, for example, if we wanted to pick out the first t
from our string s
and assign it to a new variable r
, we would do this:
r = s[0] # indexing the first element of s, assigning it to r
print(s)
print(r)
If we want to pick out the sequence is a
from s
and assign it to r
, we would do this:
r = s[5:9] # slicing elements 5 through 8 of s, assigning to r
print(r)
Here is an illustration of the inclusion and exclusion of the left and right endpoints of a slice, respectively:
print(s)
print(s[3:12]) # slice from 3 up to, but not including, 12
print(s[3]) # index 3
print(s[12]) # index 12
Lists and tuples support indexing and slicing, too:
print(l) # list l assigned above
print(l[1]) # the second element of l
print(l[1:3]) # the second and third elements of l
If your beginning index is 0
, or if your ending index is -1
(i.e., the last element), you can leave it out:
print(l[:3]) # slice from 0 to 3
print(l[2:]) # slice from 2 to the end
print(l[:]) # the whole list
One important difference between lists and tuples is that lists are mutable, whereas tuples are not. This means that you can change lists (e.g., delete an element, make the list longer). You can't do this with tuples.
print(l)
l[2] = 7 # replace the third element with the integer 7
print(l)
print(t)
t[2] = 7 # try the same thing with the tuple t, get an error
As mentioned above, the elements of lists and tuples can be any data type (including lists and tuples, as well as data types we haven't learned about yet).
k = [l, t, x] # a list, a tuple, and a number
print(k)
If you've programmed in other languages, one important fact about Python might confuse you and end up causing problems. Here's an illustration:
l[2] = 50 # change the third element of l to the number 50
print(k) # print the list k, the first element of which is the list l
Note that I changed an element of the list l
, and this showed up in the list k
, which contains l
as its first element. That is, the list that is the first element of k
and the list l
are both referring to the same underlying value. This doesn't happen with numeric types:
x = 10 # change the value of x
print(x)
print(k) # print the list k, which contains (the old) x
One more very useful basic data type in Python is the dictionary. Like lists and tuples, dictionaries can contain multiple items of any type. However, unlike lists and tuples, dictionaries have keys and values, so instead of indexing or slicing, you retrieve elements by name:
d = {'fred':5, 'bill':l, 'kurt':w}
print(d)
print(d['kurt'])
Finally, Python also has basic set
data type, which are unordered collections of unique elements. Because they are unordered, indexing and slicing don't work, but you can add or remove elements from a set using the add()
and discard()
or remove()
methods (we'll talk about methods below). The elements of sets cannot be mutable.
u = set((1,2,2,3,'a','a','b','c','c','c'))
print(u)
u.add(5) # add 5 as an element
print(u)
u.discard('c') # get rid of 'c' as an element
print(u)
There are a number of basic operations that can be performed on different data types.
Basic math operators
addition: +
subtraction: -
multplication: *
division: /
division with flooring (rounding down): //
modulus: %
exponentiation: **
matrix multiplication: @
(we'll come back to this later)
5 + 3
5 - 3
5 * 3
5 / 3
5 // 3
5 % 3
5**3
The +
and *
operators also work with strings, lists, and tuples:
s + ' ' + s[5:]
s*5
e = {'a':500000000}
h = ['hello',13,e]
k = h + l
print(h)
print(l)
print(k)
print(h*3)
print(t*3)
print(t+t)
There are a number of logical operators that are very useful. You can use ==
to test for equality, or !=
to test for unequal values.
x = 5
y = 6
x == y # test for equality of x and y, returns a Boolean
x == y-1
x != y # tests for inequality of x and y, returns a Boolean
You can use <
, <=
, >
, and >=
to test for particular types of (strict or not) inequality.
x < y
x > y
x >= y-1
The keywords and
and or
are reserved for indicating intersections and unions, respectively.
print(w)
print(v)
t = True
u = False
print(t and v)
print(t and u)
print(w or v)
print(w or u)
Non-Boolean variables can act as Booleans. Specifically, 0
and ''
(i.e., an empty string) both evaluate to False
. Any other number and any non-empty string all evaluate to True
. Note, too, that Python checks the elements in order from left to right, returning a value as soon as it can determine the value of the whole expression. We can illustrate these facts here, but they won't be particularly important until later, when we talk about control flow.
0 and 5 # 0 is False, so 0 and 5 is False as soon as Python sees 0
5 and 0 # 5 is True, but 0 is False, so Python doesn't know 5 and 0 is False until it gets to 0
6 or 0 # 6 is True, so 6 or 0 is True
0 or 6 # 0 is False, but 0 or 6 is True because 6 is True
5 and 6 # 5 is True, but Python has to check both elements to be sure 5 and 6 is True
5 or 6 # 5 is True, so 5 or 6 is True
Python is an object-oriented programming language. Part of what this means is that a many variables have methods, which are (pretty much) functions that "belong" to particular classes of variables (e.g., strings, tuples, dictionaries, etc).
You invoke a method by typing a .
after a variable name and then typing the name of the method. In a Jupyter notebook, or in IPython, you can see what methods a variable has by typing .
and hitting tab.
# list methods illustrated here with l.<tab>
If you want a copy of a list, you can use the copy()
method. A copy will not automatically inherit changes to the original list.
l = [10,'hello',e] # make a new list called l
m = l.copy() # copy it, assign to m
n = l # assign l to n
m # look at the copy
The append()
method appends an input argument to a list:
l[2] = 30 # redefine third element of l
l.append(5**4) # append 5**4 to l
print(l)
print(m) # the copy
print(n) # not a copy
If you want to count the number of times an element occurs in a list, you can use the count()
method:
l.append(False)
l.append(True)
print(l)
l.count(False)
The index()
method returns the index of the input argument:
l.index(30)
Dictionaries also have methods. keys()
returns the keys of the dictionary, and values()
returns the values:
d.keys()
d.values()
We will use methods quite a bit as we go on. For now, I just want you to know that they exist.
In a notebook or IPython terminal, you can type %who
to see all of your variables:
%who
You can add variable types to see only that type of variable:
%who int
%who str
%who dict
You can type %whos
to get more information about the variables:
%whos
You can type %ls
to see what's in the directory you're working in on your computer:
%ls
You can type %pwd
to see what directory you're working in:
%pwd
Here are all of the IPython "magics", for future reference.
We've already seen a few functions, e.g., print()
, some list and dictionary methods. A function is essentially just a block of reusable code that performs an action. Functions may or may not take inputs, and they may or may not return outputs.
It's easy to define your own functions. Here's a very simple function that takes two numbers, adds them together, and returns the sum:
def add_two_nums(n,m):
'''Returns the sum of inputs n and m'''
print(n)
print(m)
o = n + m
return o
The keyword def
tells Python that what follows is a function definition. The next bit is the name of the function (i.e., the code that you will use to call that function). Any input arguments appear in the parentheses immediately after the function name, separated by commas if there are more than one. The def
line ends with a colon, and the code inside the function must be indented - indentation is how Python knows what is inside the function and what is not. The string immediately below the name is the docstring
, or the description of what the function does. Finally, the return
statement tells Python what to give back as output.
IPython allows you to get docstrings very easily:
?add_two_nums
z = add_two_nums(x,y)
print(z)
As defined above, our function add_two_nums()
requires input values. We can give a function default values if we want. If a function has any arguments with default values, they have to come after any that do not. Here's an example of a function with one required input and two inputs with default values.
def add_three_nums(a,b=5,c=7):
'''Returns the sum of inputs a, b, and c'''
print(a)
print(b)
print(c)
return a + b + c
add_three_nums(3)
add_three_nums(3,4,2)
Inputs without default values are specified by position (i.e., first, second, third, ... input argument). We can also specify all of the inputs by name, which can be helpful when reading code. In addition, we can use the reserved term None
if we want a placeholder rather than a default value. Let's define a new function to illustrate:
def fancy_math(a=None,b=None,c=None):
'''returns (a+b)*c'''
return (a+b)*c
Using None
like this, we have to give the function inputs if we want to avoid an error:
fancy_math()
We can still give inputs by position if we want:
fancy_math(2,3,4)
Or we can give inputs by name in any order:
fancy_math(c=10,a=2,b=50)