Python Essentials

Contents

3. Python Essentials#

3.1. Overview#

This section cover the features of Python in a systematic way.

This approach helps clear up some details.

3.2. Comments#

Comments in Python is the inclusion of short descriptions along with the code to increase its readability. A developer uses them to write his or her thought process while writing the code. It explains the basic logic behind why a particular line of code was written. They are just meant for the coders themselves or other developers to understand a piece of code, especially since the Python interpreter completely ignores comments in Python.

The advantages of comments are:

  1. Enhanced code readability

  2. Code that documents itself

  3. Improved cooperation

  4. Improved troubleshooting

  5. Code control

  6. Logic explanation

  7. Code maintainability

  8. Code reuse

  9. Knowledge sharing

  10. Learning aid

  11. Documenting the steps and needs for a function

There are three types of comments:

  • single-line

  • multi-line

  • string literals

  • docstring comments

3.2.1. Single-Line Comments#

Single-line comments begin with the “#” character. Anything that is written in a single line after ‘#’ is considered as a comment. Python’s single-line comments are proved useful for supplying short explanations for variables, function declarations, and expressions.

The syntax for writing single-line comments is:

# comments here

There are two ways of using single-line comments in Python. You can use it before the code or next to the code.

# Write 'Hello, World' to standard output.
print('Hello, World')  # single-line comment next to the code

PEP8, Python Style Guide, recommends using less than 79 characters in a single-line comment to make it easier to read. If your comment is exceeding the recommended length, you can use the next type: multi-line comments.

3.2.2. Multi-Line Comments#

Python does not support multi-line comments. However, there are multiple ways to overcome this issue. None of these ways are technically multi-line comments, but you can use them as one. The first way is by using # at the beginning of each line of the comment.

# You can use 
# multi-line comments
# in this way by
# including the comment character
# at the bebinning of each line

The next way is by using string literals but not assigning them to any variables. Python ignores the string literals that are not assigned to a variable so we can use these string literals as Python comments. You can either use a single (’ ‘) quotation or double (” “) quotation to insert single-line comments using string literals

'This will be ignored by Python'
" This also will be ignored "

Multiline comments can de inserted using string literals with triple quotes (‘’’).

""" Python program to demonstrate 
 multiline comments"""
print("Multiline comments")

Comments should be made at the same indent as the code it is commenting on.

def GFG(): 
    
  # Since, this comment is inside a function 
  # It would have indent same as the function body 
  print("Start the code") 
    
  for i in range(1, 2): 
  
    # Be careful of indentation 
    # This comment is inside the body of for loop 
    print("Welcome to Comments in Python") 
    
# This comment is again outside the body 
# of function so it wont have any indent. 
  
print("Hello !!") 
GFG()
Hello !!
Start the code
Welcome to Comments in Python

3.2.3. Docstring#

  • Python docstring is the string literals with triple quotes that are appeared right after the function.

  • It is used to associate documentation that has been written with Python modules, functions, classes, and methods.

  • It is added right below the functions, modules, or classes to describe what they do. In Python, the docstring is then made available via the doc attribute. The help function can be used also.

Example:

def multiply(a, b): 
    """Multiplies the value of a and b"""
    return a*b 
  
# Print the docstring of multiply function 
print("Using __doc__:")
print(multiply.__doc__) 

print("Using help:")
help(multiply)
Using __doc__:
Multiplies the value of a and b
Using help:
Help on function multiply in module __main__:

multiply(a, b)
    Multiplies the value of a and b

3.3. Data Types#

A data type is a set of values and a set of operations defined on those values. Many data types are built into the Python language. Python has built-in data types, for example: int (for integers), float (for floating-point numbers), str (for sequences of characters) and bool (for true-false values).

To talk about data types, we need to introduce some terminology.

3.3.1. Definitions#

In the following code fragment:

a = 1234
b = 99
c = a + b

This code creates three objects, each of type int, using the literals 1234 and 99 and the expression a + b, and binds variables a, b, and c to those objects using assignment statements. The end result is that variable c is bound to an object of type int whose value is 1333.

3.3.1.1. Objects#

All data values in a Python program are represented by objects and relationships among objects. An object is an in-computer-memory representation of a value from a particular data type. Each object is characterized by its identity, type, and value.

  • The identity uniquely identifies an object. You should think of it as the location in the computer’s memory (or memory address) where the object is stored.

  • The type of an object completely specifies its behavior — the set of values it might represent and the set of operations that can be performed on it.

  • The value of an object is the data-type value that it represents.

Each object stores one value; for example, an object of type int can store the value 1234 or the value Different objects may store the same value. We can apply to an object any of the operations defined by its type (and only those operations). For example, we can multiply two int objects but not two str objects.

3.3.1.2. Object references#

An object reference is nothing more than a concrete representation of the object’s identity (the memory address where the object is stored). Python programs use object references either to access the object’s value or to manipulate the object references themselves.

3.3.1.3. Literals#

A literal is a Python-code representation of a data-type value. It creates an object with the specified value.

3.3.1.4. Operators#

An operator is a Python-code representation of a data-type operation. For example, Python uses + and * to represent addition and multiplication for integers and floating-point numbers; Python uses and, or, and not to represent boolean operations; and so forth.

3.3.1.5. Identifiers#

An identifier is a Python-code representation of a name. Each identifier is a sequence of letters, digits, and underscores, the first of which is not a digit. You should keep in mind that the letters are case sensitive.

3.3.1.6. keywords#

The keywords are reserved and you cannot use them as identifiers. To get the number and list the keywords in the current version, we can use the code:

import keyword 
list = keyword.kwlist 
print("No. of keywords present in current version :", 
len(list)) 
print(list) 
No. of keywords present in current version : 35
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

3.3.1.7. Variables#

A variable is a name for an object reference. A variable has a name (or identifier) and holds a value. It is important to choose a name which is self-descriptive and closely reflects the meaning of the variable.

3.3.1.8. Expressions#

An expression is a combination of literals, variables, and operators that Python evaluates to produce an object. Each operand can be any expression, perhaps within parentheses. For example, we can compose expressions like 4 * (x - 3) or 5 * x - 6 and Python will understand what we mean.

3.3.1.9. Statements#

A Python statement is delimited by a newline. A statement cannot cross line boundaries, except:

  1. An expression in parentheses (), square bracket [], and curly braces {} can span multiple lines.

  2. A backslash () at the end of the line denotes continuation to the next line. This is an old rule and is NOT recommended as it is error prone.

You can place multiple statements on a single line, separated by semicolon (;).

3.3.2. Common built-in Python data types#

English name

Type name

Type Category

Description

Example

integer

int

Numeric Type

positive/negative whole numbers

42

floating point number

float

Numeric Type

real number in decimal form

3.14159

complex

complex

Numeric Type

complex number in decimal form

2 + 5j

boolean

bool

Boolean Values

true or false

True

string

str

Text Type

text

"I Can Has Cheezburger?"

list

list

Sequence Type

a collection of objects - mutable & ordered

['Pio', 'Dario', 'Marian']

tuple

tuple

Sequence Type

a collection of objects - immutable & ordered

('Thursday', 6, 9, 2022)

range

set

Sequence Type

sequence of numbers - inmutable & ordered

x = range(6)

dictionary

dict

Mapping Type

mapping of key-value pairs

{'name':'CAI', 'code':696, 'credits':6}

set

set

Mapping Type

a collection of objects - mutable

{2, 5, 7, 'a', 'z'}

binary

bytes

Binary Type

immutable sequences of single bytes

x = b"Hello"

none

NoneType

Null Object

represents no value

None

3.3.3. Numeric data types#

There are three distinct numeric types: integers, floating point numbers, and complex numbers. We can determine the type of an object in Python using type(). We can print the value of the object using print().

3.3.3.1. Integers#

The int data type represents integers or natural numbers. Unlike C/C++/Java, integers are of unlimited size in Python. By default the integer literal are in decimal base, but you can also express integers in hexadecimal with prefix 0x (or 0X); in octal with prefix 0o (or 0O); and in binary with prefix 0b (or 0B). For examples, 0x1abc, 0X1ABC, 0o1776, 0b11000011.

Examples:

>>> 123 + 456 - 789
-210
>>> 123456789012345678901234567890 + 1
123456789012345678901234567891
>>> 1234567890123456789012345678901234567890 + 1
1234567890123456789012345678901234567891
>>> 2 ** 888     # Raise 2 to the power of 888
......
>>> len(str(2 ** 888))  # Convert integer to string and get its length
268                     # 2 to the power of 888 has 268 digits
>>> type(123)    # Get the type
<class 'int'>
>>> help(int)    # Show the help menu for type int
>>> # Integer Literal
>>> int_1 = 450    #Decimal Literal
>>> int_2 = 0b1011 #Binary Literal
>>> int_3 = 0o310 #Octal Literal
>>> int_4 = 0x12c #Hexadecimal Literal

3.3.3.2. Floating-point numbers (type float)#

The float data type is for representing floating-point numbers, for use in scientific and commercial applications. We use floating-point numbers to represent real numbers, but they are not the same as real numbers!. There are infinitely many real numbers, but we can represent only a finite number of floating-point numbers in any digital computer due the IEEE 64-bit representation. For example, 5.0/2.0 evaluates to 2.5 but 5.0/3.0 evaluates to 1.6666666666666667. Typically, floating-point numbers have 15 decimal digits of precision.

Examples of float numbers are: 1.0, -2.3, 3.4e5, -3.4E-5, with a decimal point and an optional exponent (denoted by e or E). .

Examples:

>>> 1.23 * -4e5
-492000.0
>>> type(1.2)        # Get the type
<class 'float'>
>>> import math      # Using the math module
>>> math.pi
3.141592653589793
>>> import random    # Using the random module
>>> random.random()  # Generate a random number in [0, 1)
0.890839384187198

3.3.3.3. Complex Numbers (type complex)#

Complex numbers have a real part and an imaginary part denoted with suffix of j (or J).

Examples:

>>> x = 1 + 2j  # Assign variable x to a complex number
>>> x = complex(1, 2)  # antother form to assign x to a complex number
>>> x           # Display x
(1+2j)
>>> x.real      # Get the real part
1.0
>>> x.imag      # Get the imaginary part
2.0
>>> type(x)     # Get type
<class 'complex'>
>>> x * (3 + 4j)  # Multiply two complex numbers
(-5+10j)

3.3.3.4. Booleans (type bool)#

The bool data type has just two values: True and False. Take note of the spelling in initial-capitalized.

In Python, integer 0, an empty value (such as empty string ‘’, “”, empty list [], empty tuple (), empty dictionary {}), and None are treated as False; anything else are treated as True. Booleans can also act as integers in arithmetic operations with 1 for True and 0 for False. This is called Boolean arithmetic and is often useful in programming.

Examples:

x = True
x
type(x)
y = 100 < 10
y
type(y)
x + y
x * y
True + True
bools = [True, True, False, True]  # List of Boolean values

sum(bools)
3

3.3.3.5. Others types#

Other number types are provided by external modules, such as decimal module for decimal fixed-point numbers, fraction module for rational numbers.

Examples:

# floats are imprecise
>>> 0.1 * 3
0.30000000000000004

# Decimal are precise
>>> import decimal  # Using the decimal module
>>> x = decimal.Decimal('0.1')  # Construct a Decimal object
>>> x * 3    # Multiply  with overloaded * operator
Decimal('0.3')
>>> type(x)  # Get type
<class 'decimal.Decimal'>
>>> from fractions import Fraction
>>> Fraction(16, -10)
Fraction(-8, 5)

3.3.3.6. The None Value#

Python provides a special value called None (take note of the spelling in initial-capitalized), which can be used to initialize an object (to be discussed in OOP later). For example,

>>> x = None
>>> type(x)   # Get type
<class 'NoneType'>
>>> print(x)
None

# Use 'is' and 'is not' to check for 'None' value.
>>> print(x is None)
True
>>> print(x is not None)
False

3.3.3.7. Dynamic Typing#

Python is dynamic typed, that means:

  • Python associates type with object, instead of variable. That is, a variable does not have a fixed type and can be assigned an object of any type. A variable simply provides a reference to an object.

  • You do not need to declare a variable before using a variable. A variable is created automatically when a value is first assigned, which links the assigned object to the variable.

You can use built-in function type(var_name) to get the object type referenced by a variable.

>>> x = 1         # Assign an int value to create variable x
>>> x             # Display x
1
>>> type(x)       # Get the type of x
<class 'int'>
>>> x = 1.0       # Re-assign a float to x
>>> x
1.0
>>> type(x)       # Show the type
<class 'float'>
>>> x = 'hello'   # Re-assign a string to x
>>> x             
'hello'
>>> type(x)       # Show the type
<class 'str'>
>>> x = '123'     # Re-assign a string (of digits) to x
>>> x
'123'
>>> type(x)       # Show the type
<class 'str'>

3.3.3.8. Type Casting: int(x), float(x), str(x)#

You can perform type conversion (or type casting) via built-in functions int(x), float(x), str(x), bool(x), etc. For example,

