Back Python Chrestomathics Ahead |
Part 3 — Remembering and manipulating values
Together we learn — To say what we mean to say — A valuable skill
Section 3.1: Names have power
- There are many tales of the mythical powers associated with knowing, bestowing, and using names. The tale of Rumpelstiltskin as collected by the Brothers’ Grimm is one such tale.
Rumpelstiltskin by Anne Anderson
- For problem solving in general and for programming in particular, the ability to name things and subsequently use those names is vital. For example, an item gotten from the user or the result of a computation will be needed in future steps.
- Python supports many types of naming. We will start by keeping track of the values of calculations.
- When something is named, computing memory is set aside to hold it. When we use its name, the contents of that memory are accessed.
- In the physical world, names can be anything. Sometimes names are created specifically to be troublesome. Consider the below glyph.
It was created (and copyrighted) for the music artist Prince. He used this symbol as his representation of his name for several years to antagonize his recording label.
- Being troublesome is an anathema when programming. Clarity is paramount. Knowing what is and is not a name is an imperative.
- To emphasize naming in programming is proscriptive, the formal term is identifier. Anything named in a program must be a legal identifier.
- The rules for forming a Python identifier are given at docs.python.org. A rough translation of that document is,
- The first character of an identifier must be alphabetic. Any other characters can be alphabetic or numeric (alphanumeric).
- The underscore character (
_
) is considered alphabetic.
- Because the space character is neither alphabetic nor numeric, it cannot be used in creating an identifier.
- Character case is important. When writing out an identifier, an uppercase letter is not equivalent to its lowercase form. This rule means that
lol
,LoL
, andLOL
are different identifiers.
- Python is intended for use throughout the world. To support this cause, it uses the Unicode standard for specifying characters. Doing so allows characters from any recognized alphabet to be used as letters. In case you were wondering, Prince’s glyph is not a letter in any alphabet.
- The following terms are legal Python identifiers. It is up to you to determine why.
sum
miles_per_hound
week51
meetingTime
- The following terms are not legal Python identifiers. It is up to you recognize why.
2bOrNot2b
family name
:-)
Section 3.2 — Variables and assignment
A variable — Is like the name of a box — Store that in your brain
- We can remember the value of a calculation by using an assignment statement. The statement has form
target = calculation
- The statement should be read as target is assigned the value of the calculation. For now, target must be an identifier (later there will be additional usages, such as updating an element of a list). Such identifiers are called variables because they can be the targets of multiple assignments — allowing their values to vary over time.
- When an assignment is executed, the following actions occur.
- The calculation is evaluated.
- The calculation value is stored in computing memory.
- The target variable is associated with that memory.
- To be a successful at programming you need to have a mental model how assignment works.
- In Python jargon, the table is called a frame. There is an entry for each variable. A variable’s entry records its name, type, and identity (an idicator where its value is kept). When a variable is used, the table is examined to determine its kind of value and where to find it. A depiction of such a table follows.
Identifier | Type | Identity |
---|---|---|
distance | integer | #459720864 |
hours | integer | #459721184 |
speed | decimal | #459726944 |
snake_caseTo make the reading of programs easier, programmers often follow coding conventions. They are not rules, but guidelines. A Python coding convention is that variables are written in snake_case. The letters in a snake_case identifier are all lower case and each successive word in the identifier is preceded by a single underscore. So, |
- Our first program with assignments is program xy.py. The program has two assignment statements. If you are disappointed that it is not more spectacular, remember our plan is to take baby steps. Before reading ahead to the discussion, first attempt to determine what it does on your own.
""" Purpose: introduce assignment
"""
x = 10
y = x
print( "x:", x )
print( "y:", y )
- The program first initializes variable
x
. The value to be assigned tox
is the value to the right of the assignment operator, which is a 10.
x = 10
- When starting to learn to program, the best advice I got was keep track on paper what is happening in your code. I want to pass this advice on to you.
- I also want to pass on something of my own, when looking at code, you must be a mindful reader. I have seen many, many students frustrated with non-working code. I ask them to read aloud with precision what the code is doing. For many, aha moments quickly occur.
- For the above assignment, my tracking would record
Variable | Value |
---|---|
x | 10 |
- The program then initializes variable
y
. The value fory
is the value to the right of the assignment operator, which isx
.
y = x
Because I see the current value of
x
is 10 according to my tracking,y
is assigned 10.
Variable | Value |
---|---|
x | 10 |
y | 10 |
- When the first
print()
statement executes, two values are displayed.
print( "x:", x )
- One value is the literal string
"x:"
. In programming jargon, we call a value, a literal, if it does not require evaluating an identifier. The other value is the value of variablex
, which according to my tracking is 10. The statement outputs
x: 10
- When the next
print()
statement executes, there are again two values to display.
print( "y:", y )
- They are the literal string
"y:"
and the value of variabley
, which according to my tracking is 10. The statement outputs
y: 10
- Examine the following program xyx.py before reading ahead. Can you determine its output?
""" Purpose: demonstrate assignment only effects the being assigned
"""
x = 10
y = x
x = 20
print( "x:", x )
print( "y:", y )
- The program again first initializes variable
x
. The value assigned tox
is the value to the right of the assignment operator, which is a 10. So, my tracking again starts off with
Variable | Value |
---|---|
x | 10 |
- The program then initializes variable
y
. The value fory
is the value to the right of the assignment operator, which isx
. Because I see the current value ofx
is 10,y
is assigned 10. At this point, my tracking would again record
Variable | Value |
---|---|
x | 10 |
y | 10 |
- The program then re-assigns variable
x
. This time 20 is to be assigned tox
. So, my hand tracking would erase (update)x
’s value and put in a 20. It is very important to realize that an assignment only effects the variable to the left of the assignment operator. Looking at the below tracking there is no way to know the previous value ofx
. This inability is also true when programming.
Variable | Value |
---|---|
x | 20 |
y | 10 |
- When the first
print()
statement executes, the values displayed are the literal string"x:"
and the value of variablex
, which is 20 according to my tracking.
- When the next
print()
statement executes, the values displayed are the literal string"y:"
and the value of variabley
, which is 10 according to my tracking.
- So, the program outputs
x: 20
y: 10
- Consider the following program arf_arf.py. Quickly look at the program and guess what you think the output should be.
""" Purpose: quick assessment of assignment
"""
x = "Toto"
y = "Dog"
x = y
y = x
print( "x:", x )
print( "y:", y )
- Now check the code by hand to determine why it outputs
x: Dog
y: Dog
Section 3.3: Multi-assignment
- Sometimes there will be situations, where we want variables that capture the individual values of a sequence (e.g, characters in a string, values in a list, etc.). Two examples are demonstrated in program multiples.py
""" Purpose: demonstrate multi-assignment
"""
# Letters in love
c1, c2, c3, c4 = "love"
# Start of the new millennium
month, day, year = "January", 1, 2000
# Results
print( c1, c2, c3, c4 )
print()
print( month, day, year )
- Python allows multi-assignment if the number of variables to the left of the assignment operator matches the number of values in the sequence to the right of the assignment operator.
- Multi-assignment begins by determining the values in the sequence on the right. The values are then assigned to the target variables from left to right.
- In the first multi-assignment, the characters in the string
"love"
are assigned respectively toc1
,c2
,c3
, andc4
.
# Letters in love
c1, c2, c3, c4 = "love"
- In the second multi-assignment, the commas-separated values
"January"
, 1, and 2000 are assigned respectively tomonth
,day
, andyear
.
# Start of the new millennium
month, day, year = "January", 1, 2000
- The program output shows the assignment results.
l o v e
January 1 2000
Assignment gotchas
|
Section 3.4: Arithmetic
- To improve our problem-solving reach, we are going to add to our programming toolbox, the ability to perform calculations. We are going to start off with calculations for two types of values: integers and decimals.
- Because not all integer and decimal numbers can be stored perfectly within a computer, the creator of Python named its versions of integers, the
int
type, and its versions of decimals, thefloat
type. These names come from languages that preceded Python.
- Python provides many operators for manipulating integers and decimal numbers. Our interest is addition (
+
), subtraction (-
), multiplication (*
), decimal division (/
), integer division (//
), exponentiation (**
), and remaindering (%
).
- Operators
+
,-
,*
, and**
, all perform addition, subtraction, multiplication, and exponentiation as you would expect.
- Operator
/
performs division with a decimal result; and operator//
performs division with an integer result. In calculating the integer result, the remainder is thrown away — there is no rounding.
- Operator
%
performs remaindering by determining what is left over after doing integer division on the operands.
- Examine the following program intsy_bitsy.py before reading ahead. Can you determine its output?
# Name some variables and print their values
a = 20
b = 3
print( "a:", a )
print( "b:", b )
print()
# Perform calculations
total = a + b
difference = a - b
product = a * b
dec_quotient = a / b
int_quotient = a // b
remainder = a % b
power = a ** b
# Print results
print( "a + b: ", total )
print( "a - b: ", difference )
print( "a * b: ", product )
print( "a / b: ", dec_quotient )
print( "a // b:", int_quotient )
print( "a ** b:", power )
print( "a % b: ", remainder )
- The program output is below.
a = 20
b = 3
a + b: 23
a - b: 17
a * b: 60
a / b: 6.666666666666667
a // b: 6
a ** b: 8000
a % b: 2
- In true decimal division, the value of
20 / 3
is 6.666666666…, where the 6’s continue forever. Current Python applications generally provide 15- or 16-digit accuracy. So,20
/
3
evaluates to 6.666666666666667.
- See that
20 // 3
was 6, rather than 7. The integer division operator does not round, it drops the decimal remainder.
- See that
20 % 3
was 2. Because 3 goes into 20, six times, with a remainder of 2.
- See that
20 ** 3
was 8000, which is 203.
- Examine the following program floatilla.py before reading ahead. Can you determine its output?
# Name some variables and print their values
x = 2.71
y = 3.14
print( "x:", x )
print( "y:", y )
print()
# Perform calculations
total = x + y
difference = x - y
product = x * y
dec_quotient = x / y
int_quotient = x // y
remainder = x % y
power = x ** y
# Print results
print( "x + y: ", total )
print( "x - y: ", difference )
print( "x * y: ", product )
print( "x / y: ", dec_quotient )
print( "x // y:", int_quotient )
print( "x ** y:", power )
print( "x % y: ", remainder )
- The program output is below.
x = 2.71
y = 3.14
x + y: 5.85
x - y: -0.43000000000000016
x * y: 8.5094
x / y: 0.8630573248407643
x // y: 0.0
x ** y: 22.883559193263366
x % y: 2.71
- You might wonder why when looking at the output, the integer division operator produced a decimal value. The Python arithmetical operators always produce a decimal value if any of the operands is decimal. However, the division was integer in that it threw away the remainder.
Section 3.5: Case study — hip-hopping
- Suppose we want to develop a program hip_hopping.py to simulate the number of rabbits occurring over four generations, where the number of rabbits doubles each generation, and there are six rabbits at the start.
- The program output appears below.
Generation: 1
Rabbits: 6
Generation: 2
Rabbits: 12
Generation: 3
Rabbits: 24
Generation: 4
Rabbits: 48
- I have been a professional programmer as a research scientist, employee, and consultant. These experiences made me painfully aware that customers (myself included) often modify the task to be accomplished. To ease the pain of such requests it pays to think ahead.
- To help here, I think it would be helpful to have two variables to set basic conditions.
# Simulation set up
starting_number_of_rabbits = 6
growth_rate = 2
- Having these variables helps isolate changes if the simulation scenario changes. By using these variables in the rest of program, that code does not to be altered if the initial conditions change.
Variable | Value |
---|---|
starting_number_of_rabbits | 6 |
growth_rate | 2 |
- In the future we will discuss how to repeat actions a desired of number of times. For now, we take baby steps, so our code explicitly handles four generations.
- The code to handle the first generation would be
# First generation
number_of_rabbits = starting_number_of_rabbits
generation = 1
print( "Generation:", generation )
print( "Rabbits: ", number_of_rabbits )
- Here we define and print two variables that we will use to keep track of current conditions in the simulation. Variable
number_of_rabbits
tracks the number of rabbits in the current generation. Variablegeneration
tracks what generation is being processed.
Variable | Value |
---|---|
starting_number_of_rabbits | 6 |
growth_rate | 2 |
number_of_rabbits | 6 |
generation | 1 |
- To handle the next (second) generation, the number of rabbits and generation number need to be updated.
# Next generation (second)
number_of_rabbits = growth_rate * number_of_rabbits
generation = generation + 1
print( "Generation:", generation )
print( "Rabbits: ", number_of_rabbits )
- The new number of rabbits is produced by multiplying the current number of rabbits by the generation growth rate.
- The new generation number is one greater than the current generation number.
- Seeing variables being updated in terms of their current values is often upsetting for new programmers. What we need to remind ourselves is that the assignment works by first evaluating the right-hand side expression and then using that value to update the target on the left-hand side.
- After the code executes, our variables look like
Variable | Value |
---|---|
starting_number_of_rabbits | 6 |
growth_rate | 2 |
number_of_rabbits | 12 |
generation | 2 |
- The code to handles the next (third) generation is the same because the number of rabbits and generation number need to be updated in the same way.
# Next generation (third)
number_of_rabbits = growth_rate * number_of_rabbits
generation = generation + 1
print( "Generation:", generation )
print( "Rabbits: ", number_of_rabbits )
- After the code executes, our variables look like
Variable | Value |
---|---|
starting_number_of_rabbits | 6 |
growth_rate | 2 |
number_of_rabbits | 24 |
generation | 3 |
- Because we continue to want to update the simulation in the same way, The code to handle the last generation is the same as that of the second and third generations.
# Next generation (fourth)
number_of_rabbits = growth_rate * number_of_rabbits
generation = generation + 1
print( "Generation:", generation )
print( "Rabbits: ", number_of_rabbits )
- After the code executes, our variables look like
Variable | Value |
---|---|
starting_number_of_rabbits | 6 |
growth_rate | 2 |
number_of_rabbits | 48 |
generation | 4 |
- The simulation requiring four generations had two purposes: reinforce assignment nuances and to make you want a mechanism to repeat actions.
Experimenting
|
Section 3.6: Casting
Castings are like spells — New kinds of values from old — But no wands needed
- When programming you will often have a data value whose type is of the wrong form — a decimal when an integer is needed, or vice-versa; or a numeric string when a numeric is needed. For these situations, there are two built-in functions to help.
int()
: returns the integer equivalent of its argument.
float()
: returns the decimal equivalent of its argument.
- Program cast_away.py demonstrates some uses of the functions.
""" Purpose: demonstrate some casting functions
"""
# Set and print values of interest
i = 1
f = 2.9
c = "33"
d = "4.5"
print( "Values"
print( "i:", i )
print( "f:", f )
print( "c:", "'" + c + "'" )
print( "d:", "'" + d + "'" )
print()
# Perform conversions
int_f = int( f )
float_i = float( i )
int_c = int( c )
float_d = float( d )
# Display results
print( "Conversions" )
print( "int( f ):", int_f )
print( "float( i ):", float_i )
print()
print( "int( c ):", int_c )
print( "float( d ):", float_d )
- The program produces output
Values
i: 1
f: 2.9
c: '33'
d: '4.5'
Conversions
int( f ): 2
float( i ): 1.0
int( c ): 33
float( d ): 4.5
- There are two
print()
statements that are more involved than usual. I thought it was important when examining the output that it be obvious thatc
andd
were numeric strings. It would be good for you to go over them to see how they worked. I will just say for now that you can add two strings together to get a new string. If you cannot wait, please checkout the daydreamer.py example.
print( "c:", "'" + c + "'" )
print( "d:", "'" + d + "'" )
- The first conversion output tells us that the
int()
function when given a decimal, throws away the decimal amount in producing its new integer. It does not round.
- The next conversion output tells us that the
float()
function when given an integer, adds a fractional amount of .0 to its new decimal.
- The other conversion output tells us that the
int()
andfloat()
functions can convert numeric strings into numeric values.
Section 3.7: What’s next
- We turn how our attention how to get input to our programs. With that ability we can problem solve.
That Black Lives Matter — Should be so easy to grasp — People are people
Back Ahead |