Table of Contents (Hide)

Python Programming

by Examples

This article is meant for experienced programmers to look at Python's syntaxes and those who need to refresh their memory. For novices, go to the next article.

I shall assume that you are familiar with some programming languages such as C/C++/Java. This article is NOT meant to be an introduction to programming.

I personally recommend that you learn a traditional general-purpose programming language (such as C/C++/Java) as foundation before learning scripting languages like Python/JavaScript/Perl/PHP because they are less structure than the traditional languages with many fancy features.

Syntax Summary and Comparison

  • EOL Comments: Python's comment begins with a '#' and lasts until the end-of-line (EOL). Python does not support multi-line comments. On the other hand, Python supports triple-quoted multi-line string and you may use multi-line string for multi-line comment, or for commenting out lines of codes.
    C/C++/C#/Java end-of-line comment begins with '\\'. They support multi-line comments via /* ... */.
  • Strings and Multi-Line Strings: Python's string can be delimited by either single quotes ('...') or double quotes ("..."). Python also supports multi-line string, delimited by either triple-single ('''...''') or triple-double quotes ("""..."""). Strings are immutable in Python.
    C/C++/C#/Java use double quotes for string and single quotes for character. The early versions do not support multi-line string.
  • Variable Type Declaration: Like most of the scripting interpreted languages (such as JavaScript/Perl), Python is dynamically typed. You do NOT need to declare variables (name and type) before using them. A variable is created via the initial assignment. Python associates types with the objects, not the variables, i.e., a variable can hold object of any types.
    In C/C++/C#/Java, which are strong-type languages, you need to declare the name and type of a variable before using it.
  • Data Types: Python support these data types: int (integers), float (floating-point numbers), str (String), bool (boolean of True or False), and more.
  • Statements: Python's statement ends with a newline.
    C/C++/C#/Java's statement ends with a semi-colon (;)
  • Compound Statements and Indentation: Python uses indentation to indicate body-block, as follows:
    header_1:          # Headers are terminated by a colon
        statement_1_1  # Body blocks are indented (recommended to use 4 spaces)
        statement_1_2
        ......
    header_2:
        statement_2_1
        statement_2_2
        ......
    
    # You can place the body-block in the same line, separating the statement by semi-colon (;)
    # This is NOT recommended.
    header_1: statement_1_1; statement_1_2; ......
    header_2: statement_2_1; statement_2_2; ......
    This syntax forces you to indent the program correctly which is crucial for reading your program. You can use space or tab for indentation (but not mixture of both). Each body level must be indented at the same distance. It is recommended to use 4 spaces for each level of indentation.
    C/C++/C#/Java use braces {}.
  • Assignment Operator: = (assign RHS value to LHS variable)
  • Arithmetic Operators: + (add), - (subtract), * (multiply), / (divide), % (modulus), // (integer divide), ** (exponent). But ++ (increment) and -- (decrement) are NOT supported.
    C/C++/Java do int divide with two int's. They support exponentiation via library function.
  • Compound Assignment Operators: +=, -=, *=, /=, %=, //=, **=.
  • Comparison Operators: ==, !=, <, <=, >, >=, in (check if a value is in a collection), not in, is (check if two variables point to the same object), not is.
  • Logical Operators: and, or, not.
    C/C++/C#/Java use &&, || and !.
  • Conditional's:
    # if-then-else
    if test:   # no parentheses needed for test
        true_block
    else:      # Optional
        false_block
    
    # Nested-if
    if test_1:
        block_1
    elif test_2:    # "elif" is a keyword
        block_2
    ......
    elif test_n:
        block_n
    else:
        else_block
    
    # Shorthand if-then-else tenary operator
    true_expr if test else false_expr
      # C/C++/C#/Java use tenary operator: test ? true_value : false_value
  • Loops:
    # while-do loop
    while test:     # no parentheses needed for test
        true_block
    else:           # Optional, run only if no break encountered
        else_block
    
    # for-each loop
    for item in sequence:
        true_block
    else:           # Optional, run only if no break encountered
        else_block
    Python does NOT support the traditional C-like for-loop with index: for (int i; i < n; ++i) { body }.
  • List: Python supports variable-size dynamic array via a built-in data structure called list, denoted as lst=[v1, v2, ..., vn]. List is similar to C/C++/C#/Java's array but NOT fixed-size. You can refer to an element via lst[i] or lst[-i], or sub-list via lst[m:n:step]. You can use built-in functions such as len(lst), sum(lst), min(lst).
  • Data Structures:
    • List: [v1, v2, ...]: mutable dynamic array.
    • Tuple: (v1, v2, v3, ...): Immutable fix-sized array.
    • Dictionary or Associative Array: {k1:v1, k2:v2, ...}: mutable key-value pairs, associative array, map.
    • Set: {k1, k2, ...}: mutable array with unique key.
  • Sequence (String, Tuple, List) Operators and Functions:
    • in, not in: membership test - check if a value is in a collection.
    • +: concatenation
    • *: repetition
    • [i], [-i]: indexing
    • [m:n:step]: slicing
    • len(seq), min(seq), max(seq)
    • seq.index(), seq.count()
  • Mutable Sequences (list) only Operators and Functions:
    • Assignment via [i], [-i] (indexing) and [m:n:step] (slicing)
    • Assignment via =, += (compound concatenation), *= (compound repetition)
    • del: delete
    • mseq.clear(), mseq.append(), mseq.extend(), mseq.insert(), mseq.remove(), mseq.pop(), mseq.copy(), mseq.reverse()
  • Function Definition:
    def functionName(*args, **kwargs):  # Positional and keyword arguments
        body
        return return_value

Example grade_statistics.py - Basic Syntaxes and Constructs

I suggest you use an IDE, such as VS Code, to write and run these programs.

This example repeatably prompts user for grade (between 0 and 100 with input validation). It then computes the sum, average, minimum, and print the horizontal histogram.

This example illustrates the basic Python syntaxes and constructs, such as comment, statement, block indentation, conditional if-else, for-loop, while-loop, input/output, string, list and function.

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
grade_statistics - Grade statistics
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Prompt user for grades (0-100 with input validation) and compute the sum, average,
  minimum, and print the horizontal histogram.
An example to illustrate basic Python syntaxes and constructs, such as block indentation,
  conditional, for-loop, while-loop, input/output, list and function.
 
Usage: ./grade_statistics.py  (Unix/macOS)
       python3 grade_statistics.py  (All Platforms)
"""
# Define all the functions before using them
def my_sum(lst):
    """Return the sum of the given list."""
    sum = 0
    for item in lst: sum += item
    return sum
 
def my_average(lst):
    """Return the average of the given list."""
    return my_sum(lst)/len(lst)   # float
 
def my_min(lst):
    """Return the minimum of the given lst."""
    min = lst[0]
    for item in lst:
        if item < min:   # Parentheses () not needed for test
            min = item
    return min
 
def print_histogram(lst):
    """Print the horizontal histogram."""
    # Create a list of 10 bins to hold grades of 0-9, 10-19, ..., 90-100.
    # bins[0] to bins[8] has 10 items, but bins[9] has 11 items.
    bins = [0]*10   # Use repetition operator (*) to create a list of 10 zeros
 
    # Populate the histogram bins from the grades in the given lst.
    for grade in lst:
        if grade == 100:  # Special case
            bins[9] += 1
        else:
            bins[grade//10] += 1  # Use // for integer divide to get a truncated int
 
    # Print histogram
    # 2D pattern: rows are bins, columns are value of that particular bin in stars
    for row in range(len(bins)):  # [0, 1, 2, ..., len(bins)-1]
        # Print row header
        if row == 9:  # Special case
            print('{:3d}-{:<3d}: '.format(90, 100), end='')  # Formatted output (new style), no newline
        else:
            print('{:3d}-{:<3d}: '.format(row*10, row*10+9), end='')  # Formatted output, no newline
 
        # Print one star per count
        for col in range(bins[row]): print('*', end='')  # no newline
        print()  # newline
        # Alternatively, use str's repetition operator (*) to create the output string
        #print('*'*bins[row])

def main():
    """The main function."""
    # Create an initial empty list for grades to receive from input
    grade_list = []
    # Read grades with input validation
    grade = int(input('Enter a grade between 0 and 100 (or -1 to end): '))
    while grade != -1:
        if 0 <= grade <= 100:  # Python support this comparison syntax
            grade_list.append(grade)
        else:
            print('invalid grade, try again...')
        grade = int(input('Enter a grade between 0 and 100 (or -1 to end): '))
 
    # Call functions and print results
    print('---------------')
    print('The list is:', grade_list)
    print('The minimum is:', my_min(grade_list))
    print('The minimum using built-in function is:', min(grade_list))  # Using built-in function min()
    print('The sum is:', my_sum(grade_list))
    print('The sum using built-in function is:', sum(grade_list))   # Using built-in function sum()
    print('The average is: %.2f' % my_average(grade_list))          # Formatted output (old style)
    print('The average is: {:.2f}'.format(my_average(grade_list)))  # Formatted output (new style)
    print('---------------')
    print_histogram(grade_list)

# Ask the Python interpreter to run the main() function
if __name__ == '__main__':
    main()

To run the Python script on command-line (BUT I suggest that you run it under an IDE, such as VS Code):

# (All platforms) Invoke Python Interpreter to run the script
$ cd /path/to/project_directory
$ python3 grade_statistics.py     // or py (in windows), or python

# (Unix/macOS/Cygwin) Set the script to executable, and execute the script directly
$ cd /path/to/project_directory
$ chmod u+x grade_statistics.py
$ ./grade_statistics.py

The expected output is:

$ Python3 grade_statistics.py
Enter a grade between 0 and 100 (or -1 to end): 9
Enter a grade between 0 and 100 (or -1 to end): 999
invalid grade, try again...
Enter a grade between 0 and 100 (or -1 to end): 101
invalid grade, try again...
Enter a grade between 0 and 100 (or -1 to end): 8
Enter a grade between 0 and 100 (or -1 to end): 7
Enter a grade between 0 and 100 (or -1 to end): 45
Enter a grade between 0 and 100 (or -1 to end): 90
Enter a grade between 0 and 100 (or -1 to end): 100
Enter a grade between 0 and 100 (or -1 to end): 98
Enter a grade between 0 and 100 (or -1 to end): -1
---------------
The list is: [9, 8, 7, 45, 90, 100, 98]
The minimum is: 7
The minimum using built-in function is: 7
The sum is: 357
The sum using built-in function is: 357
The average is: 51.00
---------------
  0-9  : ***
 10-19 :
 20-29 :
 30-39 :
 40-49 : *
 50-59 :
 60-69 :
 70-79 :
 80-89 :
 90-100: ***
How It Works
  1. #!/usr/bin/env python3 (Line 1) is applicable to the Unix environment only. It is known as the Hash-Bang (or She-Bang) for specifying the path of the Python Interpreter, so that the script can be executed directly as a standalone program.
  2. # -*- coding: UTF-8 -*- (Line 2, optional) specifies the source encoding scheme for saving the source file. We choose and recommend UTF-8 for i18n (internationalization). This special format is recognized by many editors for saving the source code in the specified encoding format.
  3. Doc-String (Line 3-13): The script begins with the so-called documentation string, or doc-string, to provide the documentation for this module. Doc-string is a multi-line string (delimited by triple single/double quotes), which can be extracted from the source file to create documentation. In this way, the documentation is maintained in the source code together with the code.
  4. def my_sum(lst): (Line 15-19): We define a function called my_sum() which takes a list and return the sum of the items. It uses a for-each-item-in loop to iterate through all the items of the given list. As Python is interpretative, you need to define the function first, before using it.
    • We choose the function name my_sum(list) to differentiate from the built-in function sum(list).
    • sum is an built-in function in Python. Our local variable sum shadows the system built-in within the my_sum function.
  5. bins = [0]*10 (Line 38): Python supports repetition operator (*). This statement creates a list of ten zeros. Repetition operator (*) can be apply on string (Line 59).
  6. for row in range(len(bins)): (Line 48, 56): Python supports only for-in loop. It does NOT support the traditional C-like for-loop with index. Hence, we need to use the built-in range(n) function to create a list of indexes [0, 1, ..., n-1], then apply the for-in loop on the indexed list.
  7. 0 <= grade <= 100 (Line 68): Python supports this syntax for comparison. C/C++/C#/Java do not.
  8. There are few ways of printing:
    1. print() built-in function (Line 75-80):
      print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
          # Print objects to the text-stream file (default standard output sys.stdout),
          #   items are separated by sep (default space) and followed by end (default newline).
          #   *objects denotes variable number of positional arguments packed into a tuple.
      By default, print() prints a newline at the end. You need to include argument end='' (empty string) to suppress the newline.
    2. print(str.format()) (Line 51, 53): using Python 3's new style for formatting string via str class member function str.format(). The string on which this method is called can contain texts, or replacement fields (place holders) delimited by braces {}. Each replacement field contains either the numeric index of a positional argument, or the name of a keyword argument, with C-like format specifiers beginning with : (instead of % in C) such as :4d for integer with width of 4, :6.2f for floating-point number with width of 6 and 2 decimal places, and :-5s for string with width of 5, and flags such as < for left-align, > for right-align, ^ for center-align.
    3. print('formatting-string' % args) (Line 81): Python 2's old style for formatted string using % operator. The formatting-string could contain C-like format-specifiers, such as %4d for integer, %6.2f for floating-point number, %5s for string. This line is included in case you need to read old programs. I suggest you use the new Python 3's formatting style.
  9. grade = int(input('Enter ... ')) (Line 66, 72): You can read input from standard input device (default to keyboard) via the built-in input() function.
    input([promptStr])
      # The optional promptStr argument is written to standard output without a trailing newline.
      # The function then reads a line from input, converts it to a string (stripping a trailing newline),
      #   and returns the string.
    As the input() function returns a string, we need to cast it to int.
  10. if __name__ == '__main__': (Line 87): When you execute a Python module via the Python Interpreter, the global variable __name__ is set to '__main__'. On the other hand, when a module is imported into another module, its __name__ is set to the module name. Hence, the above module will be executed if it is loaded by the Python interpreter, but not imported by another module. This is a good practice for running a module.

Example number_guess.py - Guess a Number

This is a number guessing game. It illustrates nested-if (if-elif-else), while-loop with bool flag, and random module. For example,

Enter your guess (between 0 and 100): 50
Try lower...
Enter your guess (between 0 and 100): 25
Try higher...
Enter your guess (between 0 and 100): 37
Try higher...
Enter your guess (between 0 and 100): 44
Try lower...
Enter your guess (between 0 and 100): 40
Try lower...
Enter your guess (between 0 and 100): 38
Try higher...
Enter your guess (between 0 and 100): 39
Congratulation!
You got it in 7 trials.
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
number_guess - Number guessing game
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Guess a number between 0 and 99.
This example illustrates while-loop with boolean flag, nested-if, and importing random module.
 
Usage: ./number_guess.py
"""
import random    # Using random.randint()
 
# Set up a secret number between 0 and 99
secret_number = random.randint(0, 99)  # return a random int between [0, 99]
trial_number = 0     # number of trials
done = False         # bool flag for loop control
 
while not(done):
    trial_number += 1
    number_in = (int)(input('Enter your guess (between 0 and 99): '))
    if number_in == secret_number:
        print('Congratulation!')
        print('You got it in {} trials.'.format(trial_number))  # Formatted printing
        done = True
    elif number_in < secret_number:
        print('Try higher...')
    else:
        print('Try lower...')
How It Works
  1. import random (Line 11): We are going to use an external module random's randint() function to generate a secret number. In Python, you need to import the external module before using it.
  2. random.randint(0, 99) (Line 14): Generate a random integer between 0 and 99 (both inclusive).
  3. done = False (Line 16): Python supports a bool type for boolean values of True or False. We will use this boolean flag to control our while-loop.
  4. while-loop (Line 18-28): The syntax is:
    while boolean_test:   # No need for () around the test
        loop_body
  5. nested-if (Line 21-28): The syntax is:
    if boolean_test_1:    # No need for () around the test
        block_1
    elif boolean_test_2:
        block_2
    ......
    else:
        else_block
    Take note that Python supports elif keyword (instead of "else if" in C/C++/Java).

Example magic_number.py - Check if Number Contains a Magic Digit

This example prompts user for a number, and checks if the number contains a magic digit. This example illustrates function, int and str operations. For example,

Enter a number: 123456789
123456789 is a magic number
123456789 is a magic number
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
magic_number - Check if the given number contains a magic digit
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Prompt user for a number, and check if the number contains a magic digit.
 
Usage: ./magic_number.py
"""
def isMagic(number:int, magicDigit:int = 8) -> bool:
    """Check if the given number contains the digit magicDigit.
    Arguments:
    number - positive int only
    magicDigit - single-digit int (default is 8)
    """
    while number > 0:
        # extract and drop each digit
        if number % 10 == magicDigit:
            return True     # break loop
        else:
            number //= 10   # integer division
 
    return False
 
def isMagicStr(numberStr:str, magicDigit:str = '8') -> bool:
    """Check if the given number string contains the magicDigit
    Arguments:
    numberStr - a numeric str
    magicDigit - a single-digit str (default is '8')
    """
    return magicDigit in numberStr  # Use built-in sequence operator 'in'
 
def main():
    """The main function"""
    # Prompt and read input string as int
    numberIn = int(input('Enter a number: '))
 
    # Use isMagic()
    if isMagic(numberIn):
        print('{} is a magic number'.format(numberIn))
    else:
        print('{} is NOT a magic number'.format(numberIn))
 
    #print(isMagic(numberIn));     # default magicDigit=8
    #print(isMagic(numberIn, 0));  # override default

    # Use isMagicStr()
    if isMagicStr(str(numberIn), '9'):    # Try removing str()
        print('{} is a magic number'.format(numberIn))
    else:
        print('{} is NOT a magic number'.format(numberIn))
 
# Run the main function
if __name__ == '__main__':
    main()
How It Works
  1. We implemented two versions of function to check for magic number - an int version (Line 10) and a str version (Line 25) - for academic purpose.
    Function Overloading: Python does not support function overloading, as Python's function parameters do not have a data type. You need to write different versions with different function names.
  2. def isMagic(number:int, magicDigit:int = 8) -> bool: (Line 10): The highlight parts are known as type hint annotations. They are ignored by Python Interpreter, and merely serve as documentation. Python supports default value for function parameter, as in magicDigit (with default value of 8).

Example hex2dec.py - Hexadecimal To Decimal Conversion

This example prompts user for a hexadecimal (hex) string, and prints its decimal equivalent. It illustrates for-loop with index, nested-if, string operation and dictionary (associative array). For example,

Enter a hex string: 1abcd
The decimal equivalent for hex "1abcd" is: 109517
The decimal equivalent for hex "1abcd" using built-in function is: 109517
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
hex2dec - hexadecimal to decimal conversion
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Prompt user for a hex string, and print its decimal equivalent
This example illustrates for-loop with index, nested-if, string operations and dictionary.
 
Usage: ./hex2dec.py
"""
import sys   # Using sys.exit()
 
dec = 0   # Accumulating from each hex digit
dictHex2Dec = {'a': 10, 'b': 11, 'c': 12, 'd': 13, 'e': 14, 'f': 15}  # lookup table for hex to dec
 
# Prompt and read hex string
hexStr = input('Enter a hex string: ')
hexStrLen = len(hexStr)
 
# Process each hex digit from the left (most significant digit)
for hexDigitIdx in range(hexStrLen):    # hexDigitIdx = 0, 1, 2, ..., hexStrlen-1
    hexDigit = hexStr[hexDigitIdx]      # Extract each 1-character string
    hexExpFactor = 16 ** (hexStrLen - 1 - hexDigitIdx)  # ** for power or exponent
    if '1' <= hexDigit <= '9':   # Python supports chain comparison
       dec += int(hexDigit) * hexExpFactor
    elif hexDigit == '0':
       pass   # Need a dummy statement for do nothing
    elif 'A' <= hexDigit <= 'F':
       dec += (ord(hexDigit) - ord('A') + 10) * hexExpFactor  # ord() returns the Unicode number
    elif 'a' <= hexDigit <= 'f':
       dec += dictHex2Dec[hexDigit] * hexExpFactor  # Look up from dictionary
    else:
       print('error: invalid hex string')
       sys.exit(1)   # Return a non-zero value to indicate abnormal termination
 
print('The decimal equivalent for hex "{}" is: {}'.format(hexStr, dec))   # Formatted output
# Using built-in function int(str, radix)
print('The decimal equivalent for hex "{}" using built-in function is: {}'.format(hexStr, int(hexStr, 16)))
How It Works
  1. The conversion formula is: hn-1hn-2...h2h1h0 = hn-1×16n-1 + hn-2×16n-2 + ... + h2×162 + h1×161 + h0×160, where hi ∈ {0-9, A-F, a-f}.
  2. import sys (Line 11): We are going to use external module sys's exit() function to terminate the program for invalid input. In Python, we need to import the module (external library) before using it.
  3. for hexDigitIdx in range(hexStrLen): (Line 21): Python does not support the traditional C-like for-loop with index. It supports only for item in lst loop to iterate through each item in the lst. We use the built-in function range(n) to generate a list [0, 1, 2, ..., n-1], and then iterate through each index in the generated list.
  4. In Python, we can iterate through each character of a string (which is also a sequence) via the for-in loop, e.g.,
    str = 'hello'
    for ch in str:  # Iterate through each character of the str
        print(ch)
    For this example, we cannot use the above as we need the index of the character to perform conversion.
  5. hexDigit = hexStr[hexDigitIdx] (Line 22): In Python, we can use indexing operator str[i] to extract the i-th character. Take note that Python does not support character type, but treats character as a 1-character string.
  6. hexExpFactor = 16 ** (hexStrLen - 1 - hexDigitIdx) (Line 23): Python supports exponent (or power) operator in the form of **. Take note that string index begins from 0, and increases from left-to-right. On the other hand, the hex digit's exponent begins from 0, but increases from right-to-left.
  7. There are 23 cases of 1-character strings for hexDigit, '0'-'9', 'A'-'F', 'a'-'z', and others (error), which can be handled by 5 cases of nested-if as follows:
    1. '1'-'9' (Line 24): we convert the string '1'-'9' to int 1-9 via int() built-in function.
    2. '0' (Line 26): do nothing. In Python, you need to include a dummy statement called pass (Line 27) in the body block.
    3. 'A'-'F' (Line 28): To convert 1-character string 'A'-'F' to int 10-15, we use the ord(ch) built-in function to get the Unicode int of ch, subtract by the base 'A' and add 10.
    4. 'a'-'f' (Line 30): Python supports a data structure called dictionary (or associative array), which contains key-value pairs. We created a dictionary dictHex2Dec (Line 14) to map 'a' to 10, 'b' to 11, and so on. We can then reference the dictionary via dic[key] to retrieve its value (Line 31). Take note that an associative array is similar to an array. An array supports only numeric keys 0, 1, 2, ... but an associative array can support any keys.
    5. Others (Line 32): we use sys.exit(1) to terminate the program. We return a non-zero code to indicate abnormal termination.

Example bin2dec.py - Binary to Decimal Conversion

This example prompts user for a binary string (with input validation), and print its decimal equivalent. For example,

Enter a binary string: 1011001110
The decimal equivalent for binary "1011001110" is: 718
The decimal equivalent for binary "1011001110" using built-in function is: 718
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
bin2dec - binary to decimal conversion
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Prompt user for a binary string, and print its decimal equivalent
 
Usage: ./bin2dec.py
"""
def validate(binStr:str) -> bool:
    """Check if the given binStr is a binary string (containing '0' and '1' only)"""
    for ch in binStr:
        if not(ch == '0' or ch == '1'): return False
 
    return True
 
def convert(binStr:str) -> int:
    """Convert the given validated binStr into its equivalent decimal"""
    dec = 0    # Accumulate from each bit
 
    # Process each bit from the left (most significant digit)
    for bitIdx in range(len(binStr)):  # bitIdx = 0, 1, 2, ..., len()-1
        bit = binStr[bitIdx]
        if bit == '1':
            dec += 2 ** (len(binStr) - 1 - bitIdx)  # ** for power
 
    return dec
 
def main():
    """The main function"""
    # Prompt and read binary string
    binStr = input('Enter a binary string: ')
    if not validate(binStr):
        print('error: invalid binary string "{}"'.format(binStr))
    else:
        print('The decimal equivalent for binary "{}" is: {}'.format(binStr, convert(binStr)))
        # Using built-in function int(str, radix)
        print('The decimal equivalent for binary "{}" using built-in function is: {}'.format(binStr, int(binStr, 2)))
 
# Run the main function
if __name__ == '__main__':
    main()
How It Works
  1. The conversion formula is: bn-1bn-2...b2b1b0 = bn-1×2n-1 + bn-2×2n-2 + ... + b2×22 + b1×21 + b0×20, where bi ∈ {0, 1}
  2. You can use built-in function int(str, radix) to convert a numeric string from the given radix to decimal (Line 38).

Example dec2hex.py - Decimal to Hexadecimal Conversion

This program prompts user for a decimal number, and print its hexadecimal equivalent. For example,

Enter a decimal number: 45678
The hex for decimal 45678 is: B26E
The hex for decimal 45678 using built-in function is: 0xb26e
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
dec2hex - decimal hexadecimal to conversion
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Prompt user for a decimal number, and print its hexadecimal equivalent
 
Usage: ./dec2hex.py
"""
hexStr = ''     # To be accumulated
hexChars = [    # Use this list as lookup table for converting 0-15 to 0-9A-F
    '0','1','2','3', '4','5','6','7', '8','9','A','B', 'C','D','E','F'];
 
# Prompt and read decimal number
dec = int(input('Enter a decimal number: '))    # positive int only
decSave = dec    # We will destroy dec
 
# Repeated modulus/division to get the hex digits in reverse order
while dec > 0:
    hexDigit = dec % 16;    # 0-15
    hexStr = hexChars[hexDigit] + hexStr;  # Append in front corresponds to reverse order
    dec = dec // 16;        # Integer division
 
print('The hex for decimal {} is: {}'.format(decSave, hexStr))   # Formatted output
# Using built-in function hex(decNumber)
print('The hex for decimal {} using built-in function is: {}'.format(decSave, hex(decSave)))
How It Works
  1. We use the modulus/division repeatedly to get the hex digits in reverse order.
  2. We use a look-up list (Line 11) to convert int 0-15 to hex digit 0-9A-F.
  3. You can use built-in function hex(decNumber), oct(decNumber), bin(decNumber) to convert decimal to hexadecimal, octal and binary, respectively; or use the more general format() function. E.g.,
    >>> format(1234, 'x')  # lowercase a-f
    '4d2'
    >>> format(1234, 'X')  # uppercase A-F
    '4D2'
    >>> format(1234, 'o')
    '2322'
    >>> format(1234, 'b')
    '10011010010'
    >>> format(0x4d2, 'b')
    '10011010010'
    >>> hex(1234)
    '0x4d2'
    >>> oct(1234)
    '0o2322'
    >>> bin(1234)
    '0b10011010010'
    
    # Print a string in ASCII code
    >>> str = 'hello'
    >>> ' '.join(format(ord(ch), 'x') for ch in str)
    '68 65 6c 6c 6f'

Example wc.py - Word Count

This example reads a filename from command-line and prints the line, word and character counts (like the wc utility in Unix). It illustrates the text file input and text string processing.

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
wc - word count
~~~~~~~~~~~~~~~
Read a file given in the command-line argument and print the number of
  lines, words and characters - like the UNIX's wc utility.
 
Usage: ./wc.py <filename>
"""
# Check if a filename is given in the command-line arguments using "sys" module
import sys              # Using sys.argv and sys.exit()
if len(sys.argv) != 2:  # Command-line arguments are kept in a list named sys.argv
    print('Usage: ./wc.py <filename>')
    sys.exit(1)         # Return a non-zero value to indicate abnormal termination
 
# You do not need to declare the name and type of variables.
# Variables are created via the initial assignments.
num_words = num_lines = num_chars = 0    # chain assignment
 
# Get input file name from list sys.argv
# sys.argv[0] is the script name, sys.argv[1] is the filename.
with open(sys.argv[1]) as infile:  # 'with-as' closes the file automatically
    for line in infile:            # Process each line (including newline) in a for-in loop
        num_lines += 1             # No ++ operator in Python?!
        num_chars += len(line)
        line = line.strip()        # Remove leading and trailing whitespaces
        words = line.split()       # Split into a list using whitespace as delimiter
        num_words += len(words)
 
# Various ways of printing results
print('Number of Lines is', num_lines)                  # Items separated by blank
print('Number of Words is: {0:5d}'.format(num_words))   # Python 3's new formatting style
print('Number of Characters is: %8.2f' % num_chars)     # Python 2's old formatting style

# Invoke Unix utility 'wc' through shell command for comparison
from subprocess import call     # Python 3
call(['wc', sys.argv[1]])       # Command in a list ['wc', filename]

import os                       # Python 2
os.system('wc ' + sys.argv[1])  # Command is a str 'wc filename'
How It Works
  1. import sys (Line 12): We use the sys module (@ https://docs.python.org/3/library/sys.html) from the Python's standard library to retrieve the command-line arguments kept in list sys.argv, and to terminate the program via sys.exit(). In Python, we need to import the module before using it.
  2. Command-Line Arguments: The command-line arguments are stored in a variable sys.argv, which is a list (Python's dynamic array). The first item of the list sys.argv[0] is the script name, followed by the other command-line arguments.
  3. if len(sys.argv) != 2: (Line 13): We use the built-in function len(list) to verify that the length of the command-line-argument list is 2.
  4. with open(sys.argv[1]) as infile: (Line 23): We open the file via a with-as statement, which closes the file automatically upon exit.
  5. for line in infile: (Line 24): We use a for-in loop to process each line of the infile, where line belong to the built-in class "str" (meant for string support @ https://docs.python.org/3/library/stdtypes.html#str). We use the str class' member functions strip() to strip the leading and trailing white spaces; and split() to split the string into a list of words.
    str.strip([chars])
        # Return a copy of the string with leading and trailing characters removed.
        # The optional argument chars is a string specifying the characters to be removed.
        # Default is whitespaces '\t\n '.
    
    str.split(sep=None, maxsplit=-1)
        # Return a list of the words in the string, using sep as the delimiter string.
        # If maxsplit is given, at most maxsplit splits are done (thus, the list will have at most maxsplit+1 elements).
  6. We also invoke the Unix utility "wc" via external shell command in 2 ways: via subprocess.call() and os.system().

Example htmlescape.py - Escape Reserved HTML Characters

This example reads the input and output filenames from the command-line and replaces the reserved HTML characters by their corresponding HTML entities. It illustrates file input/output and string substitution.

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
htmlescape - Escape the given html file
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Replace the HTML reserved characters by their corresponding HTML entities.
    " will be replaced by &quot;
    & will be replaced by &amp;
    < will be replaced by &lt;
    > will be replaced by &gt;
 
Usage: ./htmlescape.py <infile> <outfile>
"""
import sys    # Using sys.argv and sys.exit()
# Check if infile and outfile are given in the command-line arguments
if len(sys.argv) != 3:
    print('Usage: ./htmlescape.py <infile> <outfile>')
    sys.exit(1)    # Return a non-zero value to indicate abnormal termination
 
# The "with-as" statement closes the files automatically upon exit.
with open(sys.argv[1]) as infile, open(sys.argv[2], 'w') as outfile:
    for line in infile:         # Process each line (including newline)
        line = line.rstrip()    # strip trailing (right) white spaces
 
        # Encode HTML &, <, >, ".  The order of substitution is important!
        line = line.replace('&', '&amp;')    # Need to do first as the rest contain it
        line = line.replace('<', '&lt;')
        line = line.replace('>', '&gt;')
        line = line.replace('"', '&quot;')
        outfile.write('{}\n'.format(line))   # write() does not output newline
How It Works
  1. import sys (Line 14): We import the sys module (@ https://docs.python.org/3/library/sys.html). We retrieve the command-line arguments from the list sys.argv, where sys.argv[0] is the script name; and use sys.exit() (Line 18) to terminate the program.
  2. with open(sys.argv[1]) as infile, open(sys.argv[2], 'w') as outfile: (Line 21): We use the with-as statement, which closes the files automatically upon exit, to open the infile for read (default) and outfile for write ('w').
  3. for line in infile: (Line 22): We use a for-in loop to process each line of the infile, where line belongs to the built-in class "str" (meant for string support @ https://docs.python.org/3/library/stdtypes.html#str). We use str class' member function rstrip() to strip the trailing (right) white spaces; and replace() for substitution.
    str.rstrip([chars])
        # Return a copy of the string with trailing (right) characters removed.
        # The optional argument chars is a string specifying the characters to be removed.
        # Default is whitespaces '\t\n '.
    
    str.replace(old, new[, count])
        # Return a copy of the string with ALL occurrences of substring old replaced by new.
        # If the optional argument count is given, only the first count occurrences are replaced.
  4. Python 3.2 introduces a new html module, with a function escape() to escape HTML reserved characters.
    >>> import html
    >>> html.escape('<p>Test "Escape&"</p>')
    '&lt;p&gt;Test &quot;Escape&amp;&quot;&lt;/p&gt;'

Example files_rename.py - Rename Files

This example renames all the files in the given directory using regular expression (regex). It illustrates directory/file processing (using module os) and regular expression (using module re).

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
files_rename - Rename files in the directory using regex
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Rename all the files in the given directory (default to the current directory)
  matching the regular expression from_regex by to_regex.

Usage: ./files_rename.py <from_regex> <to_regex> [<dir>|.]
Eg. Rename '.txt' to '.bak' in the current directory:
$ ./files_rename.py '\.txt' '.bak'

Eg. Rename files ending with '.txt' to '.bak' in directory '/temp'
$ ./files_rename.py '\.txt$' '.bak' '/temp'

Eg. Rename 0 to 9 with _0 to _9 via back reference (\n) in the current directory:
$ ./files_rename.py '([0-9])' '_\1'
"""
import sys    # Using sys.argv, sys.exit()
import os     # Using os.chdir(), os.listdir(), os.path.isfile(), os.rename()
import re     # Regular expression: using re.sub()

if not(3 <= len(sys.argv) <= 4):    # logical operators are 'and', 'or', 'not'
    print('Usage: ./files_rename.py <from_regex> <to_regex> [<dir>|.]')
    sys.exit(1)    # Return a non-zero value to indicate abnormal termination
 
# Change directory, if given in the command-line argument
if len(sys.argv) == 4:
   dir = sys.argv[3]
   os.chdir(dir)     # change current working directory
 
count = 0    # count of files renamed
for oldFilename in os.listdir():      # list current directory, non-recursive
    if os.path.isfile(oldFilename):   # process file only (not directory)
        newFilename = re.sub(sys.argv[1], sys.argv[2], oldFilename)   # compute the new filename
        if oldFilename != newFilename:
            count += 1
            os.rename(oldFilename, newFilename)      # do the rename
            print(oldFilename, '->', newFilename)    # print changes

print("Number of files renamed:", count)
How It Works
  1. import os (Line 20): We import the os module (for operating system utilities @ https://docs.python.org/3/library/os.html), and use these functions:
    os.listdir(path='.')
        # Return a list containing the names of the entries in the directory given by path.
        # Default is current working directory denoted as '.'
    
    os.path.isfile(path)
        # Return True if path is an existing regular file (not a directory nor link).
        
    os.rename(src, dst, *, src_dir_fd=None, dst_dir_fd=None)
        # Rename the file or directory src to dst.
  2. import re (Line 21): We import the re module (for regular expression @ https://docs.python.org/3/library/re.html), and use this function:
    re.sub(pattern, replacement, string, count=0, flags=0)
        # default count=0 replaces all matches.

 

 

REFERENCES & RESOURCES

  1. The Python's mother site @ www.python.org; "The Python Documentation" @ https://www.python.org/doc/; "The Python Tutorial" @ https://docs.python.org/tutorial/; "The Python Language Reference" @ https://docs.python.org/reference/.
  2. Vernon L. Ceder, "The Quick Python Book", 2nd ed, 2010, Manning (Good starting guide for experience programmers who wish to learning Python).
  3. Mark Lutz, "Learning Python", 4th ed, 2009; "Programming Python", 4th ed, 2011; "Python Pocket Reference", 4th ed, 2010, O'reilly.