>>> x = '123'     # string
>>> type(x)
<class 'str'>
>>> x = int(x)    # Parse str to int, and assign back to x
>>> x
123
>>> type(x)
<class 'int'>
>>> x = float(x)  # Convert x from int to float, and assign back to x
>>> x
123.0
>>> type(x)
<class 'float'>
>>> x = str(x)    # Convert x from float to str, and assign back to x
>>> x
'123.0'
>>> type(x)
<class 'str'>
>>> len(x)        # Get the length of the string
5
>>> x = bool(x)   # Convert x from str to boolean, and assign back to x
>>> x             # Non-empty string is converted to True
True
>>> type(x)
<class 'bool'>
>>> x = str(x)    # Convert x from bool to str
>>> x
'True'

In summary, a variable does not associate with a type. Instead, a type is associated with an object. A variable provides a reference to an object (of a certain type).

3.3.3.9. Check Instance’s Type: isinstance(instance, type)#

You can also use the built-in function isinstance(instance, type) to check if the instance belong to the type. For example,

>>> isinstance(123, int)
True
>>> isinstance('a', int)
False
>>> isinstance('a', str)
True

3.3.3.10. The Assignment Operator (=)#

In Python, you do not need to declare variables before using the variables. The initial assignment creates a variable and links the assigned value to the variable. For example,

>>> x = 8        # Create a variable x by assigning a value
>>> x = 'Hello'  # Re-assign a value (of a different type) to x

>>> y            # Cannot access undefined (unassigned) variable
NameError: name 'y' is not defined

3.3.3.11. Pair-wise Assignment and Chain Assignment#

For example,

>>> a = 1  # Ordinary assignment
>>> a
1
>>> b, c, d = 123, 4.5, 'Hello'  # Pair-wise assignment of 3 variables and values
>>> b
123
>>> c
4.5
>>> d
'Hello'
>>> e = f = g = 123  # Chain assignment
>>> e
123
>>> f
123
>>> g
123

Assignment operator is right-associative, i.e., a = b = 123 is interpreted as (a = (b = 123)).

3.3.3.12. del Operator#

You can use del operator to delete a variable. For example,

>>> x = 8     # Create variable x via assignment
>>> x
8
>>> del x     # Delete variable x
>>> x
NameError: name 'x' is not defined

3.3.4. Number Operations#

3.3.4.1. Arithmetic Operators#

Python supports these arithmetic operators:

Operator

Mode

Usage

Description

Example

+

Binary
Unary

x + y
+x

Addition
Positive

-

Binary
Unary

x - y
-x

Subtraction
Negate

*

Binary

x * y

Multiplication

/

Binary

x / y

Float Division (Returns a float)

1 / 2 ⇒ 0.5
-1 / 2 ⇒ -0.5

//

Binary

x // y

Integer Division (Returns the floor integer)

1 // 2 ⇒ 0
-1 // 2 ⇒ -1
8.9 // 2.5 ⇒ 3.0
-8.9 // 2.5 ⇒ -4.0 (floor!)
-8.9 // -2.5 ⇒ 3.0

**

Binary

x ** y

Exponentiation

2 ** 5 ⇒ 32
1.2 ** 3.4 ⇒ 1.858729691979481

%

Binary

x % y

Modulus (Remainder)

9 % 2 ⇒ 1
-9 % 2 ⇒ 1
9 % -2 ⇒ -1
-9 % -2 ⇒ -1
9.9 % 2.1 ⇒ 1.5
-9.9 % 2.1 ⇒ 0.6000000000000001

Python’s integer division returns a floor integer, e.g., -1//2 gives -1.

3.3.4.2. Compound Assignment Operators (+=, -=, *=, /=, //=, **=, %=)#

Each of the arithmetic operators has a corresponding shorthand assignment counterpart, i.e., +=, -=, *=, /=, //=, **= and %=. For example i += 1 is the same as i = i + 1.

The table below shows a summary of the augmented operators for arithmetic operations:

Operator

Description

Sample Expression

Equivalent Expression

+=

Adds the right operand to the left operand and stores the result in the left operand

x += y

x = x + y

-=

Subtracts the right operand from the left operand and stores the result in the left operand

x -= y

x = x - y

*=

Multiplies the right operand with the left operand and stores the result in the left operand

x *= y

x = x * y

/=

Divides the left operand by the right operand and stores the result in the left operand

x /= y

x = x / y

//=

Performs floor division of the left operand by the right operand and stores the result in the left operand

x //= y

x = x // y

%=

Finds the remainder of dividing the left operand by the right operand and stores the result in the left operand

x %= y

x = x % y

**=

Raises the left operand to the power of the right operand and stores the result in the left operand

x **= y

x = x**y

3.3.4.3. Mixed-Type Operations#

For mixed-type operations, e.g., 1 + 2.3 (int + float), the value of the “smaller” type is first promoted to the “bigger” type. It then performs the operation in the “bigger” type and returns the result in the “bigger” type. In Python, int is “smaller” than float, which is “smaller” than complex.

3.3.4.4. Relational (Comparison) Operators (==, !=, <, <=, >, >=, in, not in, is, is not)#

Python supports these relational (comparison) operators that return a bool value of either True or False.

Operator

Mode

Usage

Description

Example

==
!=
<
<=
>
>=

Binary

x == y
x != y
x < y
x <= y
x > y
x >= y

Comparison
Return bool of either True or False

2 == 3
3 != 2
2 < 13
2 <= 2
13 > 2
3 >= 3

in
not in

Binary

x in seq
x not in seq

Check if x is contained in the sequence y
Return bool of either True or False

lst = [1, 2, 3]
x = 1
x in lst ⇒ True
2 in lst ⇒ True

is
is not

Binary

x is y
x is not y

Check if x and y are referencing the same object
Return bool of either True or False

x = 5
if (type(x) is int): …
x = 5.2
if (type(x) is not int): …

Python allows chained comparison of the form n1 < x < n2

>>> x = 8
>>> 1 < x < 10
True
>>> 1 < x and x < 10 # Same as above
True
>>> 10 < x < 20
False
>>> 10 > x > 1
True
>>> not (10 < x < 20)
True

Comparison operators are overloaded to accept sequences (strings, lists, tuples)

>>> 'a' < 'b'
True
>>> 'ab' < 'aa'
False
>>> 'a' < 'b' < 'c'
True
>>> (1, 2, 3) < (1, 2, 4)
True
>>> [1, 2, 3] <= [1, 2, 3]
True

3.3.5. Logical Operators (and, or, not)#

Python supports these logical (boolean) operators, that operate on boolean values.

Operator

Mode

Usage

Description

and

Binary

x and y

Logical AND

or

Binary

x or y

Logical OR

not

Unary

not x

Logical NOT

3.3.5.1. Bitwise Operators#

Python supports these bitwise operators:

Operator

Mode

Usage

Description

Example x=0b10000001
y=0b10001111

&

binary

x & y

bitwise AND

x & y ⇒ 0b10000001

|

binary

x | y

bitwise OR

x | y ⇒ 0b10001111

~

Unary

~x

bitwise NOT (or negate)

~x ⇒ -0b10000010

^

binary

x ^ y

bitwise XOR

x ^ y ⇒ 0b00001110

<<

binary

x << count

bitwise Left-Shift (padded with zeros)

x << 2 ⇒ 0b1000000100

>>

binary

x >> count

bitwise Right-Shift (padded with zeros)

x >> 2 ⇒ 0b100000

Python has augmented bitwise operators:

Operator

Operation

Example

Equivalent

&=

Augmented bitwise AND (conjunction)

x &= y

x = x & y

|=

Augmented bitwise OR (disjunction)

x |= y

x = x | y

^=

Augmented bitwise XOR (exclusive disjunction)

x ^= y

x = x ^ y

>>=

Augmented bitwise right shift

x >>= y

x = x >> y

<<=

Augmented bitwise left shift

x <<= y

x = x << y

3.3.5.2. Operator Precedence in Python#

All operators that Python supports have a precedence compared to other operators. This precedence defines the order in which Python runs the operators in a compound expression.

In an expression, Python runs the operators of highest precedence first. After obtaining those results, Python runs the operators of the next highest precedence. This process continues until the expression is fully evaluated. Any operators of equal precedence are performed in left-to-right order.

Here’s the order of precedence of the Python operators that you’ve seen so far, from highest to lowest:

Operators

Description

**

Exponentiation

+x, -x, ~x

Unary positive, unary negation, bitwise negation

*, /, //, %

Multiplication, division, floor division, modulo

+, -

Addition, subtraction

<<, >>

Bitwise shifts

&

Bitwise AND

^

Bitwise XOR

|

Bitwise OR

==, !=, <, <=, >, >=, is, is not, in, not in

Comparisons, identity, and membership

not

Boolean NOT

and

Boolean AND

or

Boolean OR

Any operators in the same row of the table have equal precedence. You can override the default operator precedence using parentheses to group terms as you do in math. The subexpressions in parentheses will run before expressions that aren’t in parentheses.

3.3.6. Built-in Functions#

Python has many built-in functions that you can use directly without importing anything. These functions cover a wide variety of common programming tasks that include performing math operations, working with built-in data types, processing iterables of data, handling input and output in your programs, working with scopes, and more.

An script to get all of the built-in functions is:

list = dir(__builtin__)
print("No. of builtin functions in current version :", len(list)) 
print(list) 
No. of builtin functions in current version : 161
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BaseExceptionGroup', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EncodingWarning', 'EnvironmentError', 'Exception', 'ExceptionGroup', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '__IPYTHON__', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'aiter', 'all', 'anext', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'display', 'divmod', 'enumerate', 'eval', 'exec', 'execfile', 'filter', 'float', 'format', 'frozenset', 'get_ipython', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr', 'reversed', 'round', 'runfile', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']

A list of the math-related built-in functions in Python is:

Function

Description

abs()

Calculates the absolute value of a number

divmod()

Computes the quotient and remainder of integer division

max()

Finds the largest of the given arguments or items in an iterable

min()

Finds the smallest of the given arguments or items in an iterable

pow()

Raises a number to a power

round()

Rounds a floating-point value

sum()

Sums the values in an iterable

Examples:

>>> abs(-42)
42
>>> abs(42)
42
>>> abs(-42.42)
42.42
>>> abs(42.42)
42.42
>>> abs(complex("-2+3j"))
3.605551275463989
>>> abs(complex("2+3j"))
3.605551275463989

>>> divmod(8, 4)
(2, 0)
>>> divmod(6.5, 3.5)
(1.0, 3.0)
>>> def hh_mm_ss(milliseconds):
...     seconds = round(milliseconds / 1000)
...     minutes, seconds = divmod(seconds, 60)
...     hours, minutes = divmod(minutes, 60)
...     return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
...

>>> hh_mm_ss(10000)
'00:00:10'
>>> hh_mm_ss(68000)
'00:01:08'
>>> hh_mm_ss(3680000)
'01:01:20'

>>> min([1, 2, 3, 4])
1
>>> max([1, 2, 3, 4])
4

>>> min(1, 2, 3, 4)
1
>>> max(1, 2, 3, 4)
4

>>> min([], default=0)
0
>>> max([], default=0)
0

>>> min([-2, 3, 4, -5, 1], key=abs)
1
>>> max([-2, 3, 4, -5, 1], key=abs)
-5

>>> pow(2, 8)
256
>>> 2**8
256

>>> pi = 3.141592653589793
>>> round(pi, 2)
3.14
>>> round(pi, 4)
3.1416
>>> round(pi, 6)
3.141593

>>> round(1.5)
2
>>> round(2.5)   
2
>>> # round() rounds to the closest multiple of 10 to the power minus ndigits. If two multiples are equally close, rounding is done toward the even choice.

>>> sum([])
0
>>> sum([1, 2, 3, 4, 5])
15
>>> sum([1, 2, 3, 4, 5], 100)  # As a positional argument
115
>>> sum([1, 2, 3, 4, 5], start=100)  # As a keyword argument
115
>>> num_lists = [[1, 2, 3], [4, 5, 6]]
>>> sum(num_lists, start=[])
[1, 2, 3, 4, 5, 6]
>>> num_tuples = ((1, 2, 3), (4, 5, 6))
>>> sum(num_tuples, start=())
(1, 2, 3, 4, 5, 6)

Python has several built-in functions that allow you to manipulate basic data types, such as integer and floating-point numbers, strings, and Boolean values. Here’s a summary of the built-in functions that help you process basic data types:

Function

Description

int()

Constructs an integer object from a number or string

bin()

Converts an integer to a binary string

oct()

Converts an integer to an octal string

hex()

Converts an integer to a hexadecimal string

float()

Constructs a floating-point object from a number or string

complex()

Constructs a complex number from arguments

str()

Creates a string object

repr()

Creates a developer-friendly string representation of an object

bool()

Converts an argument to a Boolean value

ord()

Looks up the integer code point of a character

chr()

Looks up the character for the given integer code point

bytes()

Creates a bytes object (similar to bytearray, but immutable)

bytearray()

Creates an object of the bytearray class

Here are some examples of using this functions:

>>> int()
0
>>> int(42.42)
42
>>> int("42")
42
>>> int("42.42")
Traceback (most recent call last):
    ...
ValueError: invalid literal for int() with base 10: '42.42'

