= 7
x id(x)
140030289904048
Introduction to Software Engineering (CSSE 1001)
The primitive data types in Python comprise
bool
,integer
,float
(which we skip),string
, andtuple
.They are the “built-in” types that Python has and come with a bunch of extra functionality.
Once a piece of primitive data is loaded into memory it cannot be changed. If we store an integer in the name x
= 7
x id(x)
140030289904048
then increment x
by three
= x + 3 x
we will see x
now refers to a new location in memory rather than the memory location itself being overwritten
id(x)
140030289904144
This detail is not overly important but do take care not to try and modify strings, as we will soon see it is sometimes tempting to do so.
The boolean type provides (comprehensively) the values True
and False
.
type(True)
bool
type(False)
bool
Now that we have this type we can introduce operations like greater than that return a true/false answer.
3 > 7
False
We will cover all the comparison operators on numbers that we omitted last week in this lecture.
Generally speaking statements like
> "Is it raining?"
or
> "Is it Wednesday?"
evaluate to a boolean and are called predicates.
Sometimes we want to tie two predicates together like
> "Is it raining AND Wednesday?"
This is accomplished with the operators and
, or
, not
.
2 < 3 and 3 < 2
False
and |
True |
False |
---|---|---|
True |
True |
False |
False |
False |
False |
and
. Read like a multiplication table swapping numbers for booleans and multiplication for and
.
False and False
False
False and True
False
True and False
False
True and True
True
or |
True |
False |
---|---|---|
True |
True |
True |
False |
True |
False |
or
. Read like a multiplication table swapping numbers for booleans and multiplication for or
.
False or False
False
False or True
True
True or False
True
True or True
True
not(True)
False
not(False)
True
True > False
True
True <= False
False
True != False
True
True == True
True
False == False
True
Integers in Python can be as big as we want. This requires some work behind the scenes because a computer hardware is designed to do arithmetic on integers that fit in words. In other programming languages it would be the responsibility of the programmer to not exceed the largest number.
We simply include the of arithmetic here for completion sake.
Operator | Name | Syntax |
---|---|---|
() |
Brackets | (x) |
+ |
Unary plus | +x |
- |
Unary minus | -x |
+ |
Plus | x + y |
- |
Minus | x - y |
* |
Multiplication | x * y |
\\ |
Integer Division | x // y |
% |
Modulus | x % y |
** |
Exponentiation | x ** y |
x
and y
integers (but more generally are any legal Python expressions that evaluate to integers). To be more accurate we should add “and store in memory” to each item in the semantics column.
We can now introduce the operations on numbers that evaluate to booleans.
Operator | Name | Syntax |
---|---|---|
== |
Equal | x == y |
> |
Greater than | x > y |
>= |
Greater than or equal | x >= y |
< |
Less than | x < y |
<= |
Less than or equal | x <= y |
x
and y
integers (but more generally are any legal Python expressions that evaluate to integers).
67 == 67
True
= 67, 67
x, y == y x
True
3 < 7
True
The evaluation result from this expression can be assigned to a variable.
= 3 < 7
x x
True
There is a shortcut for 0 < x and x < 100
0 < x < 100
True
Anything (with some exceptions) enclosed by single-quotes ' '
or double-quotes " "
is considered to be a string by Python.
A string is an ordered collection of characters (e.g. unicode and ascii) allowed by the computer.
"hello world"
'hello world'
'hello world'
'hello world'
type("hello world")
str
# note the lack of quotes hello world
SyntaxError: invalid syntax
# note the lack of quotes hello
NameError: name 'hello' is not defined
"hello" + "world"
'helloworld'
= " "
space "hello" + space + "world"
'hello world'
When strings are added a new string is created. This is because strings are immutable — once they are in memory they cannot change.
Because we can repeatedly add a string to itself, it makes sense to multiply strings by positive integers.
3 * "Hello World!"
'Hello World!Hello World!Hello World!'
It may be odd to have this mixed-type computation, but consider repeated adding is already okay, and multiplication by a positive integer is essentially notation for this operation.
"Hello World!" + "Hello World!" + "Hello World!"
'Hello World!Hello World!Hello World!'
Exercise 1 What is zero times a string?
0 * "hello"
The single character a
is ordered less than b
as you would expect.
"a" < "b"
True
This is because all characters are listed in a table according to ascii or unicode. These tables allow computers to standardize the way they display text by agreeing that character, say 97, should be lower-case a.
ord("a") # the "order" of the character a
97
ord("b") # the "order" of the character b
98
chr(97) # get character from order
'a'
"A" < "a"
True
"Z" < "a"
True
The best way to understand how these comparisons on longer strings are resolved is to simply implement a function that does so. However, we require string indexing for that and will therefore wait until then to do it.
"a" < "aa"
True
"b" < "aa"
False
"aba" < "ab"
False
"aZ" < "aa"
True
Exercise 2 Write a function according to the following specification.
def string_less_than(cs: str, ds: str) -> bool:
"""
Return true when string <cs> is strictly less than string <ds>.
"""
Do not use <
to solve this question.
A new line is an escape character that can be used in strings to print whatever is subsequent to it on a new line. The new line escape character is \n
.
"hello\nworld"
'hello\nworld'
'hello\nworld'
'hello\nworld'
print("hello\nworld")
hello
world
Notice how a string can be stored differently than it is printed.
A tab is a fixed amount of horizontal space. How a tab is displayed depends on the program displaying it. (This is why tabs are the worst :)
"hello\tworld"
'hello\tworld'
'hello\tworld'
'hello\tworld'
print("hello\tworld")
hello world
3 + 7
10
"3" + "7"
'37'
3 + "7"
TypeError: unsupported operand type(s) for +: 'int' and 'str'
str(3) + "7"
'37'
3 + int("7")
10
int("3.14")
ValueError: invalid literal for int() with base 10: '3.14'
float("123.456")
123.456
Note that this is only true for numbers expressed with digits!
int("seven")
ValueError: invalid literal for int() with base 10: 'seven'
There is a mechanism for printing string variables in sentences through substitution using the string formatter.
= 1
x = "two"
y f"x={x} y={y}"
'x=1 y=two'
Formatted strings are more typically used with print statements.
= 1
x = "two"
y print(f"x={x} y={y}")
x=1 y=two
A string’s length is the number of characters that comprise it.
len("h")
1
len("hello")
5
= "world"
cs len(cs)
5
len(cs+"world") == len(cs) + len("world")
True
We can ask if a string is a substring of another string using in
.
"h" in "hello world"
True
"hello" in "hello world"
True
cs = "world"
cs in "hello world"
"ow" in "hello world"
False
Because a string is ordered we can number its characters starting from zero and access them by using square brackets.
= "hello world" cs
0] cs[
'h'
1] cs[
'e'
2] cs[
'l'
len(cs)-1] cs[
'd'
len(cs)] cs[
IndexError: string index out of range
We can also index from the end of the list.
-1] cs[
'd'
-2] cs[
'l'
-3]
cs['r'
'r'
It is now possible to solve Exercise 2.
Because the string’s characters are numbered we can slice the string to obtain only a part of it. Let us define a special cs
so that the digit of the string matches its index.
= "0123456789" cs
Grab 1st inclusive through 4th exclusive characters.
1:4] cs[
'123'
0:9] cs[
'012345678'
0:10] cs[
'0123456789'
0:] # Omitting right-endpoint defaults to previous line. cs[
'0123456789'
= "0123456789" cs
Consider that (-1) % 10 == 9
.
3:-1] cs[
'345678'
Omitting left-endpoint defaults to 0.
-1] cs[:
'012345678'
Omitting both gives everything!
cs[:]
'0123456789'
Consider that (-7) % 10 == 3
.
-7:] cs[
'3456789'
Increment by two from zero inclusive to ten exclusive.
2] cs[::
'02468'
Decrement by one from ten inclusive to zero exclusive.
-1] cs[::
'9876543210'
Increment by three from one inclusive to seven exclusive.
1:-3:3] cs[
'14'
Decrement by four from zero inclusive to ten exclusive.
0:10:-4] cs[
''
Decrement by four from ten inclusive to zero exclusive.
10:0:-4] cs[
'951'
Decrement by four from ten inclusive to zero exclusive.
-4] cs[::
'951'
Something is immutable when it cannot be changed. Strings are immutable.
We cannot capitalize a word in the following way.
= "hello"
cs 0] = "H" cs[
TypeError: 'str' object does not support item assignment
The only falsy Python string is the empty string. Every other string is truthy.
bool("a")
True
bool("Hello")
True
bool("")
False
"" < "A"
True
Empty string is “smaller” than every other character.
"" < chr(0)
True
Space and the empty character are sometimes confused because they look identical when printed.
print(" ") # 1 space
print(" ") # 2 spaces
print("") # 0 spaces
As you see the output is indistinguishable (actually you will see a difference if you try and copy the spaces). None-the-less these values are not equal.
= " " # A space. space
A space has nonzero length for example.
len(space)
1
And is truthy (whereas we expect “empty” values to be false).
bool(space)
True
On the other hand,
= "" # Empty string. empty
The empty string has no length.
len(empty)
0
And is falsey.
bool(empty)
False
Generalizing strings to collect any type (not just strings) yields tuples.
In particular, a tuple is an immutable ordered collection of elements. These elements are not necessarily the same type and are not necessarily distinct.
Round brackets ()
are used to create tuples in Python.
= (0, 1, 2, 3, 4, 5) xs
type(xs)
tuple
We still have indexing.
-1] xs[
5
Tuples are immutable.
0] = -1 xs[
TypeError: 'tuple' object does not support item assignment
Mixed types are fine.
= (1, 'a', 2, 'b')
xs = (3, 'c', 4, 'd') ys
Tuple addition (which is concatenation) may not as expected.
+ ys xs
(1, 'a', 2, 'b', 3, 'c', 4, 'd')
There is an empty tuple.
type(())
tuple
+ () xs
(1, 'a', 2, 'b')
Tuple scalar multiplication
2*xs
(1, 'a', 2, 'b', 1, 'a', 2, 'b')
Nomenclature
(0, 1) # Couple
(0, 1, 2) # Triple
(0, 1, 2, 3) # Quadruple
(0, 1, 2, 3, 4) # Quintuple
(0, 1, 2, 3, 4, 5) # Sextuple
(0, 1, 2, 3, 4, 5, 6) # Septuple
(0, 1, 2, 3, 4, 5, 6, 7) # Octuple
We have to be careful when defining the length-one tuple. The expression (1)
is not a tuple.
type((1))
int
1) (
1
Here the brackets are for changing evaluation order.
Thus the following
1) + (2) (
3
1) + (2,3) (
TypeError: unsupported operand type(s)
The singleton tuple require brackets and a comma.
type((1,))
tuple
1,) + (2,) (
(1, 2)
1, 2, 3) == (1, 2, 3) (
True
1, 2, 3) == (1, 2) (
False
1, 2, 3) < (1, 2, 4) (
True
1, 2, 3) < (1, 2) (
False
1, 2) < (1, 2, 3)
(True
True
It is sometimes possible to convert from one type into another, albeit imperfectly. We have already seen an example of this when converting from float
to integer
by way of truncation. The remaining conversions are covered in this section. Note that we omit conversions into float
s as we are trying to avoid using this type.
Python will convert the “zero” of any type to false and everything else to true. What “zero” is for the various types varies but is typically what the “empty” element would be. For instance, the “zero” for integer and float is the number 0
; the “zero” for the string type is the empty string ''
.
When a value converts to true called truthy otherwise it is falsy.
Zero is truthy.
bool(0)
False
123 is falsy.
bool(123)
True
bool(0.0)
False
bool(123.345)
True
bool("")
False
bool("hello world")
True
Bear in mind the empty string is distinct from a string of spaces
bool("")
False
bool(" ")
True
It is true that they are indistinguishable when printed but none-the-less spaces are not special, they are merely characters with no strokes that render space. To emphasize this point consider the difference in length for the two strings.
len("")
0
len(" ")
1
They are not of equal length and therefore cannot be the same!
Strings comprised of digits can be converted into integers.
int("1234")
1234
type(int("1234"))
int
But strings with alpha-characters cannot.
int("hello world")
Traceback (most recent call last):
File "<python-input-1>", line 1, in <module>
int("hello world")
Floats are converted to integers through truncation.
int(123.456)
123
Booleans are converted by taking True
to 1 and False
to 0.
int(True)
1
int(False)
0
Consequently:
True + True
2
True * False
0
The function str
returns the string representation of an object.
str(123)
'123'
This is the same string that is printed when using print
on an object.
Another, more versatile, way of converting to strings is to use the string formatter.
= 1
x = 22
y f"The sum of {x} and {y} is {x+y}"
'The sum of 1 and 22 is 23'