CS1302 Introduction to Computer Programming
import sys # to access system-specific parameters
from ipywidgets import interact # for interactive user interface controls
%reload_ext divewidgets
# use OPTLite to visualize code executionValues¶
Programming is the art of instructing a computer to perform tasks by manipulating data, which is represented as values. In mathematical terms, a computer is a model of how values are stored and manipulated. Values are the building blocks of programs, and they represent a specific piece of data that can be manipulated in various ways.
While a machine language only uses binary numbers as values, higher-level programming languages provide more flexible and expressive ways to represent and manipulate values. Understanding the concept of value is crucial in programming, as it is the foundation upon which all computations are built.
Integers¶
In Python, we can enter an integer in different number systems other than the binary one:
# in decimal (base 10)
15# in binary (base 2)
0b1111# in octadecimal (base 8)
0o17# in hexadecimal (base 16)
0xFThere are also expressions with integer values but are not integer literal:
4 + 5 + 6### BEGIN SOLUTION
# There is no limit on how big an integer can be
10 ** sys.get_int_max_str_digits() - 1
# see what happens with -1 removed.
### END SOLUTIONStrings¶
A string value is a sequence of characters that can be written literally using quotes:
# single quote
print('\U0001f600:\n\tI\'m a string.')# double quote
print("\N{grinning face}:\n\tI'm a string.")# triple double quote
print(
"""😀:
I'm a string."""
)With Python, there are often many ways to do the same thing. The following one-line code (one-liner) also prints the multiple lines of strings:
print("\N{grinning face}:", "\tI'm a string.", sep="\n")What are benefits of allowing single, double, and triple quotes for string literals?
- By using double quotes, we don't need to escape the single quote in strings such as "I'm".
- Triple quotes enable a multi-line string literal to include the newline character directly, resulting in a more readable representation of the literal.
Print a cool multi-line string below.
See Also
art: https://www.ascii-art.sitebashplotlib: https://github.com/glamp/bashplotlib- Star Wars via Telnet: http://asciimation.co.nz/
### BEGIN SOLUTION
print(
"""
(ง •̀_•́)ง
╰(●’◡’●)╮
(..•˘_˘•..)
(づ ̄ 3 ̄)づ
"""
)
# install art module
!pip install art >/dev/null 2>&1
import art
yyyy, mm = "2023", "09"
art.tprint(f"""{yyyy}{mm}CS1302
Intro to Comp Progm'g""")
### END SOLUTIONUser Input¶
Instead of entering a value in a program, a programmer can get user input values at runtime, i.e., as a program executes:
print("Your name is", input("Please input your name: "))- The
inputmethod prints its argument, if any, as a prompt. - The method takes user's input and returns it as a string.
- There is no need to delimit the input string by quotation marks. Simply press
enterafter typing a string.
Explain whether the following code prints 'My name is Python'. Does print return a value?
print("My name is", print("Python"))Solution to Exercise 3 #
- Unlike
input, the functionprintdoes not return the string it is trying to print. Printing a string is, therefore, different from returning a string. printactually returns aNoneobject that gets printed asNone.
Variables¶
To perform complex computations, computers require data to be stored in memory and accessed through addresses. This is where variables come in - they serve as a simplified storage unit that abstracts away the complexities of memory addressing and value storage. With variables, programmers can assign a meaningful name and a value of various types without having to worry about the underlying memory addresses and binary interpretations. This simplifies the programming process and enables developers to focus on the logic of their code, rather than the intricacies of memory management.
Assignment¶
To define a variable, we can use the assignment operator = as follows:
x = 15
print(x)An assignment operation x = 15 is different from
- a statement of equality that is equal to 15, or
- a definition that is defined to be .
To understand the difference, let's see the effect of the following assignments step-by-step using OPTLite:
%%optlite -h 300
x = 15
x = x + 1In the second line, the value of x is incremented, i.e., increased by 1. It would not make sense to say is equal to or defined to be , since no choices of (other than ) satisfy this.
It is possible to assign different values to multiple variables in one line using the so-called tuple assignment syntax:
%%optlite -h 300
x, y, z = "15", "30", 15One can also assign the same value to different variables in one line using a chained assignment:
%%optlite -h 300
x = y = z = 0Once defined, variables can be deleted using del. Accessing a variable not assigned any value raises an error.
%%optlite -h 350
x = y = 0
del x, y
x, yIdentifiers¶
In Python, identifiers such as variable names are case sensitive, unlike older languages such as Pascal and Fortran. Furthermore, not all strings are valid identifiers:
What is the syntax for identifiers?
Must start with a letter or
_(an underscore) followed by letters, digits, or_.Must not be a keyword reserved by python:
False await else import pass None break except in raise True class finally is return and continue for lambda try as def from nonlocal while assert del global not with async elif if or yield
Evaluate the following cell and check if any of the rules above is violated.
The code uses interact imported at the beginning of the notebook with:
from ipywidgets import interactHint
delis a keyword andDelis not because identifiers are case sensitive.- Function names such as
print,input,type, etc., are not keywords and can be reassigned.
This can be useful if you want to modify the default implementations without changing their source code.
@interact
def identifier_syntax(
assignment=[
"a-number = 15",
"a_number = 15",
"15 = 15",
"_15 = 15",
"del = 15",
"Del = 15",
"type = print",
"print = type",
"input = print",
]
):
exec(assignment)
print("Ok.")Solution to Exercise 4
a-number = 15violates Rule 1 because-is not allowed.-is interpreted as an operator.15 = 15violates Rule 1 because15starts with a digit instead of letter or _.del = 15violates Rule 2 becausedelis a keyword.
To help make the code more readable, programmers follow additional style guides such as Python Enhancement Proposals (PEP) 8:
- Function names should be lowercase, with words separated by underscores as necessary to improve readability.
- Variable names follow the same convention as function names.
Type Conversion¶
The following program tries to compute the sum of two numbers from user inputs:
num1 = input("Please input an integer: ")
num2 = input("Please input another integer: ")
print(num1, "+", num2, "is equal to", num1 + num2)Unfortunately, there is a bug in the above code. Can you locate the error?
Solution to Exercise 5 #
The two numbers are concatenated instead of added together.
input returns user input as a string. E.g., if the user enters 12, the input is
- not treated as the integer twelve, but rather
- treated as a string containing two characters, one followed by two.
To confirm this, we can use type to return the data type of an expression.
num1 = input("Please input an integer: ")
print("Your input is", num1, "with type", type(num1))type can apply to any expressions. Try it out below.
type(15), type(print), type(print()), type(input), type(type), type(type(type))What happens when we add strings together?
"4" + "5" + "6"How to fix the bug then?
We can convert a string to an integer using int.
int("4") + int("5") + int("6")We can also convert an integer to a string using str.
str(4) + str(5) + str(6)Fix the bug in the following cell.
num1 = input("Please input an integer: ")
num2 = input("Please input another integer: ")
# print(num1, '+', num2, 'is equal to', num1 + num2) # fix this line below
### BEGIN SOLUTION
print(num1, "+", num2, "is equal to", int(num1) + int(num2))
### END SOLUTIONError types¶
In addition to writing code, a programmer spends significant time in debugging code that contains errors.
Can an error be automatically detected by the computer?
- You have just seen an example of a logical error, which is due to an error in the logic.
- The ability to debug or even detect such an error is, unfortunately, beyond Python's intelligence.
Other kinds of error may be detected automatically.
As an example, note that we can omit + for string concatenation, but we cannot omit it for integer summation:
print("Skipping + for string concatenation")
"4" "5" "6"print('Skipping + for integer summation')
4 5 6Python interpreter detects the bug and raises a syntax error.
Why Syntax error can be detected automatically?
Why is the print statement before the error not executed?
- The Python interpreter can detect syntax error even before executing the code because
- the interpreter simply fails to translate the code to lower-level executable code.
The following code raises a different kind of error.
print("Evaluating '4' + '5' + 6")
"4" + "5" + 6 # summing string with integerWhy Python throws a TypeError when evaluating '4' + '5' + 6?
There is no implementation of + operation on a value of type str and a value of type int.
- Unlike the syntax error, the Python interpreter can only detect a type error at runtime (when executing the code.)
- Hence, such an error is called a runtime error.
Do other languages work in the same way?
The following cell runs the corresponding javascript code using a cell magic:
%%javascript
let x = '4' + '5' + 6;
element.append(x + ' ' + typeof(x));
// no error because 6 is converted to a str implicitly%%javascript
let x = '4' * '5' * 6;
element.append(x + ' ' + typeof(x));
// no error because 4 and 5 are converted to numbers implicitlyJavascript forces a type conversion to avoid a type error. It is called a weakly-typed language.
Python is a strongly-and-dynamically-typed language:
- Strongly-typed: Python does not force a type conversion to avoid a type error.
- Dynamically-typed: Python checks data type only at runtime after translating the code to machine code.
In comparison, C/C++ and Java are statically-typed languages that checks data type during compilation.
try:
!gcc 456.cpp
except Error:
print('Cannot run shell command.')try:
!javac 456.java
except Error:
print('Cannot run shell command.')While weakly-typed languages may seem more robust, they can potentially lead to more logical errors. JavaScript, despite its popularity, is known for its tricky behavior, as demonstrated in wtfjs.
See Also
To improve readability and avoid logical errors, it's recommended to use a strongly-typed language like TypeScript. TypeScript is a superset of JavaScript that adds optional static typing and other features to the language. By enforcing stronger typing, TypeScript can detect potential errors at compile-time and improve the overall reliability of your code. Learn more about TypeScript at typescriptlang.org.
Not all the strings can be converted into integers. Try breaking the following code by providing invalid inputs and record them in the subsequent cell. Explain whether the errors are runtime errors.
num1 = input("Please input an integer: ")
num2 = input("Please input another integer: ")
print(num1, "+", num2, "is equal to", int(num1) + int(num2))Solution to Exercise 8 #
Some possible invalid inputs are:
4 + 5 + 6,15.0,fifteen
It raises a value error, which is a runtime error detected during execution.
Note that the followings are okay
int('-1'),eval('4 + 5 + 6')
Floating Point Numbers¶
Not all numbers are integers. In Enginnering, we often need to use fractions.
How to enter fractions in a program?
x = -0.1 # decimal number
y = -1.0e-1 # scientific notation
z = -1 / 10 # fraction
x, y, z, type(x), type(y), type(z)What is the type float?
floatcorresponds to the floating point representation.- A
floatis stored exactly the way we write it in scientific notation:
An efficient implementation is more complicated. Try the IEEE-754 Floating Point Converter for single-precision floating point number:
- Starting from the number 0, click the button
+1to find the smallest positive number. - Find the largest and smallest representable floating point numbers.
Integers in mathematics may be regarded as a float instead of int:
type(1.0), type(1e2)You can also convert an int or a str to a float.
float(1), float("1")Is it better to store an integer as float?
Python stores a floating point with finite precision, usually 64-bit/double precision:
sys.float_infoIt cannot accurately represent a number larger than the max:
sys.float_info.max * 2The precision also affects the check for equality.
(
1.0 == 1.0 + sys.float_info.epsilon * 0.5, # returns true if equal
1.0 == 1.0 + sys.float_info.epsilon * 0.6,
sys.float_info.max + 1 == sys.float_info.max,
)Another issue with float is that it may keep more decimal places than desired.
1 / 3How to round a floating point number to the desired number of decimal places?
round(2.665, 2), round(2.675, 2)Why 2.675 rounds to 2.67 instead of 2.68?
- A
floatis actually represented in binary. - A decimal fraction may not be represented exactly in binary.
Use the IEEE-754 Floating Point Converter to find out the value actually stored in float for 2.675.
Solution to Exercise 9 #
The value stored is 2.6749999523162841796875, which explains why it is rounded to 2.67 instead of 2.68.
The round function can also be applied to an integer.
round(150, -2), round(250, -2)Why 250 rounds to 200 instead of 300?
- Python 3 implements the default rounding method in IEEE 754.
String Formatting¶
Can we round a float or int for printing but not calculation?
This is possible with format strings:
x = 10000 / 3
print("x ≈ {:.2f} (rounded to 2 decimal places)".format(x))
x{:.2f}is a replacement field or place holder- that gets replaced by a string
- that represents the argument
xofformat - according to the format specification
.2f, i.e.,
a decimal floating point number rounded to 2 decimal places.
float)Play with the following widget to learn the effect of different format specifications. In particular, print 10000/3 as 3,333.33.
@interact(
x="10000/3",
align={"None": "", "<": "<", ">": ">", "=": "=", "^": "^"},
sign={"None": "", "+": "+", "-": "-", "SPACE": " "},
width=(0, 20),
grouping={"None": "", "_": "_", ",": ","},
precision=(0, 20),
)
def print_float(x, sign, align, grouping, width=0, precision=2):
format_spec = (
f"{{:{align}{sign}{'' if width==0 else width}{grouping}.{precision}f}}"
)
print("Format spec:", format_spec)
print("x ≈", format_spec.format(eval(x)))print("{:,.2f}".format(10000 / 3))String formatting is useful for different data types other than float.
E.g., consider the following program that prints a time specified by some variables.
# Some specified time
hour = 12
minute = 34
second = 56
print("The time is " + str(hour) + ":" + str(minute) + ":" + str(second) + ".")Imagine you have to show also the date in different formats.
The code can become very hard to read/write because
- the message is a concatenation of multiple strings and
- the integer variables need to be converted to strings.
Omitting + leads to syntax error. Removing str as follows also does not give the desired format.
print("The time is ", hour, ":", minute, ":", second, ".") # note the extra spacesTo make the code more readable, we can use the format function as follows.
message = "The time is {}:{}:{}."
print(message.format(hour, minute, second))- We can have multiple place-holders
{}inside a string. - We can then provide the contents (any type: numbers, strings..) using the
formatfunction, which - substitutes the place-holders by the function arguments from left to right.
According to the string formatting syntax, we can change the order of substitution using
- indices (0 is the first item) or
- names inside the placeholder
{}:
print("You should {0} {1} what I say instead of what I {0}.".format("do", "only"))
print("The surname of {first} {last} is {last}.".format(first="John", last="Doe"))You can also put variables inside the format specification directly and have a nested string formatting.
align, width = "^", 5
print(f"{{:*{align}{width}}}".format(x)) # note the syntax f"..."Play with the following widget to learn more about the formating specification.
- What happens when
alignis none butfillis*? - What happens when the
expressionis a multi-line string?
@interact(
expression=r"'ABC'",
fill="*",
align={"None": "", "<": "<", ">": ">", "=": "=", "^": "^"},
width=(0, 20),
)
def print_object(expression, fill, align="^", width=10):
format_spec = f"{{:{fill}{align}{'' if width==0 else width}}}"
print("Format spec:", format_spec)
print("Print:", format_spec.format(eval(expression)))Solution to Exercise 11
- It returns a ValueError because align must be specified when fill is.
- The newline character is simply regarded a character. The formatting is not applied line-by-line. E.g., try 'ABC\nDEF'.