>>> int("0b10", base=2)
2
>>> int("0x10", base=16)
16

>>> bin(42)
'0b101010'
>>> oct(42)
'0o52'
>>> hex(42)
'0x2a'

>>> float()
0.0
>>> float(42)
42.0
>>> float("42")
42.0
>>> float("3.14")
3.14

>>> complex(3, 6)
(3+6j)
>>> complex(1, 0)
(1+0j)
>>> complex(0, 1)
1j
>>> complex(3.14, -2.75)
(3.14-2.75j)

>>> str(42)
'42'
>>> str(3.14)
'3.14'
>>> str([1, 2, 3])
'[1, 2, 3]'
>>> str({"one": 1, "two": 2, "three": 3})
"{'one': 1, 'two': 2, 'three': 3}"
>>> str({"A", "B", "C"})
"{'B', 'C', 'A'}"

>>> repr(42)
'42'
>>> repr(3.14)
'3.14'

>>> bool()
False
>>> bool(0)
False
>>> bool(42)
True
>>> bool(0.0)
False
>>> bool(3.14)
True
>>> bool("")
False
>>> bool("Hello")
True
>>> bool([])
False
>>> bool([1, 2, 3])
True

>>> ord("A")
65
>>> ord("Z")
90
>>> ord("x")
120
>>> ord("ñ")
241
>>> ord("&")
38

>>> chr(65)
'A'
>>> chr(90)
'Z'
>>> chr(120)
'x'
>>> chr(241)
'ñ'
>>> chr(38)
'&'

>>> bytes()
b''
>>> bytes(b"Using ASCII characters or bytes \xc3\xb1")
b'Using ASCII characters or bytes \xc3\xb1'
>>> bytes("Using non-ASCII characters: ñ Ł", encoding="utf-8")
b'Using non-ASCII characters: \xc3\xb1 \xc5\x81'
>>> bytearray()
bytearray(b'')
>>> bytearray(b"Using ASCII characters or bytes \xc3\xb1")
bytearray(b'Using ASCII characters or bytes \xc3\xb1')
>>> bytearray("Using non-ASCII characters: ñ Ł", encoding="utf-8")
bytearray(b'Using non-ASCII characters: \xc3\xb1 \xc5\x81')

3.3.7. String#

In Python, strings can be delimited by a pair of single-quotes (’…’) or double-quotes (”…”). Python also supports multi-line strings via triple-single-quotes (‘’’…’’’) or triple-double-quotes (“””…”””).

To place a single-quote (’) inside a single-quoted string, you need to use escape sequence ‘. Similarly, to place a double-quote (”) inside a double-quoted string, use “. There is no need for escape sequence to place a single-quote inside a double-quoted string; or a double-quote inside a single-quoted string.

A triple-single-quoted or triple-double-quoted string can span multiple lines. There is no need for escape sequence to place a single/double quote inside a triple-quoted string. Triple-quoted strings are useful for multi-line documentation, HTML and other codes.

Python uses Unicode character set to support internationalization (i18n). ASCII strings are represented as byte strings, prefixed with b, e.g., b’ABC’.

Strings are immutable, i.e., their contents cannot be modified. String functions such as upper(), replace() returns a new string object instead of modifying the string under operation.

s1 = 'apple'
print(s1)

s2 = "orange"
print(s2)

s3 = "'orange'"   # Escape sequence not required
print(s3)

s3 ="\"orange\""  # Escape sequence needed
print(s3)

# A triple-single/double-quoted string can span multiple lines
s4 = """testing
12345"""
print(s4)
apple
orange
'orange'
"orange"
testing
12345

3.3.7.1. Escape Sequences for Characters (\code)#

You need to use escape sequences (a back-slash + a code) for:

  • Special non-printable characters, such as tab (\t), newline (\n), carriage return (\r)

  • Resolve ambiguity, such as “ (for “ inside double-quoted string), ‘ (for ‘ inside single-quoted string), \ (for ).

  • \xhh for character in hex value and \ooo for octal value

  • \uxxxx for 4-hex-digit (16-bit) Unicode character and \Uxxxxxxxx for 8-hex-digit (32-bit) Unicode character.

3.3.7.2. Built-in Functions and Operators for Strings#

You can operate on strings using:

  • built-in functions such as len();

  • operators such as in (contains), + (concatenation), * (repetition), indexing [i] and [-i], and slicing [m:n:step].

These functions and operators are applicable to all sequence data types including string, list, and tuple (see later).

Function / Operator

Usage

Description

Examples s = ‘Hello’

len()

len(str)

Length

len(s) ⇒ 5

in

substr in str

Contain? Return bool of either True or False

‘ell’ in s ⇒ True
‘he’ in s ⇒ False

+
+=

str + str1
str += str1

Concatenation

s + ‘!’ ⇒ ‘Hello!’

*
*=

str * count
str *= count

Repetition

s * 2 ⇒ ‘HelloHello’

[i]
[-i]

str[i]
tr[-i]

Indexing to get a character. The front index begins at 0; back index begins at -1 (=len(str)-1).

s[1] ⇒ ‘e’
s[-4] ⇒ ‘e’

[m:n:step]
[m:n]
[m:]
[:n]
[:]

str[m:n:step]
str[m:n]
str[m:]
str[:n]
str[:]

Slicing to get a substring.
From index m (included) to n (excluded) with step size.
The defaults are: m=0, n=-1, step=1.

s[1:3] ⇒ ‘el’
s[1:-2] ⇒ ‘el’
s[3:] ⇒ ‘lo’
s[:-2] ⇒ ‘Hel’
s[:] ⇒ ‘Hello’
s[0:5:2] ⇒ ‘Hlo’

Examples:

>>> s = "Hello, world"   # Assign a string literal to the variable s
>>> type(s)              # Get data type of s
<class 'str'>
>>> len(s)       # Length
12
>>> 'ello' in s  # The in operator
True

# Indexing
>>> s[0]       # Get character at index 0; index begins at 0
'H'
>>> s[1]
'e'
>>> s[-1]      # Get Last character, same as s[len(s) - 1]
'd'
>>> s[-2]      # 2nd last character
'l'

# Slicing
>>> s[1:3]     # Substring from index 1 (included) to 3 (excluded)
'el'
>>> s[1:-1]
'ello, worl'
>>> s[:4]      # Same as s[0:4], from the beginning
'Hell'
>>> s[4:]      # Same as s[4:-1], till the end
'o, world'
>>> s[:]       # Entire string; same as s[0:len(s)]
'Hello, world'

# Concatenation (+) and Repetition (*)
>>> s = s + " again"  # Concatenate two strings
>>> s
'Hello, world again'
>>> s * 3        # Repeat 3 times
'Hello, world againHello, world againHello, world again'

# str can only concatenate with str, not with int and other types
>>> s = 'hello'
>>> print('The length of \"' + s + '\" is ' + len(s))  # len() is int
TypeError: can only concatenate str (not "int") to str
>>> print('The length of \"' + s + '\" is ' + str(len(s)))
The length of "hello" is 5

# String is immutable
>>> s[0] = 'a'
TypeError: 'str' object does not support item assignment

Python does not have a dedicated character data type. A character is simply a string of length 1. You can use the indexing operator to extract individual character from a string, as shown in the above example; or process individual character using for-in loop (to be discussed later).

The built-in functions ord() and chr() operate on character, e.g.,

# ord(c) returns the integer ordinal (Unicode) of a one-character string
>>> ord('A')
65
>>> ord('水')
27700

# chr(i) returns a one-character string with Unicode ordinal i; 0 <= i <= 0x10ffff.
>>> chr(65)
'A'
>>> chr(27700)
'水'

3.3.7.3. String-Specific Member Functions#

Python supports strings via a built-in class called str (to see in the Object-Oriented Programming chapter). The str class provides many member functions. Since string is immutable, most of these functions return a new string. The commonly-used member functions are as follows, supposing that s is a str object:

  • str.strip(), str.rstrip(), str.lstrip(): strip the leading and trailing whitespaces, the right (trailing) whitespaces; and the left (leading) whitespaces, respectively.

  • str.upper(), str.lower(): Return a uppercase/lowercase counterpart, respectively.

  • str.isupper(), str.islower(): Check if the string is uppercase/lowercase, respectively.

  • str.find(key_str):

  • str.index(key_str):

  • str.startswith(key_str):

  • str.endswith(key_str):

  • str.split(delimiter_str), delimiter_str.join(strings_list):

Examples:

>>> dir(str)      # List all attributes of the class str
[..., 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs',
'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal',
'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle',
'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace',
'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines',
'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

>>> s = 'Hello, world'
>>> type(s)
<class 'str'>

>>> dir(s)         # List all attributes of the object s
.......
>>> help(s.find)   # Show the documentation of member function find
.......
>>> s.find('ll')   # Find the beginning index of the substring
2
>>> s.find('app')  # find() returns -1 if not found
-1

>>> s.index('ll')  # index() is the same as find(), but raise ValueError if not found
2
>>> s.index('app')
ValueError: substring not found

>>> s.startswith('Hell')
True
>>> s.endswith('world')
True
>>> s.replace('ll', 'xxx')
'Hexxxo, world'
>>> s.isupper()
False
>>> s.upper()
'HELLO, WORLD'

>>> s.split(', ')    # Split into a list with the given delimiter
['Hello', 'world']
>>> ', '.join(['hello', 'world', '123'])  # Join all strings in the list using the delimiter
'hello, world, 123'
 
>>> s = '  testing 12345   '
>>> s.strip()        # Strip leading and trailing whitespaces
'testing 12345'
>>> s.rstrip()       # Strip trailing (right) whitespaces
'  testing 12345'
>>> s.lstrip()       # Strip leading (left) whitespaces
'testing 12345   '

# List all the whitespace characters - in module string, attribute whitespace
>>> import string
>>> string.whitespace   # All whitespace characters
' \t\n\r\x0b\x0c'
>>> string.digits       # All digit characters
'0123456789'
>>> string.hexdigits    # All hexadecimal digit characters
'0123456789abcdefABCDEF'

3.3.7.4. String Formatting 1: Using str.format() function#

There are a few ways to produce a formatted string for output. One style
is the str’s format() member function with {} as place-holders (called format fields). For examples,

# Replace format fields {} by arguments in format() in the SAME order
>>> '|{}|{}|more|'.format('Hello', 'world')
'|Hello|world|more|'

# You can use 'positional' index in the form of {0}, {1}, ...
>>> '|{0}|{1}|more|'.format('Hello', 'world')
'|Hello|world|more|'
>>> '|{1}|{0}|more|'.format('Hello', 'world')
'|world|Hello|more|'

# You can use 'keyword' inside {}
>>> '|{greeting}|{name}|'.format(greeting='Hello', name='Peter')
'|Hello|Peter|'

# Mixing 'positional' and 'keyword'
>>> '|{0}|{name}|more|'.format('Hello', name='Peter')
'|Hello|Peter|more|'
>>> '|{}|{name}|more|'.format('Hello', name='Peter')
'|Hello|Peter|more|'

# You can specify field-width with :n,
#  alignment (< for left-align, > for right-align, ^ for center-align) and
#  padding (or fill) character.
>>> '|{1:8}|{0:7}|'.format('Hello', 'Peter')   # Set field-width
'|Peter   |Hello  |'      # Default left-aligned
>>> '|{1:8}|{0:>7}|{2:-<10}|'.format('Hello', 'Peter', 'again')  # Set alignment and padding
'|Peter   |  Hello|again-----|'    # > (right align), < (left align), - (fill char)
>>> '|{greeting:8}|{name:7}|'.format(name='Peter', greeting='Hi')
'|Hi      |Peter  |'

# Format int using ':d' or ':nd'
# Format float using ':f' or ':n.mf'
>>> '|{0:.3f}|{1:6.2f}|{2:4d}|'.format(1.2, 3.456, 78)
'|1.200|  3.46|  78|'
# With keywords
>>> '|{a:.3f}|{b:6.2f}|{c:4d}|'.format(a=1.2, b=3.456, c=78)
'|1.200|  3.46|  78|'

When you pass lists, tuples, or dictionaries (to be discussed later) as arguments into the format() function, you can reference the sequence’s elements in the format fields with [index]. For examples,

# list and tuple
>>> tup = ('a', 11, 11.11)
>>> lst = ['b', 22, 22.22]
>>> '|{0[2]}|{0[1]}|{0[0]}|'.format(tup)  # {0} matches tup, indexed via []
'|11.11|11|a|'
>>> '|{0[2]}|{0[1]}|{0[0]}|{1[2]}|{1[1]}|{1[0]}|'.format(tup, lst)  # {0} matches tup, {1} matches lst
'|11.11|11|a|22.22|22|b|'

# dictionary
>>> dict = {'c': 33, 'cc': 33.33}
>>> '|{0[cc]}|{0[c]}|'.format(dict)
'|33.33|33|'
>>> '|{cc}|{c}|'.format(**dict)  # As keywords via **  
'|33.33|33|'

3.3.7.5. String Formatting 2: Using str.rjust(n), str.ljust(n), str.center(n), str.zfill(n)#

You can also use str’s member functions like str.rjust(n) (where n is the field-width), str.ljust(n), str.center(n), str.zfill(n) to format a string. For example,

# Setting field width and alignment
>>> '123'.rjust(5)
'  123'
>>> '123'.ljust(5)
'123  '
>>> '123'.center(5)
' 123 '
>>> '123'.zfill(5)  # Pad (Fill) with leading zeros
'00123'

# Floats
>>> '1.2'.rjust(5)
'  1.2'
>>> '-1.2'.zfill(6)
'-001.2'

3.3.7.6. String Formatting 3: Using % operator#

The old style is to use the % operator, with C-like printf() format specifiers. For examples,

# %s for str
# %ns for str with field-width of n (default right-align)
# %-ns for left-align
>>> '|%s|%8s|%-8s|more|' % ('Hello', 'world', 'again')
'|Hello|   world|again   |more|'

# %d for int
# %nd for int with field-width of n
# %f for float
# %n.mf for float with field-with of n and m decimal digits
>>> '|%d|%4d|%6.2f|' % (11, 222, 33.333)   
'|11| 222| 33.33|'

3.3.7.7. Conversion between String and Number: int(), float() and str()#

You can use built-in functions int() and float() to parse a “numeric” string to an integer or a float; and str() to convert a number to a string. For example,

# Convert string to int
>>> s = '12345'
>>> s
'12345'
>>> type(s)
<class 'str'>
>>> i = int(s)
>>> i
12345
>>> type(i)
<class 'int'>

# Convert string to float
>>> s = '55.66'
>>> s
'55.66'
>>> f = float(s)
>>> f
55.66
>>> type(f)
<class 'float'>
>>> int(s)
ValueError: invalid literal for int() with base 10: '55.66'

# Convert number to string
>>> i = 123
>>> s = str(i)
>>> s
'123'
>>> type(s)
<class 'str'>
'123'

3.3.8. The None Value#

Python provides a special value called None (note the spelling in initial-capitalized), which can be used to initialize an object (see OOP later). For example,

>>> x = None
>>> type(x)   # Get type
<class 'NoneType'>
>>> print(x)
None

# Use 'is' and 'is not' to check for 'None' value.
>>> print(x is None)
True
>>> print(x is not None)
False

3.3.9. Data Structure: List, Tuple, Dictionary and Set#

3.3.9.1. List [v1, v2,…]#

Python has a powerful built-in dynamic array called list.

  • A list is enclosed by square brackets [].

  • A list can contain items of different types. It is because Python associates types to objects, not variables.

  • A list grows and shrinks in size automatically (dynamically). You do not have to specify its size during initialization.

  • A list is mutable. You can update its contents.

Built-in Functions and Operators for list

A list, like string, is a sequence. Hence, you can operate lists using:

  • built-in sequence functions such as len().

  • built-in sequence functions for list of numbers such as max(), min(), and sum().

  • built-in operators such as in (contains), + (concatenation) and * (repetition), del, [i] (indexing), and [m,n,step] (slicing).

Notes:

  • You can index the items from the front with positive index, or from the back with negative index. E.g., if lst is a list, lst[0] and lst[1] refer to its first and second items; lst[-1] and lst[-2] refer to the last and second-to-last items.

  • You can also refer to a sub-list (or slice) using slice notation lst[m:n:step] (from index m (included) to index n (excluded) with step size).

Operator

Usage

Description

Examples
lst = [8, 9, 6, 2]

in not in

x in lst
x not in lst

Contain? Return bool of either True or False

9 in lst ⇒ True
5 in lst ⇒ False

+
+=

lst + lst1
lst += lst1

Concatenation

lst + [5, 2]
⇒ [8, 9, 6, 2, 5, 2]

*
*=

lst * count
lst *= count

Repetition

lst * 2
⇒ [8, 9, 6, 2, 8, 9, 6, 2]

[i]
[-i]

lst[i]
lst[-i]

Indexing to get an item.
Front index begins at 0;
back index begins at -1 (or len(lst)-1).

lst[1] ⇒ 9
lst[-2] ⇒ 6

[m:n:step]
[m:n]
[m:]
[:n]
[:]

lst[m:n:step]
lst[m:n]
lst[m:]
lst[:n]
lst[:]

Slicing to get a sublist.
From index m (included) to n (excluded) with step size.
The defaults are: m is 0, n is len(lst)-1.

lst[1:3] ⇒ [9, 6]
lst[1:-2] ⇒ [9]
lst[3:] ⇒ [2]
lst[:-2] ⇒ [8, 9]
lst[:] ⇒ [8, 9, 6, 2]
lst[0:4:2] ⇒ [8, 6]
newlst = lst[:] ⇒ Copy
lst[4:] = [1, 2] ⇒ Extend

del

del lst[i]
del lst[m:n]
del lst[m:n:step]

Delete one or more items

del lst[1] ⇒ [8, 6, 2]
del lst[1:] ⇒ [8]
del lst[:] ⇒ [ ] (Clear)

Function

Usage

Description

Examples lst = [8, 9, 6, 2]

len()

len(lst)

Length

len(lst) ⇒ 4

max()
min()

max(lst)
min(lst)

Maximum value
minimum value

max(lst) ⇒ 9
min(lst) ⇒ 2

sum()

sum(lst)

Sum (for number lists only)

sum(lst) ⇒ 16

list, unlike string, is mutable. You can insert, remove and modify its items.

For examples,

>>> lst = [123, 4.5, 'hello', True, 6+7j]  # A list can contains items of different types
>>> lst
[123, 4.5, 'hello', True, (6+7j)]
>>> len(lst)   # Length
5
>>> type(lst)
<class 'list'>

# "Indexing" to get a specific element
>>> lst[0]
123
>>> lst[-1]   # Negative index from the end
(6+7j)
# Assignment with indexing
>>> lst[2] = 'world'   # Assign a value to this element
>>> lst
[123, 4.5, 'world', True, (6+7j)]

# "Slicing" to get a sub-list
>>> lst[0:2]
[123, 4.5]
>>> lst[:3]   # Same as lst[0:3]
[123, 4.5, 'world']
>>> lst[2:]   # Same as lst[2: len(lst)]
['world', True, (6+7j)]
>>> lst[::2]   # Step size of 2 for alternate elements
[123, 'world']
>>> lst[::-1]  # Use negative index to reverse the list
['world', 4.5, 123]
# Assignment with Slicing
>>> lst[2:4]
['world', True]     # 2-element sub-list
>>> lst[2:4] = 0    # Cannot assign a scalar to slice
TypeError: can only assign an iterable
>>> lst[2:4] = [1, 2, 'a', 'b']   # But can assign a list of any length
>>> lst
[123, 4.5, 1, 2, 'a', 'b', (6+7j)]
>>> lst[1:3] = []   # Remove a sub-list
>>> lst
[123, 2, 'a', 'b', (6+7j)]
>>> lst[::2] = ['x', 'y', 'z']   # Can use step size
>>> lst
['x', 2, 'y', 'b', 'z']
>>> lst[::2] = [1, 2, 3, 4]      # But need to replace by a list of the same length
ValueError: attempt to assign sequence of size 4 to extended slice of size 3

# Operators: in, +, *, del
>>> 'x' in lst
True
>>> 'a' in lst
False
>>> lst + [6, 7, 8]   # Concatenation
['x', 2, 'y', 'b', 'z', 6, 7, 8]
>>> lst * 3           # Repetition
['x', 2, 'y', 'b', 'z', 'x', 2, 'y', 'b', 'z', 'x', 2, 'y', 'b', 'z']
>>> del lst[1]        # Remove an element via indexing
>>> lst
['x', 'y', 'b', 'z']
>>> del lst[::2]      # Remove a slice
>>> lst
['y', 'z']

# List can be nested
>>> lst = [123, 4.5, ['a', 'b', 'c']]
>>> lst
[123, 4.5, ['a', 'b', 'c']]
>>> lst[2]
['a', 'b', 'c']

# Appending Items to a list:

>>> lst = [123, 'world']
>>> lst[2]     # Python performs index bound check
IndexError: list index out of range
>>> lst[len(lst)] = 4.5  # Cannot append using indexing
IndexError: list assignment index out of range
>>> lst[len(lst):] = [4.5]  # Can append using slicing
>>> lst
[123, 'world', 4.5]
>>> lst[len(lst):] = [6, 7, 8]  # Append a list using slicing
>>> lst
[123, 'world', 4.5, 6, 7, 8]
>>> lst.append('nine')  # append() one item
>>> lst
[123, 'world', 4.5, 6, 7, 8, 'nine']
>>> lst.extend(['a', 'b'])  # extend() takes a list
>>> lst
[123, 'world', 4.5, 6, 7, 8, 'nine', 'a', 'b']

>>> lst + ['c']  # '+' returns a new list; while slicing-assignment modifies the list and returns None
[123, 'world', 4.5, 6, 7, 8, 'nine', 'a', 'b', 'c']
>>> lst  # No change
[123, 'world', 4.5, 6, 7, 8, 'nine', 'a', 'b']

# Copying a list

>>> l1 = [123, 4.5, 'hello']
>>> l2 = l1[:]   # Make a copy via slicing
>>> l2
[123, 4.5, 'hello']
>>> l2[0] = 8    # Modify new copy
>>> l2
[8, 4.5, 'hello']
>>> l1           # No change in original
[123, 4.5, 'hello']

>>> l3 = l1.copy()   # Make a copy via copy() function, same as above

# Contrast with direct assignment
>>> l4 = l1    # Direct assignment (of reference)
>>> l4
[123, 4.5, 'hello']
>>> l4[0] = 8  # Modify new copy
>>> l4
[8, 4.5, 'hello']
>>> l1         # Original also changes
[8, 4.5, 'hello']

list-Specific Member Functions

The list class provides many member functions. Suppose lst is a list object:

  • lst.index(item): return the index of the first occurrence of item; or error.

  • lst.append(item): append the given item behind the lst and return None; same as slicing operation lst[len(lst):] = [item].

  • lst.extend(lst1): append the given list lst1 behind the lst and return None; same as slicing operation lst[len(lst):] = lst1.

  • lst.insert(index, item): insert the given item before the index and return None. Hence, lst.insert(0, item) inserts before the first item of the lst; - - lst.insert(len(lst), item) inserts at the end of the lst which is the same as lst.append(item).

  • lst.remove(item): remove the first occurrence of item from the lst and return None; or error.

  • lst.pop(): remove and return the last item of the lst.

  • lst.pop(index): remove and return the indexed item of the lst.

  • lst.clear(): remove all the items from the lst and return None; same as operator del lst[:].

  • lst.count(item): return the occurrences of item.

  • lst.reverse(): reverse the lst in place and return None.

  • lst.sort(): sort the lst in place and return None.

  • lst.copy(): return a copy of lst; same as lst[:].

Recall that list is mutable (unlike string which is immutable). These functions modify the list directly. For examples,

>>> lst = [123, 4.5, 'hello', [6, 7, 8]]  # list can also contain list
>>> lst
[123, 4.5, 'hello', [6, 7, 8]]
>>> type(lst)  # Show type
<class 'list'>
>>> dir(lst)   # Show all the attributes of the lst object

>>> len(lst)
4
>>> lst.append('apple')  # Append item at the back
>>> lst
[123, 4.5, 'hello', [6, 7, 8], 'apple']
>>> len(lst)
5
>>> lst.pop(1)     # Retrieve and remove item at index
4.5
>>> lst
[123, 'hello', [6, 7, 8], 'apple']
>>> len(lst)
4
>>> lst.insert(2, 55.66)  # Insert item before the index
>>> lst
[123, 'hello', 55.66, [6, 7, 8], 'apple']
>>> del lst[3:]         # Delete the slice (del is an operator , not function)
>>> lst
[123, 'hello', 55.66]
>>> lst.append(55.66)   # A list can contain duplicate values
>>> lst
[123, 'hello', 55.66, 55.66]
>>> lst.remove(55.66)   # Remove the first item of given value
>>> lst
[123, 'hello', 55.66]
>>> lst.reverse()       # Reverse the list in place
>>> lst
[55.66, 'hello', 123]
 
# Searching and Sorting
>>> lst2 = [5, 8, 2, 4, 1]
>>> lst2.sort()     # In-place sorting
>>> lst2
[1, 2, 4, 5, 8]
>>> lst2.index(5)   # Get the index of the given item
3
>>> lst2.index(9)
......
ValueError: 9 is not in list
>>> lst2.append(1)
>>> lst2
[1, 2, 4, 5, 8, 1]
>>> lst2.count(1)   # Count the occurrences of the given item
2
>>> lst2.count(9)
0
>>> sorted(lst2)    # Built-in function that returns a sorted list
[1, 1, 2, 4, 5, 8]
>>> lst2
[1, 2, 4, 5, 8, 1]  # Not modified

Using list as a last-in-first-out Stack

To use a list as a last-in-first-out (LIFO) stack, use append(item) to add an item to the top-of-stack (TOS) and pop() to remove the item from the TOS.

Using list as a first-in-first-out Queue

To use a list as a first-in-first-out (FIFO) queue, use append(item) to add an item to the end of the queue and pop(0) to remove the first item of the queue.

However, pop(0) is slow! The standard library provide a class collections.deque to efficiently implement deque with fast appends and pops from both ends.

Consider the statement ϵ_values = [], which creates an empty list. Lists are a native Python data structure used to group a collection of objects.

Items in lists are ordered, and duplicates are allowed in lists.

For example, try

x = [10, 'foo', False]
type(x)
list

The first element of x is an integer, the next is a string, and the third is a Boolean value.

When adding a value to a list, we can use the syntax list_name.append(some_value)

x
[10, 'foo', False]
x.append(2.5)
x
[10, 'foo', False, 2.5]

Here append() is what’s called a method, which is a function “attached to” an object—in this case, the list x.

  • Python objects such as lists, strings, etc. all have methods that are used to manipulate data contained in the object.

  • String objects have string methods, list objects have list methods, etc.

Another useful list method is pop()

x
[10, 'foo', False, 2.5]
x.pop()
2.5
x
[10, 'foo', False]

Lists in Python are zero-based, so the first element is referenced by x[0]

x[0]   # first element of x
10
x[1]   # second element of x
'foo'

3.3.9.2. Tuple (v1, v2,…)#

Tuple is similar to list except that it is immutable (just like string). Hence, tuple is more efficient than list. A tuple consists of items separated by commas, enclosed in parentheses ().

>>> tup = (123, 4.5, 'hello')  # A tuple can contain different types
>>> tup
(123, 4.5, 'hello')
>>> tup[1]           # Indexing to get an item
4.5
>>> tup[1:3]         # Slicing to get a sub-tuple
(4.5, 'hello')
>>> tup[1] = 9       # Tuple, unlike list, is immutable
TypeError: 'tuple' object does not support item assignment
>>> type(tup)
<class 'tuple'>
>>> lst = list(tup)  # Convert to list
>>> lst
[123, 4.5, 'hello']
>>> type(lst)
<class 'list'>

# An one-item tuple needs a comma to differentiate from parentheses:

>>> tup = (5,)  # An one-item tuple needs a comma
>>> tup
(5,)
>>> x = (5)     # Treated as parentheses without comma
>>> x
5

# The parentheses are actually optional, but recommended for readability. 
# Nevertheless, the commas are mandatory. For example,

>>> tup = 123, 4.5, 'hello'
>>> tup
(123, 4.5, 'hello')
>>> tup2 = 88,  # one-item tuple needs a trailing commas 
>>> tup2
(88,)

# However, we can use empty parentheses to create an empty tuple
# Empty tuples are quite useless, as tuples are immutable.
>>> tup3 = ()
>>> tup3
()
>>> len(tup3)
0

You can operate on tuples using (supposing that tup is a tuple):

  • built-in functions such as len(tup);

  • built-in functions for tuple of numbers such as max(tup), min(tup) and sum(tup);

  • operators such as in, + and *

  • tuple’s member functions such as tup.count(item), tup.index(item), etc.

Conversion between List and Tuple

You can covert a list to a tuple using built-in function tuple() and a tuple to a list using list(). For examples,

>>> tuple([1, 2, 3, 1])  # Convert a list to a tuple
(1, 2, 3, 1)
>>> list((1, 2, 3, 1))   # Convert a tuple to a list
[1, 2, 3, 1]

tuples, are “immutable” lists

x = ('a', 'b')  # Parentheses instead of the square brackets
x = 'a', 'b'    # Or no brackets --- the meaning is identical
x
('a', 'b')
type(x)
tuple

In Python, an object is called immutable if, once created, the object cannot be changed.

Conversely, an object is mutable if it can still be altered after creation.

Python lists are mutable

x = [1, 2]
x[0] = 10
x
[10, 2]

But tuples are not

x = (1, 2)
x[0] = 10
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[18], line 2
      1 x = (1, 2)
----> 2 x[0] = 10

TypeError: 'tuple' object does not support item assignment

We’ll say more about the role of mutable and immutable data a bit later.

Tuples (and lists) can be “unpacked” as follows

integers = (10, 20, 30)
x, y, z = integers
x
10
y
20

Tuple unpacking is convenient and is used it often.

3.3.9.3. Slice Notation#

To access multiple elements of a sequence (a list, a tuple or a string), you can use Python’s slice notation.

For example,

a = ["a", "b", "c", "d", "e"]
a[1:]
['b', 'c', 'd', 'e']
a[1:3]
['b', 'c']

The general rule is that a[m:n] returns n - m elements, starting at a[m].

Negative numbers are also permissible

a[-2:]  # Last two elements of the list
['d', 'e']

You can also use the format [start:end:step] to specify the step

a[::2]
['a', 'c', 'e']

Using a negative step, you can return the sequence in a reversed order

a[-2::-1] # Walk backwards from the second last element to the first element
['d', 'c', 'b', 'a']

The same slice notation works on tuples and strings

s = 'foobar'
s[-3:]  # Select the last three elements
'bar'

3.3.9.4. Dictionary. (Associative Array) {k1:v1, k2:v2,…}#

Python’s built-in dictionary type supports key-value pairs (also known as name-value pairs,associative array, or mappings).

  • A dictionary is enclosed by a pair of curly braces {}. The key and value are separated by a colon (:), in the form of {k1:v1, k2:v2, …}

  • Unlike list and tuple, which index items using an integer index 0, 1, 2, 3,…, dictionary can be indexed using any key type, including number, string or other types.

  • Dictionary is mutable.

>>> dct = {'name':'Peter', 'gender':'male', 'age':21}
>>> dct
{'age': 21, 'name': 'Peter', 'gender': 'male'}
>>> dct['name']       # Get value via key
'Peter'
>>> dct['age'] = 22   # Re-assign a value
>>> dct
{'age': 22, 'name': 'Peter', 'gender': 'male'}
>>> len(dct)
3
>>> dct['email'] = 'peter@nowhere.com'   # Add new item
>>> dct
{'name': 'Peter', 'age': 22, 'email': 'peter@nowhere.com', 'gender': 'male'}
>>> type(dct)
<class 'dict'>

# Use dict() built-in function to create a dictionary
>>> dct2 = dict([('a', 1), ('c', 3), ('b', 2)])  # Convert a list of 2-item tuples into a dictionary
>>> dct2
{'b': 2, 'c': 3, 'a': 1}

Dictionary-Specific Member Functions

The dict class has many member methods. The commonly-used are follows (suppose that dct is a dict object):

  • dct.has_key()

  • dct.items(), dct.keys(), dct.values()

  • dct.clear()

  • dct.copy()

  • dct.get()

  • dct.update(dct2) merge the given dictionary dct2 into dct. Override the value if key exists, else, add new key-value.

  • dct.pop()

For Examples,

>>> dct = {'name':'Peter', 'age':22, 'gender':'male'}
>>> dct
{'gender': 'male', 'name': 'Peter', 'age': 22}

>>> type(dct)  # Show type
<class 'dict'>
>>> dir(dct)   # Show all attributes of dct object
......

>>> list(dct.keys())       # Get all the keys as a list
['gender', 'name', 'age']
>>> list(dct.values())     # Get all the values as a list
['male', 'Peter', 22]
>>> list(dct.items())      # Get key-value as tuples
[('gender', 'male'), ('name', 'Peter'), ('age', 22)]

# You can also use get() to retrieve the value of a given key
>>> dct.get('age', 'not such key')  # Retrieve item
22
>>> dct.get('height', 'not such key')
'not such key'
>>> dct['height']
KeyError: 'height'
    # Indexing an invalid key raises KeyError, while get() could gracefully handle invalid key

>>> del dct['age']   # Delete (Remove) an item of the given key
>>> dct
{'gender': 'male', 'name': 'Peter'}

>>> 'name' in dct
True

>>> dct.update({'height':180, 'weight':75})  # Merge the given dictionary
>>> dct
{'height': 180, 'gender': 'male', 'name': 'Peter', 'weight': 75}

>>> dct.pop('gender')  # Remove and return the item with the given key 
'male'
>>> dct
{'name': 'Peter', 'weight': 75, 'height': 180}
>>> dct.pop('no_such_key')   # Raise KeyError if key not found
KeyError: 'no_such_key'
>>> dct.pop('no_such_key', 'not found')   # Provide a default if key does not exist
'not found'

Dictionaries are much like lists, except that the items are named instead of numbered

d = {'name': 'Frodo', 'age': 33}
type(d)
dict
d['age']
33

The names 'name' and 'age' are called the keys.

The objects that the keys are mapped to ('Frodo' and 33) are called the values.

3.3.9.5. Set {k1, k2,…}#

A set is an unordered, non-duplicate collection of objects. A set is delimited by curly braces { }, just like dictionary. You can think of a set as a collection of dictionary keys without associated values. Sets are mutable.

For example,

>>> st = {123, 4.5, 'hello', 123, 'Hello'}
>>> st         # Duplicate removed and ordering may change
{'Hello', 'hello', 123, 4.5}
>>> 123 in st  # Test membership
True
>>> 88 in st
False

# Use the built-in function set() to create a set.
>>> st2 = set([2, 1, 3, 1, 3, 2])  # Convert a list to a set. Duplicate removed and unordered.
>>> st2
{1, 2, 3}
>>> st3 = set('hellllo')  # Convert a string to a character set.
>>> st3
{'o', 'h', 'e', 'l'}

Set-Specific Operators (&, !, -, ^)

Python supports set operators & (intersection), | (union), - (difference) and ^ (exclusive-or). For example,

>>> st1 = {'a', 'e', 'i', 'o', 'u'}
>>> st1
{'e', 'o', 'u', 'a', 'i'}
>>> st2 = set('hello')  # Convert a string to a character set
>>> st2
{'o', 'l', 'e', 'h'}
>>> st1 & st2   # Set intersection
{'o', 'e'}
>>> st1 | st2   # Set union
{'o', 'l', 'h', 'i', 'e', 'a', 'u'}
>>> st1 - st2   # Set difference
{'i', 'u', 'a'}
>>> st1 ^ st2   # Set exclusive-or
{'h', 'i', 'u', 'a', 'l'}

Sets are unordered collections without duplicates, and set methods provide the usual set-theoretic operations

s1 = {'a', 'b'}
type(s1)
set
s2 = {'b', 'c'}
s1.issubset(s2)
False
s1.intersection(s2)
{'b'}

The set() function creates sets from sequences

s3 = set(('foo', 'bar', 'foo'))
s3
{'bar', 'foo'}

3.3.9.6. Sequence Types: list, tuple, str#

list, tuple, and str are parts of the sequence types. list is mutable, while tuple and str are immutable. They share the common sequence’s built-in operators and built-in functions, as follows:

Opr / Func

Usage

Description

in
not in

x in seq x not in seq

Contain? Return bool of either True or False

+

seq + seq1

Concatenation

*

seq * count

Repetition (Same as: seq + seq + …)

[i]
[-i]

seq[i]
seq[-i]

Indexing to get an item.
Front index begins at 0; back index begins at -1 (or len(seq)-1).

[m:n:step]
[m:n]
[m:]
[:n]
[:]

seq[m:n:step]
seq[m:n]
seq[m:]
seq[:n}
seq[:]

Slicing to get a sub-sequence.
From index m (included) to n (excluded) with step size.
The defaults are: m is 0, n is len(seq)-1.

len()
min()
max()

len(seq)
min(seq)
max(seq)

Return the Length, minimum and maximum of the sequence

seq.index()

seq.index(x)
seq.index(x, i)
seq.index(x, i, j)

Return the index of x in the sequence, or raise ValueError.
Search from i (included) to j (excluded)

seq.count()

seq.count(x)

Returns the count of x in the sequence

For mutable sequences (list), the following built-in operators and built-in functions (func(seq)) and member functions (seq.func(*args)) are supported:

Opr / Func

Usage

Description

[]

seq[i] = x
seq[m:n] = []
seq[:] = []
seq[m:n] = seq1
seq[m:n:step] = seq1

Replace one item
Remove one or more items
Remove all items
Replace more items with a sequence of the same size

+=

seq += seq1

Extend by seq1

*=

seq *= count

Repeat count times

del

del seq[i]
del seq[m:n]
del seq[m:n:step]

Delete one item
Delete more items, same as: seq[m:n] = []

seq.clear()

seq.clear()

Remove all items, same as: seq[:] = [] or del seq[:]

seq.append()

seq.append(x)

Append x to the end of the sequence,
same as: seq[len(seq):len(seq)] = [x]

seq.extend()

seq.extend(seq1)

Extend the sequence,
same as: seq[len(seq):len(seq)] = seq1 or seq += seq1

seq.insert()

seq.insert(i, x)

Insert x at index i, same as: seq[i] = x

seq.remove()

seq.remove(x)

Remove the first occurrence of x

seq.pop()

seq.pop()
seq.pop(i)

Retrieve and remove the last item
Retrieve and remove the item at index i

seq.copy()

seq.copy()

Create a shallow copy of seq, same as: seq[:]

seq.reverse()

seq.reverse()

Reverse the sequence in place

3.4. Flow Control Constructs#

3.4.1. Conditional if-elif-else#

Conditional statements allow us to write programs where only certain blocks of code are executed depending on the state of the program. Let’s look at some examples and take note of the keywords, syntax and indentation.

Conditions allow for the user to specify if and when certain lines or blocks of code are executed. Specifically, when a condition is true, the block of indented code directly below runs.

The if statement is a powerful way to control when a block of code is run. It is structured as shown below with the if statement ending in a colon and the block of code below indented by four spaces. In the Jupyter notebook, hitting the Tab key will also generate four spaces.

There are times when there is an alternative block of code that you will want to be run when the if statement evaluates as False.

There is an additional statement called the elif statement, short for “else if,” which is used to add extra conditions below the first if statement. The block of code below an elif statement only runs if the if statement is False and the elif statement is True.

The syntax is as follows. The elif (else-if) and else blocks are optional.

# if-else
if test:   # no parentheses needed for test
    true_block
else:
    false_block

# Nested-if
if test_1:
    block_1
elif test_2:
    block_2
elif test_3:
    block_3
......
......
elif test_n:
    block_n
else:
    else_block

In the example below, if pH is equal to 7, the first indented block is run. Otherwise, if pH is greater than 7, the second block is executed. In the event that the if and all elif statements are False, then the else block is executed.

if pH == 7:
    print('The solution is neutral.')
elif pH > 7:
    print('The solution is basic.')
else:
    print('The solution is acidic.')

# American evaluation
if score >= 90:
    letter = 'A'
elif score >= 80:
    letter = 'B'
elif score >= 70:
    letter = 'C'
elif score >= 60:
    letter = 'D'
else:
    letter = 'F'

Examples:

import math
#ej1.py
radio = float(input('Ingresa radio '))
cod = int(input('Ingresa codigo '))
if cod == 1 :
    per = 2*math.pi*radio
    print("Perimetro de la circunferencia = ",per)
elif cod == 2 :
    sup = math.pi*radio**2
    print('Superficie del circulo = ',sup)
elif cod == 3 :
    sup = 4*math.pi*radio**2
    print('Superficie de la esfera = ',sup)
elif cod == 4 :
    vol = 4./3.*math.pi*radio**3
    print('Volumen de la esfera = ',vol)
else:
    print('Codigo fuera de rango')
name = "Tom"

if name.lower() == "tom":
    print("That's my name too!")
elif name.lower() == "santa":
    print("That's a funny name.")
else:
    print(f"Hello {name}! That's a cool name!")
print("Nice to meet you!")
That's my name too!
Nice to meet you!
x = 5.3

if x == 0:    # No need for parentheses around the test condition
    print('x is zero')
elif x > 0:
    print('x is more than zero')
else:
    print('x is less than zero')
x is more than zero

The main points to notice:

  • Use keywords if, elif and else

  • The colon : ends each conditional expression

  • Indentation (by 4 empty space) defines code blocks

  • In an if statement, the first block whose conditional statement returns True is executed and the program exits the if block

  • if statements don’t necessarily need elif or else

  • elif lets us check several conditions

  • else lets us evaluate a default block if all other conditions are False

  • the end of the entire if statement is where the indentation returns to the same level as the first if keyword

Patterns with if-else:

absolutevalue

if x < 0:
x = -x

put x and y into sorted order

if x > y:
temp = x
x = y
y = temp

maximum of x and y

if x > y:
maximun= x
else:
maximun= y

error check for remainder operation

if den == 0:
print(“Division by zero”)
else:
print(“Remainder= “ , num% den)

error check forquadratic formula

discriminant = bb –4.0a*c
if discriminant < 0.0:
print(“No real roots”)
else:
d = math.sqrt(discriminant)
print((-b+ d)/2.0)
print((-b-d)/2.0)

If statements can also be nested inside of one another:

name = "Super Tom"

if name.lower() == "tom":
    print("That's my name too!")
elif name.lower() == "santa":
    print("That's a funny name.")
else:
    print(f"Hello {name}! That's a cool name.")
    if name.lower().startswith("super"):
        print("Do you really have superpowers?")

print("Nice to meet you!")
Hello Super Tom! That's a cool name.
Do you really have superpowers?
Nice to meet you!

Shorthand if-else (or Conditional Expression): Inline if/else

We can write simple if statements “inline”, i.e., in a single line, for simplicity. The syntax is:

true_expr if test else false_expr
    # Evaluate and return true_expr if test is True; otherwise, evaluate and return false_expr
x = 0
print('zero' if x == 0 else 'not zero')

x = -8
abs_x = x if x > 0 else -x
print(abs_x)

words = ["the", "list", "of", "words"]

x = "long list" if len(words) > 10 else "short list"
print(x)
zero
8
short list

The last part of the above code is equivalent to:

words = ["the", "list", "of", "words"]

if len(words) > 10:
    x = "long list"
else:
    x = "short list"
x
'short list'

Any object can be tested for “truth” in Python, for use in if and while statements.

  • True values: all objects return True unless they are a bool object with value False or have len() == 0

  • False values: None, False, 0, empty sequences and collections: '', (), [], {}, set()

Tip

Read more in the docs here.

Example:

x = 1

if x:
    print("I'm truthy!")
else:
    print("I'm falsey!")

x = False

if x:
    print("I'm truthy!")
else:
    print("I'm falsey!")

x = []

if x:
    print("I'm truthy!")
else:
    print("I'm falsey!")    
I'm truthy!
I'm falsey!
I'm falsey!

Comparison and Logical Operators

Python supports these comparison (relational) operators, which return a bool of either True or False.

  • < (less than), <= (less than or equal to), == (equal to), != (not equal to), > (greater than), >= (greater than or equal to).

  • in, not in: Check if an item is|is not in a sequence (list, tuple, string, set, etc).

  • is, is not: Check if two variables have the same reference.

Python supports these logical (boolean) operators: and, or, not.

Chain Comparison v1 < x < v2

Python supports chain comparison in the form of v1 < x < v2, e.g.,

>>> x = 8
>>> 1 < x < 10
True
>>> 1 < x and x < 10  # Same as above
True
>>> 10 < x < 20
False
>>> 10 > x > 1
True
>>> not (10 < x < 20)
True

Comparing Sequences

The comparison operators (such as ==, <=) are overloaded to support sequences (such as string, list and tuple).

In comparing sequences, the first items from both sequences are compared. If they differ the outcome is decided. Otherwise, the next items are compared, and so on.

# String
>>> 'a' < 'b'     # First items differ
True
>>> 'ab' < 'aa'   # First items the same. Second items differ
False
>>> 'a' < 'b' < 'c'   # with chain comparison
True

# Tuple
>>> (1, 2, 3) < (1, 2, 4)  # First and second items the same. Third items differ
True
# List
>>> [1, 2, 3] <= [1, 2, 3]  # All items are the same
True
>>> [1, 2, 3] < [1, 2, 3]
False

Short-circuiting

Python supports a concept known as “short-circuting”. This is the automatic stopping of the execution of boolean operation if the truth value of expression has already been determined.

Expression

Result

Detail

A or B

If A is True then A else B

B only executed if A is False

A and B

If A is False then A else B

B only executed if A is True

3.4.1.1. A Comment on Indentation#

In Python, all code blocks (i.e., those occurring inside loops, if clauses, function definitions, etc.) are delimited by indentation.

Thus, unlike most other languages, whitespace in Python code affects the output of the program.

Once you get used to it, this is a good thing: It

  • forces clean, consistent indentation, improving readability

  • removes clutter, such as the brackets or end statements used in other languages

On the other hand, it takes a bit of care to get right, so please remember:

  • The line before the start of a code block always ends in a colon

    • for i in range(10):

    • if x > y:

    • while x < 100:

    • etc.

  • All lines in a code block must have the same amount of indentation.

  • The Python standard is 4 spaces, and that’s what you should use.

3.4.2. The while Loop#

The while loop is used to keep executing the indented block of code below until a stop condition is satisfied.

while test:
    true_block
 
# while loop has an optional else block
while test:
    true_block
else:           # Run only if no break encountered
    else_block

The else block is optional, which will be executed if the loop exits normally without encountering a break statement.

Examples:

# Sum from 1 to the given upperbound
upperbound = int(input('Enter the upperbound: '))
sum = 0
number = 1
while number <= upperbound:  # No need for () around test condition
    sum += number
    number += 1
print(sum)
import sys
# Filename: powersoftwo.py. Accept positive integer n as a
# command-line argument. Write to standard output a table
# showing the first n powers of two.
n = int(sys.argv[1])
power = 1
i = 0
while i <= n:
    # Write the ith power of 2.
    print(str(i) + ' ' + str(power))
    power = 2 * power
    i = i + 1
# python powersoftwo.py 1
# 0 1
# 1 2

The indented block of code below the while statement is run until x is no longer less than ten. The x < 10 is known as the termination condition, and it is checked each time before the indented code is executed.The syntax is as follows:

x = 0
while x < 10:
    print(x)
    x = x + 2  # increments by 2
0
2
4
6
8

The while loops should be used with caution. This is because it is not difficult to have what is known as a faulty termination condition resulting in the code executing indefinitely… or until you manually stop Python or Python crashes because it ran out of memory. This happens because the termination condition is never met resulting in a runaway process.

Warning

Do not run the following code! It may result in Python crashing.

x = 0
while x != 10:
    x = x + 3
    print('Done')

In the above code, the value is incremented until it reaches 10 (remember, != means “does not equal”), and then a “Done” message is printed - at least that is the intention. No message is ever printed and the while loop keeps running. If we do the math on the values for x, we find that in incrementing by three (0, 3, 6, 9, 12,…), the value for x never equals 10, so the while loop never stops. For this reason, it is wise to avoid while loops unless you absolutely must use them. If you do use a while loop, triple check you termination condition and avoid using = or != in your termination condition. Instead, try to use <= or >=. These are less likely to fail.

Note that

  • the code block for the while loop is again delimited only by indentation.

  • the statement x = x + 3 can be replaced by x += 3.

3.4.3. Break, Continue, & Pass Commands#

Other ways to control the flow of code execution are the continue, pass, and break commands. These are not used heavily, but it is helpful to know about them on the occasions that you need them. The below table summarizes each of these statements below.

**Table ** Loop Interruptions

Statement

Description

break

Breaks out of lowest containing for/while loop

continue

Starts the next iteration of the lowest containing for/while loop

pass

No action; code continues on

The break statement breaks out of the most lowest containing loop. This is useful if you want to apply a condition to completely stop the for or while loop early. A break statement can often be avoided through other methods, but it is good to be able to use one for instances where you really need it.

The continue statement skips the remaining statements of the loop and continues the next iteration. In other words, is similar to the break except that instead of completely stopping a loop, it stops only the current iteration of the loop and immediately starts the next cycle.

The pass statement does nothing. It serves as a placeholder for an empty statement or empty block. It is merely a placeholder for code that you have not yet written by telling the Python interpreter to continue on. No completed code should contain a pass statement. The reason for using one is to be able to run and test code without errors occurring due to missing parts.

3.4.4. The for loop#

As we seen with while Loops allow programs to rerun the same block of code multiple times. This is important because there are often sections of code that need to be run numerous times, sometimes extending into the thousands. If we needed to include a separate copy of the same code for every time it is run, our scripts would be unreasonably large.

The for loop is the most common technique for iteration in Python. It is often used to iterate over a multi-element object like lists or tuples, and for each element, the block of indented code below is executed.

There are many ways to consider the iteration.

3.4.4.1. The for-in loop#

For each element of the sequence, it “binds” the name variable_name to that element and then executes the code block. The for-in loop has the following syntax:

for item in sequence:  # sequence: string, list, tuple, dictionary, set
    true_block
 
# for-in loop with a else block
for item in sequence:
    true_block
else:        # Run only if no break encountered
    else_block

You shall read it as “for each item in the sequence…”. Again, the else block is executed only if the loop exits normally, without encountering the break statement.

Python tends to favor looping without explicit indexing.

For example,

x_values = [1, 2, 3]  # Some iterable x
for x in x_values:
    print(x * x)
1
4
9

is preferred to

for i in range(len(x_values)):
    print(x_values[i] * x_values[i])
1
4
9

When you compare these two alternatives, you can see why the first one is preferred.

Iterating through a Sequence (String, List, Tuple, Dictionary, Set) using for-in Loop

The for-in loop is primarily used to iterate through all the items of a sequence. For example,

# String: iterating through each character
>>> for char in 'hello': print(char)
h
e
l
l
o

# List: iterating through each item
animals = ['dog', 'cat', 'bird']
for animal in animals:
    print("The plural of " + animal + " is " + animal + "s")

# List: iterating through each item
>>> for item in [123, 4.5, 'hello']: print(item)
123
4.5
hello

# Tuple: iterating through each item
>>> for item in (123, 4.5, 'hello'): print(item)
123
4.5
hello

# Dictionary: iterating through each key
>>> dct = {'a': 1, 2: 'b', 'c': 'cc'}
>>> for key in dct: print(key, ':', dct[key])
a : 1
c : cc
2 : b

# Set: iterating through each item
>>> for item in {'apple', 1, 2, 'apple'}: print(item)
1
2
apple

# File: iterating through each line
>>> infile = open('test.txt', 'r')
>>> for line in infile: print(line)
...Each line of the file...
>>> infile.close()

# Iterating through a Sequence of Sequences
# A list of 2-item tuples
>>> lst = [(1,'a'), (2,'b'), (3,'c')]
# Iterating through the each of the 2-item tuples
>>> for v1, v2 in lst: print(v1, v2)  # each item of the list is: v1, v2
1 a
2 b
3 c

# A list of 3-item lists
>>> lst = [[1, 2, 3], ['a', 'b', 'c']]
>>> for v1, v2, v3 in lst: print(v1, v2, v3)  # each item of the list is: v1, v2, v3
1 2 3
a b c
    
# Iterating through a Dictionary
>>> dct = {'name':'Peter', 'gender':'male', 'age':21}

# Iterate through the keys (as in the above example)
>>> for key in dct: print(key, ':', dct[key])
age : 21
name : Peter
gender : male

# Iterate through the key-value pairs
>>> for key, value in dct.items(): print(key, ':', value)
age : 21
name : Peter
gender : male

>>> dct.items()  # Return a list of key-value (2-item) tuples
[('gender', 'male'), ('age', 21), ('name', 'Peter')]

Take note that you cannot use the “for item in lst” loop to modify a list. To modify the list, you need to get the list indexes by creating an index list. For example,

# List to be modified
>>> lst = [11, 22, 33]

# Cannot use for-in loop to modify the list
>>> for item in lst:
        item += 1    # modifying item does not modify the list
>>> print(lst)
[11, 22, 33]  # No change

# You need to modify the list through the indexes
>>> idx_lst = [0, 1, 2]   # Create your own index list for the list to be processed (not practical)
>>> for idx in idx_lst:   # idx = 0, 1, 2
        lst[idx] += 1     # modify the list through index 
>>> print(lst)
[12, 23, 34]


# Example: list containing the squares of the values in a previous list, 
# first create an empty list and append the square values to the list.
numbers = [1, 2, 3, 4, 5, 6]  # original values
squares = []  # an empty list

for value in numbers:
    squares.append(value**2)

Manually creating the index list is not practical. You can use the range() function to create the index list (described below).

3.4.4.2. The range() Built-in Function#

The range() function produces a series of running integers, which can be used as index list for the for-in loop.

  • range(n) produces integers from 0 to n-1;

  • range(m, n) produces integers from m to n-1;

  • range(m, n, s) produces integers from m to n-1 in step of s.

For example,

# Sum from 1 to the given upperbound
upperbound = int(input('Enter the upperbound: '))
sum = 0
for number in range(1, upperbound+1):  # number = 1, 2, 3, ..., upperbound
    sum += number
print('The sum is:', sum)
 
# Sum a given list
lst = [9, 8, 4, 5]
sum = 0
for idx in range(len(lst)):  # idx = 0, 1, ..., len()-1
    sum += lst[idx]
print('The sum is:', sum)
 
# There is no need to use indexes to 'read' the list!
lst = [9, 8, 4, 5]
sum = 0
for item in lst:  # Each item of lst
    sum += item
print('The sum is:', sum)

# You can also use built-in function to get the sum
del sum   # Need to remove the variable 'sum' before using built-in function sum()
print('The sum is:', sum(lst))

# But you need indexes to modify the list
for idx in range(len(lst)):  # idx = 0, 1, ..., len()-1
    lst[idx] += 1
print(lst)

# Or you can use a while loop, which is longer
idx = 0
while idx < len(lst):
    lst[idx] += 1
    idx += 1
print(lst)

# You can create a new list through a one liner list comprehension
lst = [11, 22, 33]
lst1 = [item + 1 for item in lst]
print(lst1)

Using else-clause in Loop

Recall that the else-clause will be executed only if the loop exits without encountering a break.

# List all primes between 2 and 100
for number in range(2, 101):
    for factor in range(2, number//2+1):  # Look for factor
        if number % factor == 0:  # break if a factor found
            print('{} is NOT a prime'.format(number))  
            break
    else:
        print('{} is a prime'.format(number))  # Only if no break encountered

3.4.4.3. The iter() and next() Built-in Functions#

The built-in function iter(iterable) takes an iterable (such as sequence) and returns an iterator object. You can then use next(iterator) to iterate through the items. For example,

>>> lst = [11, 22, 33]
>>> iterator = iter(lst)
>>> next(iterator)
11
>>> next(iterator)
22
>>> next(iterator)
33
>>> next(iterator)
StopIteration   # Raise StopIteration exception if no more item
>>> type(iterator)
<class 'list_iterator'>

3.4.4.4. The reversed() Built-in Function#

To iterate a sequence in the reverse order, apply the reversed() function which reverses the iterator over values of the sequence. For example,

>>> lst = [11, 22, 33]
>>> for item in reversed(lst): print(item, end=' ')
33 22 11
>>> reversed(lst)
<list_reverseiterator object at 0x7fc4707f3828>

>>> str = "hello"
>>> for ch in reversed(str): print(ch, end='')
olleh

3.4.4.5. The enumerate() Built-in Function#

You can use the built-in function enumerate() to obtain the positional indexes, when looping through a sequence. For example,

# List
>>> lst = ['a', 'b', 'c']
>>> for idx, value in enumerate(lst): print(idx, value)
0 a
1 b
2 c
>>> enumerate(lst)
<enumerate object at 0x7ff0c6b75a50>

# You can also use enumerate() to get the indexes to modify the list
>>> lst = [11, 22, 33]
>>> for idx, value in enumerate(lst): lst[idx] += 1
>>> lst
[12, 23, 34]

# Tuple
>>> tup = ('d', 'e', 'f')
>>> for idx, value in enumerate(tup): print(idx, value)
0 d
1 e
2 f

3.4.4.6. Multiple Sequences and the zip() Built-in Function#

Python provides some facilities to simplify looping without indices. One is zip(), which is used for stepping through pairs from two sequences.

For example, the following code

countries = ('Japan', 'Korea', 'China')
cities = ('Tokyo', 'Seoul', 'Beijing')
for country, city in zip(countries, cities):
    print(f'The capital of {country} is {city}')
The capital of Japan is Tokyo
The capital of Korea is Seoul
The capital of China is Beijing

The zip() function is also useful for creating dictionaries, for example:

names = ['Tom', 'John']
marks = ['E', 'F']
dict(zip(names, marks))
{'Tom': 'E', 'John': 'F'}

To loop over two or more sequences concurrently, you can pair the entries with the zip() built-in function. For examples,

>>> lst1 = ['a', 'b', 'c']
>>> lst2 = [11, 22, 33]
>>> for i1, i2 in zip(lst1, lst2): print(i1, i2)
a 11
b 22
c 33
>>> zip(lst1, lst2)   # Return a list of tuples
[('a', 11), ('b', 22), ('c', 33)]

# zip() for more than 2 sequences
>>> tuple3 = (44, 55)
>>> zip(lst1, lst2, tuple3)
[('a', 11, 44), ('b', 22, 55)]

3.4.4.7. Comprehension for Generating Mutable List, Dictionary and Set#

List comprehension provides a one-liner concise way to generate a new list. The syntax is:

result_list = [expression_with_item for item in list]
result_list = [expression_with_item for item in list if test]   # with an optional test
 
# Same as
result_list = []
for item in list:
    if test:
        result_list.append(item)

For examples,

>>> sq_lst = [item * item for item in range(1, 11)]
>>> sq_lst
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# Same as
>>> sq_lst = []
>>> for item in range(1, 11):
        sq_lst.append(item * item)

>>> lst = [3, 4, 1, 5]
>>> sq_lst = [item * item for item in lst]  # no test, all items
>>> sq_lst
[9, 16, 1, 25]

>>> sq_lst_odd = [item * item for item in lst if item % 2 != 0]
>>> sq_lst_odd
[9, 1, 25]
# Same as
>>> sq_lst_odd = []
>>> for item in lst:
        if item % 2 != 0:
            sq_lst_odd.append(item * item)

# Nested for
>>> lst = [(x, y) for x in range(1, 3) for y in range(1, 4) if x != y]
>>> lst
[(1, 2), (1, 3), (2, 1), (2, 3)]
# Same as
>>> lst = []
>>> for x in range(1,3):
        for y in range(1,4):
            if x != y: lst.append((x, y))
>>> lst
[(1, 2), (1, 3), (2, 1), (2, 3)]

Similarly, you can create dictionary and set (mutable sequences) via comprehension. For example,

# Dictionary {k1:v1, k2:v2,...}
>>> dct = {x:x**2 for x in range(1, 5)}  # Use braces for dictionary
>>> dct
{1: 1, 2: 4, 3: 9, 4: 16}

# Set {v1, v2,...}
>>> set = {ch for ch in 'hello' if ch not in 'aeiou'}  # Use braces for set too
>>> set
{'h', 'l'}

3.5. Console Input/Output: input() and print() Built-in Functions#

You can use built-in function input() to read input from the keyboard (as a string) and print() to print output to the console. For example,

>>> x = input('Enter a number: ')
Enter a number: 5
>>> x
'5'          # A quoted string
>>> type(x)  # Check data type
<class 'str'>
>>> print(x)
5

# Cast input from the 'str' input to 'int'
>>> x = int(input('Enter an integer: '))
Enter an integer: 5
>>> x
5            # int
>>> type(x)  # Check data type
<class 'int'>
>>> print(x)
5

3.5.1. input()#

Python input() function is used to take user input. By default, it returns the user input in form of a string.

Syntax:

input(prompt)

prompt [optional]: any string value to display as input message

Example:

input("What is your name? ")

Returns: Return a string value as input by the user.

If you want to take input as int or float, you just need to typecast it.

>>> user_input = input()
foo bar baz
>>> user_input
'foo bar baz'

>>> name = input("What is your name? ")
What is your name? Winston Smith
>>> name
'Winston Smith'

>>> number = input("Enter a number: ")
Enter a number: 50
>>> print(number + 100)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: must be str, not int

>>> number = int(input("Enter a number: "))
Enter a number: 50
>>> print(number + 100)
150
# Taking input as string
color = input("What color is rose?: ")
print(color)

# Taking name of the user as input
# and storing it name variable
name = input("Please Enter Your Name: ")

# taking age of the user as input and
# storing in into variable age
age = input("Please Enter Your Age: ")

print("Name & Age: ", name, age)

# Taking input as int
# Typecasting to int
n = int(input("How many roses?: "))
print(n)

# Taking number 1 from user as int
num1 = int(input("Please Enter First Number: "))
# Taking number 2 from user as int
num2 = int(input("Please Enter Second Number: "))

# adding num1 and num2 and storing them in
# variable addition
addition = num1 + num2

# printing
print("The sum of the two given numbers is {} ".format(addition))

# Taking input as float
# Typecasting to float
price = float(input("Price of each rose?: "))
print(price)

# Read a list of integers
# creating an empty list
lst = []
# number of elements as input
n = int(input("Enter number of elements : "))
# iterating till the range
for i in range(0, n):
            ele = int(input())
            lst.append(ele) # adding the element
print(lst)

# Read matrix with split and nested list comprehension
m, n = [int(x) for x in input("Enter the number of rows and columns separated with blank: ").split()]
print("Enter %d rows of %d columns of float values separated by blanks"%(m,n))
matrix = [[float(j) for j in input().split()] for i in range(m)]
print(matrix)

# Read square matrix with nested list comprehension. One value by row 
matrix_size = int(input("Enter the range of matrix: "))
print("Enter %d rows of float values: "%(matrix_size*matrix_size))
matrix = [[float(input()) for _ in range(matrix_size)] for _ in range(matrix_size)]
print(matrix)

# Read using handling exceptions
while True:
    try:
        age = int(input("How old are you? "))
    except ValueError:
        print("Please enter a number for your age.")
    else:
        break

print(f"Next year, you'll be {age + 1} years old")

3.5.2. print()#

The print() function, which acknowledges 0 or more expressions divided by commas, is the easiest way to produce output. This function alters the expressions you approve into a string prior to writing to the screen.

The built-in function print() has the following whole syntax:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
    # Print objects to the text stream file (default standard output sys.stdout),
    #   separated by sep (default space) and followed by end (default newline \n).

where:

  • *objects: one or greater objects to be printed.

  • sep: Separator among objects. Default value = one space

By default, print() separates objects by a single space and appends a newline to the end of the output:

Examples:

>>> print('apple')  # Single item
apple
>>> print('apple', 'orange')  # More than one items separated by commas
apple orange
>>> print('apple', 'orange', 'banana')
apple orange banana

>>> first_name = "Winston"
>>> last_name = "Smith"
>>> print("Name:", first_name, last_name)
Name: Winston Smith
    
# If an object isn’t a string, then print() converts it to an appropriate 
# string representation before displaying it
>>> example_list = [1, 2, 3]
>>> example_int = -12
>>> example_dict = {"foo": 1, "bar": 2}
>>> print(example_list, example_int, example_dict, len)
[1, 2, 3] -12 {'foo': 1, 'bar': 2} <built-in function len>
        
# print()'s separator (sep) and ending (end)
# print() with default newline
>>> for item in [1, 2, 3, 4]:
        print(item)  # default is newline
1
2
3
4
# print() without newline
>>> for item in [1, 2, 3, 4]:
        print(item, end='')   # suppress end string
1234
# print() with some arbitrary ending string 
>>> for item in [1, 2, 3, 4]:
       print(item, end='--')
1--2--3--4--
# Test separator between items
>>> print('apple', 'orange', 'banana')  # default is space
apple orange banana
>>> print('apple', 'orange', 'banana', sep=',')
apple,orange,banana
>>> print('apple', 'orange', 'banana', sep=':')
apple:orange:banana
>>> print('apple', 'orange', 'banana', sep='|')
apple|orange|banana
>>> print('apple', 'orange', 'banana', sep='\n')  # newline
apple
orange
banana

3.5.2.1. Printing With Advanced Features#

print() takes a few additional arguments that provide modest control over the format of the output. Each of these is a special type of argument called a keyword argument.

  • Keyword arguments have the form =.

  • Any keyword arguments passed to print() must come at the end, after the list of objects to display.

Separating Printed Values

Adding the keyword argument sep=<str> causes Python to separate objects by instead of by the default single space:

>>> print("foo", 42, "bar")
foo 42 bar

>>> print("foo", 42, "bar", sep="/")
foo/42/bar

>>> print("foo", 42, "bar", sep="...")
foo...42...bar

>>> d = {"foo": 1, "bar": 2, "baz": 3}
>>> for k, v in d.items():
...     print(k, v, sep=" -> ")
...
foo -> 1
bar -> 2
baz -> 3

To squish objects together without any space between them, specify an empty string (“”) as the separator:

>>> print("foo", 42, "bar", sep="")
foo42bar

Controlling the Newline Character

The keyword argument end=<str> causes output to be terminated by instead of by the default newline:

>>> if True:
...     print("foo", end="/")
...     print(42, end="/")
...     print("bar")
...
foo/42/bar

if you’re displaying values in a loop, you might use end to cause the values to be displayed on one line, rather than on individual lines:

>>> for number in range(10):
...     print(number)
...
0
1
2
3
4
5
6
7
8
9

>>> for number in range(10):
...     print(number, end=(" " if number < 9 else "\n"))
...
0 1 2 3 4 5 6 7 8 9

You can use the end keyword to specify any string as the output terminator.

Sending Output to a Stream print() accepts two additional keyword arguments, both of which affect how the function handles the output stream:

  • file=<stream>: By default, print() sends its output to a default stream called sys.stdout, which is usually equivalent to the console. The file= argument causes print() to send the output to an alternate stream designated by instead.

  • flush=True: Ordinarily, print() buffers its output and only writes to the output stream intermittently. flush=True specifies that Python forcibly flushes the output stream with each call to print().

3.5.2.2. Formatted print#

There are four common methods that will allow you to add Python variables in a string: the comma, the modulus operator, string format and f-strings.

The comma

The most common way to separate strings and variables is with a comma:

>>> name = "John"
>>> age = 16
>>> height = 1.72
>>> print("Name:", name, "; Age:", age, "; Height:", height, "m")
Name: John ; Age: 16 ; Height: 1.72 m

Note that each comma separation is a “space” in the output string.

The % operator

Example:

>>> name = "John"
>>> age = 16
>>> height = 1.72
>>> print("Name: %s; Age: %d; Height: %fm" % (name, age, height))
Name: John; Age: 16; Height: 1.720000m
>>> print("Name: %s; Age: %d; Height: %.1fm" % (name, age, height))
Name: John; Age: 16; Height: 1.7m

There are two major limitations:

  • You can’t include any data types, such as list or datetime.

Different components of a conversion specifier appear in the format string and determine how values are formatted when Python inserts them into the format string.

A conversion specifier begins with a % character and can consist of a few components in a certain order:

The % character and the component are required. The remaining components, shown in square brackets, are optional.

The following table summarizes what each component of a conversion specifier does:

Component

Meaning

%

Introduces the conversion specifier

Indicates one or more flags that exert finer control over formatting

Specifies the minimum width of the formatted result

.

Determines the length and precision of floating-point or string output

Indicates the type of conversion to be performed

The type of conversion that Python applies to the corresponding value before inserting it into the format string can be one of this table that lists the possible conversion types:

Conversion Type

d, i, u

Decimal integer

x, X

Hexadecimal integer

o

Octal integer

f, F

Floating-point

e, E

E notation

g, G

Floating-point or E notation

c

Single character

s, r, a

String

%

Single ‘%’ character

The Component: You can determine the minimum width of the output field by using the component. If the output is shorter than , then by default, it’s right-justified in a field that is characters wide and padded with ASCII space characters on the left.

The . Component: The . conversion specifier component affects the floating-point conversion types and character conversion types.

  • For the floating-point conversion types f, F, e, and E, . determines the number of digits after the decimal point.

  • String values formatted with the s, r, and a character conversion types are truncated to the length specified by the . component

The component of a conversion specifier can include any of the characters shown in the following table:

Character

Controls

#

Display of base or decimal point for integer and floating-point values

0

Padding of values that are shorter than the specified field width

-

Justification of values that are shorter than the specified field width

+

Display of leading sign for numeric values

‘ ‘ (space)

Display of leading sign for numeric values

The String Format Method

Python string has a format method that lets you insert any data type. It’s very similar to the % operator with %s or %d or %f replaced with {}, but better for a few reasons, including:

  1. You don’t have to be sure about the data type.

  2. You can insert any data type.

  3. You can repeatedly use a value by indexing.

  4. The values can be expressed as a list of key-value pairs.

>>> name = "John"
>>> age = 16
>>> height = 1.72
>>> print("Name: {}; Age: {}; Height: {}m".format(name, age, height))
Name: John; Age: 16; Height: 1.72m
>>> print("{} test scores in a list {} ".format(name, [23, 25.5, 28]))
John test scores in a list [23, 25.5, 28] 
>>> print("{0} is {3}. {0} loves {1}, {2} and {0}".format(name,'Harry Potter', 'ice cream', age))
John is 16. John loves Harry Potter, ice cream and John
>>> print("{fname} {lname} is {age}".format(age=16, fname="John", lname="Snow"))
John Snow is 16

F-Strings

Another option is the formatted string literal, f-string.

>>> name = "John"
>>> age = 16
>>> height = 1.72
>>> print(f"Hello, {name}. You are {age}.")
Hello, John. You are 16.
>>> print(f"Hello, {name}. In 50 years, you'll be {age + 50}.")
Hello, John. In 50 years, you'll be 66. 
>>> print(f"Hello, {name.upper()}! You're {age} years old.")
Hello, JOHN! You're 16 years old.
>>> print(f"{[2**n for n in range(3, 9)]}")
[8, 16, 32, 64, 128, 256]

3.5.2.3. Redirection and Piping#

For many applications, typing input data as a standard input stream from the terminal window is untenable because doing so limits our program’s processing power by the amount of data that we can type. Similarly, we often want to save the information printed on the standard output stream for later use. We can use operating system mechanisms to address both issues.

Redirecting standard output to a file

By adding a simple directive to the command that invokes a program, we can redirect its standard output to a file, for permanent storage or for input to some other program at a later time. For example, the command:

D:\Python>python serie_1_5.py > dataex.txt

specifies that the standard output stream is not to be written in the terminal window, but instead is to be written to a text file named dataex.txt.

The code of serie_1_5.py is:

for i in range(1,6):
    print(i)
print('n')

Redirecting standard input from a file

Similarly, we can redirect standard input so that a program reads data from a file instead of the terminal application. For example, the command:

D:\Python>python average.py < dataex.txt

reads a sequence of numbers from the file data.txt, computes their average, and writes the average to standard output. Specifically, the < symbol is a directive to implement the standard input stream by reading from the file data.txt instead of by waiting for the user to type something into the terminal window.

The code of average.py is:

total = 0.0
count = 0

while True:
    try:
        value = input()
        total += float(value)
        count += 1
    except ValueError or EOFError:
        break

avg = total / count
print('Average is ' + str(avg))

Connecting two programs

The most flexible way to implement the standard input and standard output abstractions is to specify that they are implemented by our own programs! This mechanism is called piping. For example, the following command:

D:\Python>python serie_1_5.py | average.py

specifies that the standard output stream for serie_1_5.py and the standard input stream for average.py are the same stream. That is, the result has the same effect as the following sequence of commands:

D:\Python>python serie_1_5.py > dataex.txt
D:\Python>python average.py < dataex.txt

but the file data.txt is not needed.

3.6. File Input/Output#

File Input/Output (IO) requires 3 steps:

  1. Open the file for read or write or both.

  2. Read/Write data.

  3. Close the file to free the resources.

Python provides built-in functions and external modules to support these operations.

3.6.1. Opening/Closing a File#

  • open(file, [mode=’r’]) -> fileObj: Open the file and return a file object. The available modes are:

    • ‘r’ (read-only) (default),

    • ‘w’ (write - erase all contents for existing file),

    • ‘a’ (append), ‘r+’ (read and write).

    You can also use ‘rb’, ‘wb’, ‘ab’, ‘rb+’ for binary mode (raw-byte) operations. You can optionally specify the text encoding via keyword parameter encoding, e.g., encoding=”utf-8”.

  • fileObj.close(): Flush and close the file stream.

3.6.2. Reading/Writing Text Files#

The fileObj returned after the file is opened maintains a file pointer. It initially positions at the beginning of the file and advances whenever read/write operations are performed.

3.6.2.1. Reading Line/Lines from a Text File#

  • fileObj.readline() -> str: (most commonly-used) Read next line (up to and including newline) and return a string (including newline). It returns an empty string after the end-of-file (EOF).

  • fileObj.readlines() -> [str]: Read all lines into a list of strings.

  • fileObj.read() -> str: Read the entire file into a string.

3.6.2.2. Writing Line to a Text File#

  • fileObj.write(str) -> int: Write the given string to the file and return the number of characters written. You need to explicitly terminate the str with a ‘\n’, if needed. The ‘\n’ will be translated to the platform-dependent newline (‘\r\n’ for Windows or ‘\n’ for Unixes/macOS).

Examples:

# Open a file for writing and insert some records
>>> f = open('test.txt', 'w')
>>> f.write('apple\n')
>>> f.write('orange\n')
>>> f.write('pear\n')
>>> f.close()    # Always close the file
# Check the contents of the file created

# Open the file created for reading and read line(s) using readline() and readlines()
>>> f = open('test.txt', 'r')
>>> f.readline()         # Read next line into a string
'apple\n'
>>> f.readlines()        # Read all (next) lines into a list of strings
['orange\n', 'pear\n']
>>> f.readline()         # Return an empty string after EOF
''
>>> f.close()

# Open the file for reading and read the entire file via read() 
>>> f = open('test.txt', 'r')
>>> f.read()              # Read entire file into a string
'apple\norange\npear\n'
>>> f.close()

# Read line-by-line using readline() in a while-loop
>>> f = open('test.txt')
>>> line = f.readline()   # include newline
>>> while line:
        line = line.rstrip()  # strip trailing spaces and newline
        # process the line
        print(line)
        line = f.readline()
apple
orange
pear
>>> f.close()

3.6.3. Processing Text File Line-by-Line#

We can use a with-statement to open a file, which will be closed automatically upon exit, and a for-loop to read line-by-line as follows:

with open('path/to/file.txt', 'r') as f:  # Open file for read
    for line in f:           # Read line-by-line
        line = line.strip()  # Strip the leading/trailing whitespaces and newline
        # Process the line
# File closed automatically upon exit of with-statement

The with-statement is equivalent to the try-finally statement as follows:

try:
    f = open('path/to/file.txt')
    for line in f:
        line = line.strip()
        # Process the line
finally:
    f.close()

Example: Line-by-line File Copy

The following script copies a file into another line-by-line, prepending each line with the line number.

"""
file_copy: Copy file line-by-line from source to destination
------------------------------------------------------------
Usage: file_copy <src> <dest>
"""
import sys
import os

def main():
    # Check and retrieve command-line arguments
    if len(sys.argv) != 3:
        print(__doc__)
        sys.exit(1)   # Return a non-zero value to indicate abnormal termination
    fileIn  = sys.argv[1]
    fileOut = sys.argv[2]

    # Verify source file
    if not os.path.isfile(fileIn):
        print("error: {} does not exist".format(fileIn))
        sys.exit(1)

    # Verify destination file
    if os.path.isfile(fileOut):
        print("{} exists. Override (y/n)?".format(fileOut))
        reply = input().strip().lower()
        if reply[0] != 'y':
           sys.exit(1)

    # Process the file line-by-line
    with open(fileIn, 'r') as fpIn, open(fileOut, 'w') as fpOut:
        lineNumber = 0
        for line in fpIn:
            lineNumber += 1
            line = line.rstrip()   # Strip trailing spaces and newline
            fpOut.write("{}: {}\n".format(lineNumber, line))
            # Need \n, which will be translated to platform-dependent newline
        print("Number of lines: {}\n".format(lineNumber))

if __name__ == '__main__':
    main()

3.6.4. Binary File Operations#

  • fileObj.tell() -> int: returns the current stream position. The current stream position is the number of bytes from the beginning of the file in binary mode, and an opaque number in text mode.

  • fileObj.seek(offset): sets the current stream position to offset bytes from the beginning of the file.