Python Explained

Here are my Python essentials for anyone wanting to learn this programming language. This post will be continually updated.

 

My book on Cloud Computing with Amazon. It is only $0.99 and buying it helps support my family and I. Thankyou in advance.

 

Table of Contents

Getting Started With Python

 

Python is one of the most popular programming languages. It is used for a lot of different fields including, science, data analysis, and application development. 

Its commands are processed by an interpreter. 

Most of Python’s keywords are English words that make it easy for beginners to understand. It uses indentation liberally to group statements into blocks of code. This helps in reading and comprehending the code. 

 

Installing Python

For the Windows operating system, you just go to Python’s website and download the executable.

https://python.org/downloads

Follow the instructions and you will soon have a functional Python interpreter installed and working. 

For Linux systems, Python usually comes with the distribution. So, there will usually be nothing to do except update your version. To update your version, just use your package manager to do this. Linux users will understand what this means immediately. If it is not installed, you can use your package manager to install it. Search python3 to find it.

 

Using The Interpreter

The Python interpreter processes text. You type this text in the shell of your operating system or in a text editor.  

You can interact with the Python interpreter a few different ways.

  • In Windows, open CMD and type python
  • In Linux, open a terminal window and type python
  • From the start menu, you can choose Python
  • From the start menu, you can choose the IDLE program 

You can use the interpreter as a calculator with parentheses as needed. 

 

Your First Program

You can type commands and write your first program from this window. A Python program is just a text file with commands in it and saved with the .py extension. It is also a good idea to create a python folder somewhere to save your programs. 

In your interpreter window, we can print some text. That is technically a program but it is what most languages start with. Type:

print(‘I am learning Python’)

Use the menu to save this to your computer. Call it something like ‘learn.py’. Name it whatever you want though, it does not matter. 

You can navigate to the file through your gui and double click it.

You can also navigate to it through your command line. If you do it this way, once you are in the directory where the file is located, just type ‘python learn.py’ to run it.

 

Using Variables

All programming languages have variables. Python is no exception. Variables let you store data. You can then run operations on the variables as needed. Name your variables something meaningful.

life_counter=0

temperature=55

The first part is the variable name followed by an equals sign. After that contains the value of the variable. All variables must be initialized when created. This means they must be assigned a value when they are first created. 

You do not have to specify a data type when creating variables. This is called dynamic typing.

 

Comments

Comments are a universal way for programming languages to document code. They are meant to explain the thoughts behind a statement, the purpose of a block of code, and to make it easier on anyone reading the code at a later date.

You use the # symbol in front of a line of text to make it a comment. 

# The purpose of this variable is to be a counter and keep track of the iterations in a loop

You can do multi-line comments by enclosing text within triple quote marks(“””).

 

User Input

To capture user input, we use the input() function. It will accept a string inside its parentheses. Afterwards, it will prompt the user for input. User input is read as a text string. The text string is then assigned to a variable. 

fav_team=input(‘What is your favorite baseball team? : ‘)

print(fav_team)

 

Errors

There are three types of errors that can occur. They are:

  • Syntax
  • Runtime
  • Semantic

Syntax errors are when you use the Python language incorrectly. An example of this is misspelling a keyword. Runtime errors can happen when you run a program. This can be a lot of different things but generally means something was misused. Semantic errors are not technically errors. The program can still run but you get unexpected results.

 

Overview

The Python language is processed by the interpreter. It is a high level language because it uses English wording. Indentation is used to group statements into blocks. A Python program is just a text file that uses the .py file extension. The print() function outputs the string enclosed within its parentheses. String values are enclosed within quote marks. 

A variable is a container with a name. It stores values and can be used by referencing that variable’s name. Variables can be any data type but they all have to be initialized first with some value. The input() function accepts user input. You can assign this input to a variable to increase your program usefulness. 

 

Python Operations

 

Let us get familiar with python operations and how they are used.

If you have not already, make a new folder at the base of your drive and call it python.

We will store our scripts here in case we need them to expand on a subject.

As in other programming languages, use parentheses to direct the order of operations.

Values in our expressions are called operands.

All the different python operations have an order in which they are performed.

 

Arithmetic

Define some variables:

a=5
b=10

print( a, '+', b, '=', a + b )
5 + 10 = 15

print( a, '-', b, '=', a - b )
5 - 10 = -5

print( a, '*', b, '=', a * b )
5 * 10 = 50

print( b, '/', a, '=', b / a )
10 / 5 = 2.0

print( a, '%', b, '=', a / b )
5 % 10 = 0.5

print( a, '^2 =', a*a, sep = '')
5^2 = 25

The sep character sequence specifies space in the output. We will use it more later.



Assigning Values

There are many ways to assign values in python. There are several ways to assign values because these are shortcuts and save time once you learn them.

 

=

a=b

a=b

+=

a+=b

a=(a+b)

-=

a-=b

a=(a-b)

*=

a*=b

a=(a*b)

/=

a/=b

a=(a/b)

%=

a%=b

a=(a%b)

//=

a//b

a=(a//b)

**=

a**b

a=(a**b)



These operations are efficient to use. It will save you time by learning these shortcuts slowly.

Also, the ‘=’ operator assigns a value to a variable. It does not test equality between two different variables or values.

 

Let us practice these shortcuts with some simple examples.

 

a=10
b=20

print(‘Initializing Variables:\t\t’, ‘a =’ a, ‘\tb =’, b)
a += b

print(‘Addition:\t\t’, ‘a =’, a, ‘(10+20)’)
a -= b

print(‘Subtraction:\t’, ‘a =’, a, ‘(20-10)’)
a *= b

print(‘Multiplication:\t’, ‘a =’, ‘(10*20)’)
a /= b

print(‘’Division:\t’, ‘a =’, a, ‘(20 / 10)’)
a %= b

print(‘Modulo:\t’, ‘a =’, a, ‘(20 % 10)’)

 

Comparing Values

As in math and other languages, there are several operators for comparing values in python. The most commonly used are:



==

Equality

!=

Inequality

>

Greater Than

<

Less Than

>=

Greater Than or Equal To

<=

Less Than or Equal To

  

 

This is logic math. For example, the ‘==’ will compare two operands and return true if both are equal in value. The ‘!=’ operator returns true if two operands are not equal. The ‘>’ operator returns true if the first operator is greater than the second. The ‘<’ operator returns true if the first operator is less than the second.

 

The ‘>=’ operator returns true if the operand is greater than or equal to the second. The ‘<=’ returns true if the operand is less than or equal to the second. 

 

nothing=0
zero=0
one=1
upper= 'A'
lower= 'a'

print('Equality :\t', nothing, '==', zero, nothing == zero)
print('Equality :\t', upper, '==', lower, upper == lower)
print('Inequality :\t', nothing, '!=', one, nothing != one)
print('Greater :\t', nothing, '>', one, nothing > one)
print('Lesser :\t', nothing, '<', one, nothing < one)
print('Greater or Equal To :\t', nothing, '>=', zero, nothing >= zero)
print('Less Than or Equal To :\t', one, '<=', zero, one <= zero)

 

Logic

Logic operators are used a lot in python. They include:

 

and

Logical And

or

Logical Or

not

Logical Not



Logical And will look at two operators and return true if both operands are true.

Logical Or will look at two operators and return true if one of the operands is true.

Logical Not is used with another operand and returns the inverse value of it.

This is called boolean logic.

 

t=True
f=False

print('And Logic:')
print('t and t =', t and t)
print('t and f =', t and f)
print('f and f =', f and f)

print('\nOr Logic:')
print('t or t =', t or t)
print('t or f =', t or f)
print('f or f =', f or f)

print('\nNot Logic:')
print('t =', t, '\tnot t =', not t)
print('f =', f, '\tnot f =', not f)

 

Conditions

Every programming language I have heard of has a way to test conditions to see if they are true or false. Python is no different. You have an expression and if it is true you do a certain action. However, if it is false , you do a different action. It is called the conditional expression. You can use several different operators with the conditional expression.

 

An expression will return a value of some kind. In Python, this is the test expression and up to two actions afterwards. 

 

a=1
b=2

print('\nVariable a is :', 'One' if(a==1) else 'Not One')
print('Variable a is : :', 'Even' if(a%2==0) else 'Odd')

print('\nVariable b is :', 'One' if (b==1) else 'Not One')
print('Variable b is :', 'Even' if (b%2==0) else 'Odd')

max = a if (a>b) else b

print('\nGreater Value Is :', max)

 

Precedence

Operator precedence determines the order in which the interpreter evaluates expressions. You can dictate precedence with certain operators. 

 

a=2
b=4
c=8

print('\nDefault Order :\t', a, '*', c,'+', b, '=', a*c+b)
print('Forced Order :\t', a, '* (',c,'+',b,') =', a*(c+b))

print('\nDefault Order :\t', c, '//', b, '-', a, '=', c//b-a)
print('Forced Order :\t', c,'// (',b,'-', a,')=', c//(b-a))

print('\nDefault Order :\t', c, '%', a, '+', b, '=', c%a+b)
print('Forced Order :\t', c, '% (',a,'+',b,')=', c%(a+b))

print('\nDefault Order :\t', c, '**', a, '+', b, '=', c**a+b)
print('Forced Order :\t', c, '** (',a, '+', b,')=', c**(a+b))

 

Casting Data Types

The most popular data types are string, integer, and float. Data type recognition is especially important when assigning numeric data to variables from user input as it is stored by default as a string data type. The data type of stored values can be easily converted into a different data type using built-in functions. The built-in data type conversion functions return a new object representing the converted value. 

  • int(x) - converts x to an integer whole number
  • float(x) - converts x to a floating-point number
  • str(x) - converts x to a string representation
  • chr(x) - converts x to a character
  • unichr(x) - converts x to a unicode character
  • ord(x) - converts x to its integer value
  • hex(x) - converts x to its hexadecimal value
  • oct(x) - converts integer x to an octal string

The Python built-in type() function can be used  to determine which data type class the value contained in a variable. 

 

a=input('Enter A Number:')
b=input('Now Enter Another Number:')

sum=a+b
print('\nData type sum:', sum, type(sum))

sum=int(a)+int(b)
print('Data type sum:', sum, type(sum))

sum=float(sum)
print('Data type sum:', sum, type(sum))

sum=chr(int(sum))
print('Data type sum:', sum, type(sum))



Manipulating Bits

In computer terms, each byte comprises 8 bits that can each contain a 1 or a 0 to store a binary number, representing decimal values from 0 to 255. It is possible to manipulate individual parts of a byte using the Python bitwise operators listed below:

  • | Or
  • & And
  • ~ Not
  • ^ Xor
  • << Shift left
  • >> Shift right

Unless programming for a device with limited resources, there is seldom a need to utilize bitwise operators, but they can be useful.

 

a=10
b=5
print('a=', a, '\tb=', b)

# 1010 ^ 0101 = 1111 (decimal 15)
a=a^b

# 1111 ^ 0101 = 1010 (decimal10)
b=a^b

# 1111 ^ 1010 = 0101 (decimal 5)
a=a^b

print('a=', a, '\tb=', b)



Arithmetic operators can form expressions with two operands for addition, subtraction, multiplication, division, floor division, modulo, and exponent.

The assignment operator (=) can be combined with an arithmetic operator to perform an arithmetic calculation then assign its result.

Comparison operators can form expressions comparing two operands for equality, inequality, greater, lesser, greater or equal, and lesser or equal values.

Logical (and) and (or) operators  form expressions evaluating two operands  to return a boolean value of true or false.

The logical not operator returns the inverse boolean value of a single operand.

A conditional if-else expression evaluates a given expression for a boolean True or False value, then returns one of two operands depending on the result.

Expressions containing multiple operators will execute their operations in accordance with the default precedence rules unless explicitly determined by the addition of parentheses.

The data type of a variable value can be converted to a different data type by the built-in Python functions int(), float(), and str() to return a new converted object.

Python’s built-in type() function determines to which data type class a specified variable belongs.

Bitwise operators OR, And, Not, and Xor each return a value after comparison of the values within two bits whereas the Shift left and Shift right operators move the bit values a specified number of bits in their direction. 




Statements in Python

 

In Python, a variable must be initialized before it can be used. This is usually done in the statement that uses it. 

More than one variable can be initialized  with the same value using a single statement. 

A = b = d = e = 10

More than one variable can also be initialized to different values using commas in a statement.

A, b, c, = 15, 25, 35

Unlike regular variables, which can only store a single item of data, Python can use a list which can store multiple items of data. The data is stored sequentially in list elements that are index numbered starting at zero. The first value is stored in element zero and goes up from there.

A list is created much like any other variable, but it is initialized by assigning values as a comma-separated list between square brackets.

num=[0,1,2,3,4,5]

An individual list element can be referenced using the list name followed by square brackets containing that element’s index number. This means that num[1] references the second element in the example above, since the first element starts at zero.

Lists can have more than one index to represent multiple dimensions, rather than the single dimension of a regular list. Multi-dimensional lists of three indices and more are uncommon but two-dimensional lists are useful to store grid-based information such as [x,y] coordinates.

A list of string values can even be considered to be a multi-dimensional list, as each is itself a list of characters. Each character can be referenced by its index number within its particular string.

 

quarter=[‘January’, ‘February’, ‘March’]

print(‘First Month:’, quarter[0])

print(‘Second Month:’, quarter[1])

print(‘Third Month:’, quarter[2])

coordinates=[ [1,2,3] , [4,5,6] ]

print(‘\nTop Left 0,0:’, coordinates[0][0] )

print(‘Bottom Right 1,2:’, coordinates[1][2] )

print(‘\nSecond Month First Letter:’, quarter[1][0] )

 

String indices may also be negative numbers. To start counting from the right where -1 references the last letter.

 

Manipulating Lists

List variables can contain multiple items of data. They are widely used in Python and have a number of methods and options.



list.append(x)

Adds item x to the end of the list

list.extend(L)

Adds all items in list L to the end of the list

list.insert(i,x)

Inserts item x at index position i

list.remove(x)

Removes first item x from the list

list.pop(i)

Removes item at index i and returns it 

list.index(x)

Returns the index in the list of first item x

list.count(x)

Returns the number of times x appears in list

list.sort()

Sort all list items, in place

list.reverse()

Reverse all list items, in place

 

Python also has a useful len(L) function that returns the length of the list L as the total number of elements it contains. Like the index() and count() methods, the returned value is numeric so cannot be directly concatenated to a text string for output.

String representation of numeric values can be produced by Python’s str(n) function for concatenation to other strings, which returns a string version of the numeric n value. A string representation of an entire list can be returned by the str(L) function for concatenation to other strings. Remember that the original version remains unchanged as the returned versions are merely copies of the original version.

Individual list elements can be deleted by specifying their index number to the Python del(i) function. This can remove a single element at a specified i index position, or a slice of elements can be removed using slice notation i1:i2 to specify the index number of the first and last element. In this case, i1 is the index number of the first element to be removed and all elements up to, but not including, the element at the i2 index number will be removed.

 

basket=['Apple', 'Bun', 'Cola']

crate=['Egg', 'Fig', 'Grape']

print('Basket List:', basket)

print('Basket Elements:', len(basket))

basket.append('Damson')

print('Appended:', basket)

print('Last Item Removed:', basket.pop())

print('Basket List:', basket)

basket.extend(crate)

print('Extended:', basket)

del basket[1]

print('Item Removed:', basket)

del basket[1:3]

print('Slice Removed:', basket)

 

The last index number in the slice denotes at what point to stop removing elements, but the element at that position does not get removed.

 

Restricting Lists

For a tuple, the values in a regular list can be changed as the program proceeds, but a list can be created with fixed immutable values that cannot be changed by the program. A restrictive immutable Python list is known as a tuple and is created by assigning values as a comma-separated list between parentheses in a process known as tuple packing.

colors-tuple=(‘Red’, ‘Green’, ‘Red’, ‘Blue’, ‘Red’)

An individual tuple element can be referenced using the tuple name followed by square brackets containing that element’s index number. Usefully, all values stored inside a tuple can be assigned to individual variables in a process known as sequence unpacking.

A,b,c,d,e = colors-tuple

For a set, the values in a regular list can be repeated in its elements, as in the tuple above, but a list of unique values can be created where duplication is not allowed. A restrictive Python list of unique values is known as a set and is created by assigning values as a comma-separated list between curly brackets.

phonetic-set={‘Alpha’, ‘Bravo’, ‘Charlie’)

Individual set elements cannot be referenced using the set name followed by square brackets containing an index number, but instead sets have methods that can be dot-suffixed to the set  name for manipulation and comparison. 



set.add(x)

Adds item x to the set

set.update(x,y,z)

Adds multiple items to the set

set.copy()

Returns a copy of the set

set.pop()

Removes one random item from the set

set.discard(x)

Removes item x if found in the set

set1.intersection(set2)

Returns items that appear in both sets

set1.difference(set2)

Returns items in set1 but not in set2

  



zoo=('Kangaroo', 'Leopard', 'Moose',)

print('Tuple:', zoo, '\tLength:', len(zoo))

print(type(zoo))

bag={'Red', 'Green', 'Blue'}

bag.add('Yellow')

print('\nSet:', bag, '\tLength', len(bag))

print(type(bag))

print('\nIs Green in bag Set?:', 'Green' in bag)

print('Is Orange in bag Set?:', 'Orange' in bag)

box={'Red', 'Purple', 'Yellow'}

print('\nSet:', box, '\t\tLength', len(box))

print('Common to both Sets:', bag.intersection(box))



In Python programming a dictionary is a data container that can store multiple items of data as a list of key:value pairs. Unlike regular list container values, which are referenced by their index number, values stored in dictionaries are referenced by their associated key. The key must be unique within that dictionary, and is typically a string name although numbers may be used.

Creating a dictionary is simply a matter of assigning the key:value pairs as a comma-separated list between curly brackets to a name of your choice. Strings must be enclosed within quotes, as usual, and a : colon character must come between the key and its associated value.

A key:value pair can be deleted from a dictionary by specifying the dictionary name and the pair’s key to the del keyword. Conversely, a key:value pair can be added to a dictionary by assigning a value to the dictionary’s name and a new key.

Python dictionaries have a keys() method that can be dot-suffixed to the dictionary name to return a list, in random order, of all the keys in that dictionary. If you prefer the keys to be sorted into alphanumeric order, simply enclose the statement within the parentheses of the Python sorted() function.

A dictionary can be searched to see if it contains a particular key with the Python in operator, using the syntax key “in” dictionary. The search will return a boolean True value when the key is found in the specified dictionary, otherwise it will return false.

Two dictionaries can be merged into one single dictionary using the | merge operator, where dict3=dict1 | dict2. Alternatively, a dictionary can be merged with a second dictionary using the |= update operator, where dict1 |= dict2.

Dictionaries are the final type of data container available in Python. Here are the types again:



Variable

A single value

List

Multiple values in an ordered index

Tuple

Multiple fixed values in a sequence

Set

Unique values in an unordered collection

Dictionary

Multiple unordered key:value pairs

 

user_sys={'name': 'Bob', 'sys': 'Win'}

user_lang={'name': 'Bob', 'lang': 'Python'}

dict=user_sys|user_lang

print('\nDictionary:', dict)

print('\nLanguage:', dict['lang'])

print('\nKeys:', dict.keys())

del dict['name']

dict['user']='Tom'

print('\nDictionary:', dict)

print('\nIs There A Name Key?:', 'name' in dict)

 

Notice the quotes must be preceded by a backslash character within a string to prevent the string being prematurely terminated.

 

Branching in Python

 

The Python if keyword performs the basic conditional test that evaluates a given expression for a boolean value of True or False. This allows a program to proceed in different directions according to the result of a test and it is known as conditional branching.

 

The tested expression must be followed by a :, then statements to be executed when the test succeeds should follow below on separate lines, and each line must be indented from the if test line. The size of the indentation is not important, but it must be the same for each line.

 

If expression

Do this

 

An if test can offer alternative statements to execute when the test fails by appending an else keyword after the statements to be executed when the test succeeds.

 

If expression

Do this

Else:

Alternative expression

 

An if test block can also be followed by an alternative test using the elif keyword (else if) that offers statements to be executed when the alternative test succeeds.

 

If expression

Do this

Elif another expression

Do this instead

Else:

Do this when the above are false

 

Conditional branching can also be performed using a match case block. A value to be evaluated is specified after the match keyword and this is compared to a pattern specified to one or more case statements. Only when the specified value matches a pattern will the statements inside that case block be executed, otherwise the program will simply proceed. A match case block has this syntax:

 

Match value:

Case 1:

Do this

Case 2:

Do this

Case 3:

Do this

 

Indentation of code is very important in Python as it identifies code blocks to the interpreter. The match case block in Python is similar to the switch case block found in other languages.

 

num = int(input(' Please enter a number: '))

if num > 5:

    print(' Number is greater than 5\n ')

elif num < 5:

    print(' Number is less than 5\n ')

else:

    print(' Number is 5\n ')

   cmd = input(' Enter STOP or GO: ').upper()

   match cmd:

        case 'GO':

            print(' Started ')

        case 'STOP':

            print(' Stopped ')

 

The user input is read as a string value by default, so must be cast as an int data type with int() for arithmetical comparison. The match comparison is case-sensitive so the user input is forced to uppercase by the upper() string method before comparison.



Looping

A loop is a piece of code in a program that automatically repeats. One complete execution of all statements within a loop is called an iteration. The length of the loop is controlled by a conditional test made within the loop. While the tested expression is found to be true, the loop will continue. When the tested expression is found to be false the loop ends.

 

In Python programming, the while keyword created a loop. It is followed by the test expression then a : character. Statements to be executed when the test succeeds should follow below on separate lines, and each line must be indented the same space from the while test line. This statement block must include a statement that will at some point change the result of the expression evaluation, otherwise an infinite loop is created. 

 

Indentation of code blocks must also be observed in Python’s interactive mode. Loops can be nested, one within another, to allow complete execution of all iterations of an inner nested loop on each iteration of the outer loop. A counter variable can be initialized with a starting value immediately before each loop definition, included in the test expression, and incremented on each iteration until the test fails, then the loop ends. 

 

Unlike other Python keywords, the keywords True and False begin with uppercase letters. Hit return to move to the next line and see the interpreter automatically indent the new line as it expects further statements. Hit return again to execute the entered code.

 

i = 1

while i <4:

    print( '\nOuter loop iteration: ', i)

    i+=1

    j = 1

    while j <4:

        print( '\nInner loop iteration: ',j)

        j+=1

 

The output printed from the inner loop is indented from that of the outer loop by the \t tab character. The += assignment statement i +=1 is simply a shorthand way to say i=i+1. 

 

Looping Over Items

 

In Python programming, the for keyword loops over all items in any list specified to the in keyword. This statement must end with a : colon character, and statements to be executed on each iteration of the loop must be indented.

 

For each item inlist

Statements to be executed on each iteration

Statements to be executed on each iteration

 

As a string is simply a list of characters, the for in statement can loop over each character. Similarly, a for in statement can loop over each element in a list, each item in a tuple, each member of a set, or each key in a dictionary.

 

A for in loop iterates over the items of any list or string in the order that they appear in the sequence, but you cannot directly specify the number of iterations to make, a halting condition, or the size of iteration step. You can, however, use the Python range() function to iterate over a sequence of numbers by specifying a numeric end value within its parameters. This will generate a sequence that starts at zero and continues up to, but not including, the specified end value. For example, range(5) generates 0,1,2,3,4. 

 

Optionally, you can specify both a start and end value within the parentheses of the range() function, separated by a comma. For example, range(1,5) generates 1,2,3,4. Also, you can specify a start value, end value, and a step value to the range() function as a comma-separated list within its parentheses. For example, range(1,14,4) generates 1,5,9,13. 

 

You can specify the list’s name within the parentheses of Python’s enumerate() function to display each element’s index number and its associated value. 

 

When looping through multiple lists simultaneously, the element values of the same index number in each list can be displayed together by specifying the list names as a comma-separated list within the parentheses of Python’s zip() function. To ensure lists are of equal length, this can include a final strict=true argument. 

 

When looping through a dictionary you can display each key and its associated value using the dictionary items() method and specify two comma-separated variable names to the for keyword, one for the key name and the other for its value. 

 

The range() function can generate  a sequence that decreases, counting down, as well as those that count upward. The for loop in Python is unlike that in other languages, as it does not allow step size and end value to be specified. 

 

chars=[ 'A', 'B', 'C' ]

fruit=( 'Apple', 'Banana', 'Cherry' )

dict={ 'name': 'Mike', 'ref': 'Python', 'sys': 'Win' }

print( '\nElements:\t', end='')

for item in chars:

    print( item, end='')

print( '\nEnumerated:\t', end='')

for item in enumerate( chars ):

    print( item, end='' )

print( '\nZipped:\t', end='' )

for item in zip( chars, fruit, strict=True ):

       print( item, end='' )

print( '\nPaired:' )

for key, value in dict.items():

       print( key, '=', value )

 

In Python programming, anything that contains multiple items that can be looped over is called iterable.

 

Breaking Out of Loops

The Python break keyword can be used to prematurely terminate a loop when a specified condition is met. The break statement is situated inside the loop statement block and is preceded by a test expression. When the test returns True, the loop ends immediately and the program proceeds on to the next task. For example, in a nested inner loop it proceeds to the next iteration of the outer loop.

 

for i in range(1,4):

    for j in range(1,4):

        print( 'Running i=' , i , 'j=' , j )

 

Now, once you see how that runs, we will add a break statement to see how it will affect the previous code.

 

for i in range(1,4):

    for j in range(1,4):

        print( 'Running i=' , i , 'j=' , j )

        if i == 2 and j == 1:

                 print( 'Breaks inner loop at i=2 j=1' )

                 break 

 

The Python continue keyword can be used to skip a single iteration of a loop when a specified condition is met. The continue statement is situated inside the loop statement block and is preceded by a test expression. When the test returns true, that one iteration ends and the program proceeds to the next iteration. 

 

for i in range(1,4):

    for j in range(1,4):

        print( 'Running i=' , i , 'j=' , j )

        if i==1 and j==1:

                    print( 'Continue inner loop at i=1 and j=1' )

                    continue

        if i == 2 and j == 1:

                 print( 'Breaks inner loop at i=2 j=1' )

                 break

 

Here, the break statement halts all three iterations of the inner loop when the outer loop tries to run it the second time. The continue statement just skips the first iteration of the inner loop when the outer loop tries to run it for the first time. 

Scope Of Functions in Python

Most Python programs contain a number of functions that can be called when they are needed. These are custom functions. A custom function is created using the “def” keyword. It stands for definition. You follow it with a function name of your choice and parentheses. You can choose any name for your function except Python keywords. This line must end with a colon character. The statements to be executed whenever the function gets called must appear on lines below and be indented.

 

Def base_steals();

Statement1

Statement2

 

Function statements must be indented from the definition line by the same amount so the Python interpreter can recognize the block.

 

Once the function statements have been executed, program flow resumes at the point directly following the function call. This modularity is very useful in Python programming to isolate  set routines so they can be called upon repeatedly.

 

To create custom functions it is necessary to understand the accessibility scope of variables in a program. Variables created outside functions can be referenced by statements inside functions, so they have global scope. Variables created inside functions cannot be referenced from outside the function in which they have been created, so these have local scope. 

 

The limited accessibility of local variables means that variables of the same name can appear in different functions without conflict. If you want to coerce a local variable to make it accessible elsewhere, it must first be declared with the Python global keyword followed by its name only. 

 

It may subsequently be assigned a value that can be referenced from anywhere in the program. Where a global variable and a local variable have the same name, the function will use the local version. 

 

Avoid using global variables in order to prevent accidental conflict, use only local variables where possible. 

 

global_var=1

def my_vars():

    print('Global Variable:', global_var)

    local_var=2

    print('Local Variable:', local_var)

    global inner_var

    inner_var=3

my_vars()

print('Coerced Global:', inner_var)

 

Arguments To Your Functions

When defining a custom function in Python programming, you can specify an argument name between the function’s parentheses. A value can then be passed to that argument by specifying the value in the parentheses of the call to the function. The function can now use that passed in value during its execution by referencing it via the argument name. For example, defining a function to accept an argument to print out, like this…

 

Def echo(user):
print(‘User:’, user)

 

A call to this function must specify a value to be passed to the argument within its parentheses so it can be printed out:

 

echo(‘YourName’)

 

Multiple arguments can be specified in the function definition by including a comma-separated list of argument names within the function parentheses:

 

Def echo(user, lang, sys):
print(‘User:’, user, ‘Language:’, lang, ‘Platform:’, sys)

 

When calling a function whose definition specifies arguments, the call must include the same number of data values as arguments. For example, to call this example with multiple arguments:

 

echo(‘YourName’, ‘Python’, ‘Windows’)

 

The passed values must appear in the same order as the arguments list unless the caller also specifies the argument names, like this:

 

echo(lang=’Python’, user=’YourName’, sys=’Windows’)

 

Optionally, a default value may be specified in the argument list when defining a function. This will be overridden when the caller specifies a value for that argument, but will be used by the function when no value gets passed by the caller:

 

Def echo(user, lang, sys=’Linux’):
print((‘User:’, user, ‘Language:’, lang, ‘Platform:’, sys)

 

This means you may call the function passing fewer values than the number of arguments specified in the function definition, to use the default argument value, or pass the same number of values as specified arguments to override the default value.

 

Argument naming follows the same conventions as variables and functions. Name arguments the same as variables passed to them to make the data movement obvious.

 

def echo(user, lang, sys):
   print('User:', user, 'Language:', lang, 'Platform:', sys)

echo('YourName', 'Python', 'Windows')

echo(lang='Python', sys='Mac OS', user='Anne')

def mirror(user='Carole', lang='Python'):
   print('\nUser:', user, 'Language:', lang)

mirror()
mirror(lang='Java')
mirror(user='Tony')
mirror('Susan', 'C++')

 

Returning Values

Like Python’s built in str() function, which returns a string representation of the value specified as its argument by the caller, custom functions can also return a value to their caller by using the Python “return” keyword to specify a value to be returned. For example, to return to the caller the total of adding two specified argument values, like this:

 

Def sum(a,b):

Return a+b

 

The returned result may be assigned to a variable by the caller for subsequent use by the program, like this:

 

total=sum(8,4)

print(‘Eight plus four is:’, total)

 

Or the returned result may be used directly in line like this:

 

print(‘Eight plus four is:’, sum(8,4))

 

Typically, a return statement will appear at the very end of a function block to return the final result of executing all statements contained in that function.

 

A return statement may appear earlier in the function block to halt execution of all subsequent statements in that block. This immediately resumes execution of the program at the caller. The return statement may specify a value to be returned to the caller or the value may be omitted. Where no value is specified, a default value of “none” is assumed. Typically, this is used to halt execution of the function statements after a conditional test is found to be “false”. For example, where a passed argument value is below a specified number:

 

Def sum(a,b):

If a<b:

Return

Return a+b

 

In this case, the function will return the default value “none” when the first passed argument value is below five and the final statement will not be executed. Where the function is to perform arithmetic, user input can be validated for integer values with the built-in “isdigit()” function. You can specify a default value for an argument in the function definition.

 

num=input('Enter an integer:')

def square(num):

    if not num.isdigit():

        return 'invalid entry'

    num=int(num)

    return num*num

print(num, 'Squared is:', square(num))

 

Remember that user input is read as a “str” data type so ust be cast into an “int” or a “float” data type for arithmetic.

Callbacks In Python

Callbacks In Python

In Python, a named function is created using the "def" keyword to specify a function name, which can be used to call that function at 
any time in the program to execute the statements it contains. Optionally, the named function can return a value to the caller.

Python also allows an anonymous function to be created using the lambda keyword. 
An anonymous function may only contain a single expression that must always return a value. 

Unlike the usual creation of a function with the "def" keyword, the creation of a function with a lambda keyword returns a function object.
This can be assigned a variable, which can then be used to reference the function at any time in the program to execute the expression it
contains.

The lambda keyword offers the programmer an alternative syntax for the creation of a function. For example:


def square(x):
 return x**2


can alternatively be written as:


square = lambda x:x**2


In either case, the call square(5) returns the result 25 by passing in an integer argument to the function. 
Note that the lambda keyword is followed by an argument without parentheses, and the specified expression does not require the return 
keyword as all functions created with lambda must implicitly return a value.

While the lambda keyword offers an alternative way to create a function, it is mostly used to embed a function within the code.
For instance, callbacks are frequently coded as inline lambda expressions embedded directly in a caller's arguments list.
Instead of being defined with the "def" keyword elsewhere in the program and referenced by name.
For example:


def function_1: statements
def function_2: statements
callbacks = [ function_1, function_2 ]


This can be written as:

callbacks = [ lambda: expression, lambda: expression ]

def function_1(x): return x**2
def function_2(x): return x**3
def function_3(x): return x**4

callbacks = [function_1, function_2, function_3]

print('\nNamed Functions:')
for function in callbacks:print('Result:', function(3))

callbacks = \
[lambda x:x**2, lambda x:x**3, lambda x:x**4]

print('\nAnonymous Functions:')
for function in callbacks:print('Result:', function(3))


Function definitions that contain just one statement can be written on just one line.
The \ backslash character can be used to allow code to continue on the nect line.

Placeholders

The Python "pass" keyword is useful when writing program code as a temporary placeholder that can be inserted into the code at places where further code needs to be
added later. The "pass" keyword is inserted where a statement is required syntactically, but it merely performs a null operation. When it is executed nothing happens and no
code needs to be executed. This allows an incomplete program to be executed for testing by simulating correct syntax so the interpreter does not report errors.


bool = True
if bool:
    print('Python is better than R')
else:
    pass


In loop structures it is important not to confuse the "pass" keyword, which allows the interpreter to process all subsequent statements 
on that iteration, with the "continue" keyword, which skips subsequent statements on that iteration of the loop only.


title = '\nPython is better than R\n'

for char in title:print(char, end = '')

for char in title:
    if char == 'y':
        print('*', end = '')
        continue
    print(char, end = '')

for char in title:
    if char == 'y':
        print('*', end = '')
        pass
    print(char, end = '')


Producing Generators

When a Python function is called, it executes the statements it contains and may return a value specified to the return keyword. After the function ends, control returns
to the caller and the state of the function is not retained. When the function is next called, it will process its statements from start to finish once more.

A Python generator is a special function that returns a generator object to the caller rather than a data value. This retains the state of the function when it was last 
called, so it will continue from that point when next called.

Generator functions are produced by definition just like regular functions, but contain a yield statement. This begins with the Python yield keyword and specifies the
generator object to be returned to the caller. When the yield statement gets executed, the state of the generator object is frozen, and the current value in its expression 
list is retained. The generator object returned by the yield statement can be conveniently assigned to a variable. Python's built-in "next()" function can then specify that
variable name within its parentheses to continue execution of the function from the point at which it was frozen, exactly as if the yield statement were just another external call.

Repeatedly calling the generator object with the "next()" function continues execution of the function until it raises an exception. This can be avoided by enclosing the
yield statement within an infinite loop so it will return successive values on each iteration.


def fibonacci_generator():
    a=b=1

    while True:
        yield a
        a,b=b,a+b

fib=fibonacci_generator()

for i in fib:
    if i > 100:
        break
    else:
        print('Generated:',i)


In the above script, the variables are initialized with a common value in a single statement.
You can use the inbuilt "type()" function to confirm the object type. here, the type(fib) is confirmed as a generator class object. 

Exceptions in Python

Exceptions
Sections of a python script in which it is possible to anticipate errors, such
as those handling user input, can be enclosed in a "try except" block to handle
exception errors. The statements to be executed are grouped in a try : block,
and exceptions are passed to the ensuing except : block for handling.
Optionally, this may be followed by a finally : block containing statements to
be executed after exceptions have been handled.

Python recognizes many built in exceptions such as the nameError, which occurs
when a variable name is not found, the indexError, which occurs when trying to
address a non-existent list index, and the ValueError, which occurs when a
built-in operation or function receives an argument that has an inappropriate
value.

Each exception returns a descriptive message that can be assigned to a variable
with the "as" keyword. This can be used to display the nature of the exception
when it occurs.


title='Princeton Companion To Mathematics'

try:
    print(titel)

except NameError as msg:
    print(msg)

 

Run that and you can see how the error will get handled.

Multiple exceptions can be handled by specifying their type as a comma-separated
list in parentheses within the except block.

You can also make the interpreter report an exception by using the raise keyword
to specify the type of exception to be recognized and a custom descriptive
message in parentheses.



day=32
try:
    if day > 31 :
        raise ValueError('invalid day number')

except ValueError as msg:
    print('the program found AN', msg)

finally :
    print('but today is beautiful anyway')

Statements in the try block are all executed unless or until an exception
occurs.

Assertions
When tracking down errors in your code it is often useful to comment out one or
more lines of code by prefixing each line with the hash character. The Python
interpreter will then omit execution of those lines to help localize where a
problem lies. 

Another useful debugging technique employs the Python assert keyword to add
error-checking code to your script. This examines a specified test expression
for a boolean True or False result, and reports an AssertionError when the test
fails. Optionally, an assert statement can include a descriptive message to
supply when reporting an AssertionError.

When the test expression fails, the interpreter reports the AssertionError and
halts execution of the script, but when the test succeeds, the assert statement
does nothing, and execution of the script continues.

Employing assert statements is an effective way to document your script, as
their descriptive messages provide commentary and their tests alert you when
your code is erroneous.

Assert versus Exception
At first glance, an AssertionError can appear confusingly similar to an
exception, but it is important to recognize their distinctions:
1. Expections provide a way to handle errors that may legitimately occur at
   runtime.
2. AssertionErrors provide a way to alert the programmer to mistakes during
   development.

Typically, assert statements will be removed from release versions of a program
after debugging is complete, whereas except statements will remain to handle
runtime errors. You can have the interpreter ig nore all assert statements using
a -o switch in the run command, for example, python -O assert.py



chars=['alpha', 'beta', 'gamma', 'delta', 'epsilon']

def display(elem):
    assert type(elem) is int, 'argument must be integer'
    print('list element', elem, '=', chars[elem])

elem=4
display(elem)

elem=elem/2
display(elem)

This AssertionError occurs because the division operation returns a float value,
not an integer value.

Functions are defined using the def keyword, and contain indented statements to
execute when the function gets called.
Variables with global scope can be referenced from anywhere, but variables with
local scope can only be referenced from within the function in which they are
declared.
Arguments are declared as a comma-separated list within the parentheses of a
function definition.
Function calls must supply data for each function argument unless a default
value is specified in their declarations.
Optionally, a function can include a return statement to return a value to the
caller.
An anonymous function containing a single expression is created with the lambda
keytword, and returns a function object. 
Callbacks are frequently coded as inline lambda expressions embeded directly in
a caller's argument list.

Placeholders can be created by inserting the pass keyword where a statement is
required syntactically.
A generator function is created when a statement using the yield keyword appears
in its function block.
Generator functions retain the state of the function when last called, and
return a generator object to the caller.
The built in next() function can be used to continue execution of a generator
function from the point where it was frozen.
Anticipated runtime exception errors can be handled by enclosing statements in a
try except block.
Optionally, a finally statement can be used to specify statements to be executed
after exceptions have been handled.
Error-checking code can be added to scripts using the assert keyword to report
development errors.

Using Modules in Python

 

Storing Functions
Python function definitions can be stored in one or more separate files for
easier maintenance and to allow them to be used in several programs without
copying the definitions into each one. Each file storing function definitions is
called a module and the module name is the file name without the .py extension.

Functions stored in the module are made available to a program using the python
import keyword followed by the module name. Although not essential, it is
customary to put any import statements at the beginning of the program.

Imported functions can be called using their name dot-suffixed after the module
name. Where functions stored in a module include arguments, it is often useful
to assign a default value to the argument in the definition. This makes the
function more versatile, as it becomes optional for the call to specify an
argument value.

You can create an alias when importing a module using "import as" keywords. For
example, import pokemon as darkrai allows you to use darkrai as the function
prefix in function calls. 

Function Names
Internally, each python module and program has its own symbol table that is used
by all functions defined in that context only. This avoids possible conflicts
with functions of the same name in another module if both modules were imported
into one program. Where you import individual function names, the module name
does not get imported, so it cannot be used as a prefix.

When you import a module with an import statement, that module's symbol table
does not get added to the program's table, only the module's name gets added.
That is why you need to call the module's functions using their module name
prefix.

Generally, it is prefarable to avoid conflicts by importing the module name and
calling its functions with the module name prefix, but you can import individual
function names instead with a from import statement. the module name is
specified after the from keyword, and functions to import are specified as a
comma-separated list after the import keyword. Alternatively, the * wildcard
character can be specified after import to import all function names into the
program's own symbol table. This means the functions can be called without a
module name prefix. 

For larger programs, you can import modules into other modules to build a module
hierarchy.

System Queries
Python includes "sys" and "keyword" modules that are useful for querrying the
python system itself. The keyword module contains a list of all python leywords
in its "kwlist" attribute, and provides an "iskeyword()" mothod if you want to
test a word.

You can explore the many features of the "sys" module, and indeed any feature of
python, using the interactive mode help system. Just type "help()" at the ">>>"
prompt to start the help system, then type "sys" at the "help>" prompt that
appears.

Perhaps most usefully, the "sys" module has attributes that contain the python
version number, interpreter location on your system, and a list of all
directories where the interpreter seeks module files, so if you save module
files in any of these directories you can be sure the interpreter will find
them.



import sys, keyword
print("Python Version: ", sys.version)
print("Python interpreter location:", sys.executable)
print("Python module Search path:")
for dir in sys.path:
    print(dir)
print("Python Keywords:")
for word in keyword.kwlist:
    print(word)

The first item on the python search path is your current directory, so any file
within there, or within any subdirectories you make there, will be found by the
python interpreter. 

Mathematical Operations
Python includes a math module that provides lots of methods you can use to
perform mathematical procedures once imported.

The "math.ceil()" and "math.floor()" methods enable a program to perform
rounding of a floating point value specified between their parentheses to the
closest integer. "Math.ceil()" rounds up and "math.floor()" rounds down but the
value returned, although an integer, is a float data type rather than an int data
type.

The "math.pow()" method requires two arguments to raise a specified value by a
specified power. The "math.sqrt()" method simply requires a single argument and
returns a square root of that specified value. Both method results are returned
as a numeric value of the float data type.

Typical trigonometry can be performed using methods from the math module too,
such as "math.sin()", "math.cosin()", and "math.tan()". Python also includes a
random module that can be used to produce pseudo random numbers once imported
into a program. 

The random.random() method produces a single floating point number between zero
and 1.0. The random.sample() method produces a list of elements selected at
random from a sequence. This method requires two arguments to specify the
sequence to select from, and the length of the list to be produced. As the
range() function returns a sequence of numbers, this can be used to specify a
sequence as the first argument to the random.sample() method, so it will
randomly select numbers from that sequence to produce a list in which no numbers
repeat. 

Integers can be cast from the int data type to the float data type using the
float() function and to the string data type using the str() function.



import math, random
print("Rounding up 6.6:", math.ceil(6.6))
print("Rounding down 3.3:", math.floor(3.3))
num=9
print(num, "Squared:", math.pow(num,2))
print(num, "Square Root:", math.sqrt(num))
numbers=random.sample(range(1,69),6)
print("The random numbers selected are:", numbers)

All the math methods here return floating point numbers of the float data type.
The list produced by random.sample() does not actually replace elements of the
sequence but merely copies a sample, as its name says.

Calculating Decimals
Python programs that attempt floating-point arithmetic can produce unexpected
and inaccurate results because the floating-point numbers cannot accurately
represent all decimal numbers.



book=14.99
rate=1.35
tax=book*rate
total=book+tax
print("item:\t", "%.2f" % book)
print("Tax:\t", "%.2f" % tax)
print("Total:\t", "%.2f" % total)

Here, the variable values are formatted using a string substitution technique to
show two decimal places.

To help understand this problem, edit all three print statements to display the
variable values expanded to 20 decimal places, then run the program again.



book=14.99
rate=1.35
tax=book*rate
total=book+tax
print("item:\t", "%.20f" % book)
print("Tax:\t", "%.20f" % tax)
print("Total:\t", "%.20f" % total)

It is now clear that the tax value is represented numerically slightly below
0.735, so gets rounded down to 0.73. Conversely, the total value is represented
numerically slightly above 1.435, so gets rounded up to 1.44, creating the
apparent addition error.

Erros in floating-point arithmetic can be avoided by using python's decimal
module. This provides a decimal() object with which floating-point numbers can
be more accurately represented.

Add a statement at the beginning of the program to import the decimal module to
make all features available from decimal import *. Then, edit the first two
variable assignments to objects:
book=Decimal(14.99)
rate=Decimal(1.35)
Now run the program again to see the difference.



from decimal import *
book=Decimal(14.99)
rate=Decimal(1.35)
tax=book*rate
total=book+tax
print("item:\t", "%.2f" % book)
print("Tax:\t", "%.2f" % tax)
print("Total:\t", "%.2f" % total)

Always use the decimal() object to calculate monetary values or anywhere that
accuracy is essential.

Working with Time
The python datetime module can be imported into a program to make use of times
and dates. It provides a datetime object with attributes of year, month, day,
hour, minute, second, and microsecond.

A datetime object has a today() method that assigns the current date and time
values to its attributes and returns them in a tuple. It also has a getattr()
method that requires two arguments specifying the datetime object name and
attribute to retrieve. Alternatively, the attributes can be referenced using dor
notation such as datetime.year.

All values in a datetime object are stored as numeric values but can be
transformed into text equivalents using its strftime() method. This requires a
single string argument that is a directive specifying which part of the tuple to
return and in what format. The possible directives are listed below.

%A    Full weekday name
%B    Full month name
%c    Date and time appropriate for locale
%d    Day of the month
%f    Microsecond number 0-999999
%H    Hour number 0-23
%I    Hour number 1-12
%j    Day of the year number 0-366
%m    Month number 1-12
%M    Minute number 0-59
%p    AM or PM equivalent for locale
%S    Second number 0-59
%w    Week day number 0-6
%W    Week of the year number 0-53
%X    Time appropriate for locale
%Y    Year 0001-9999
%z    timezone offset from UTC
%Z    Timezone name

Make a new script and run this code to see how date objects are handled.
from datetime import *

today=datetime.today()
print("Today is : ", today)

for attr in ["year","month","day","minute","second","microsecond"]:
    print(attr, ":\t", getattr(today,attr))

print("Time :", today.hour, ":", today.minute, sep='')

day=today.strftime("%A")
month=today.strftime("%B")

As the datetime object is in a module of the same name, simply importing the
module means it would be referenced as datetime.datetime. Use from datetime
import * so it can be referenced just as datetime.

As the strftime() method requires a string argument, the directive must be
enclosed between quote marks.

You can assign new values to attributes of a datetime object using its replace()
method, such as today=today.repalce(year=2023).

Using Timers
Getting the current time both before and after an event means that the duration
of the event can be calculated by their difference. The python time module can
be imported into a program to provide various time-related functions.

Current system time is usually counted as the number of seconds elapsed since
the Epoch at 00:00:00 GMT on January 1, 1970. The time module's time() method
returns the current time in seconds since the Epoch as a floating point number
when called.

The figure returned by the time() method can be converted into a struct_time
object using gmtime() or localtime() methods. This object has attributes of
tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, and
tm_isdst that can be referenced using dot notation. For example, struct.tm_wday.

All values in a struct_time object are stored as numeric values but can be
transformed into text equivalents using the strftime() method. This requires an
argument that is a format directive followed by the name of the struct_time
object. The possible directives include those listed in the table. For example,
strftime("%A",struct) for weekday.

The time module also provides a sleep() method that can be used to pause
execution of a program. Its argument specifies the amount of time in seconds by
which to delay execution.

The gmtime() method converts elapsed time from the Epoch to a struct_time object
at UTC with daylight savings time always set to zero, whereas localtime()
converts to a struct_time object at your local system time.

Here is an example script you can try:
from time import *

start_timer = time()
struct = localtime(start_timer)

print("\nStarting Countdown At:", strftime("%X",struct))


i=10
while i > -1:
    print(i)
    i =i-1
    sleep(1)

end_timer = time()
difference = round(end_timer - start_timer)

print("\nRuntime:", difference, "Seconds")



The argument to the sleep() method may be a floating point number to indicate a
more precise sleep pause time. Do not confuse the time.strftime() method used
here with the datetime.strftime() method used earlier.

Patterns
The python "re" module can be imported into a program to make use of regular
expression patterns that describe a particular string of characters. Regular
expressions are useful for text validation and for search and replace operations
within text by matching their specified pattern to a section of the text. 

A regular expression pattern may consist entirely of literal characters
describing a character string to match within some text. For example, the
regular expression wind finds a match in windows, the pattern literally matches
the string in the text. More typically, a regular expression pattern consists of
a combination of literal characters and these metacharacters. 

.        any characters                py..on
^        first characters            ^py
*        zero or more repetitions    py*
+        one or more repetitions        py+
?        zero or one repetition        py?
{}        multiple repetitions        a{3}
[]        character class                [a-z]
\        special sequence            \s
|        either optional character    a|b
()        expression group            (...)

A combination of literals and metacharacters defining a pattern to be matched
can be specified to the re.comile() method to return a pattern object. This
object has a match() method to specify a string within its parentheses to
compare against the pattern.

When a match() comparison succeeds, a match object is returned containing
information about the match, otherwise a None value is returned when the
comparison fails.

A match object has start() and end() methods, which return the position of the
match, and a group() method that returns the string matched by the comparison.

Run this script to see examples of regular expresisons.

from re import *
pattern=compile('(^|\s)[-a-z0-9_.]+@([-a-z0-9]+\.)+[a-z]{2,6}(\s|$)')
def get_address():
    address=input('Enter Email Address:')
    is_valid=pattern.match(address)
    if is_valid:
        print('Valid Address:', is_valid.group())
    else:
        print('Invalid address \n')
get_address()

Summary
Functions can be stored in modules that are named as the file name without the
.py file extension.

An import statement makes module functions available in a program by
dot-suffixing their name after the module name.

A from import statement makes module functions available in a program without
the need to dot-suffix their name.

The sys module has attributes that contain the python version number,
interpreter location, and path to search for modules.

The keyword module has a kwlist attribute that contains a list of all current
python keywords.

The math module provides methods to perform mathematical procedures such as
math.ceil() and math.floor().

The random module provides a random() method that produces pseudo random
numbers and a sample() method that produces a list of elements selected at
random from a sequence.

The decimal module provides a datetime object with year, month, day, hour,
minute, second, and microsecond attributes that can be referenced by
dot-suffixing or with the getattr() method.

A datetime object has a strftime() method that can specify a directive to
return a formatted part of the object.

The time module provides a time() method that returns the current elapsed time
in seconds since the Epoch.

The gmtime() and localtime() methods return a struct_time object that has
attributes containing date and time components.

The re module provides a compile() method to create a regular expression
pattern and a match() method to compare a pattern to a specified string.

Using Strings

Manipulating Strings
Strings can be manipulated in a program using the various operators that are
available in python.

+        concatenate - join strings together
*        repeat - multiply the string
[]        slice - select a character at a specified index position
[:]        range slice - select characters in a specified index range
in        membership exclusive - return True if character exists in the string
not in    membership exclusive - return True if character doesn't exist in string
r/R        raw string - suppress meaning of escape characters
''' '''    docstring - describe a module, function, class, or method

The [] slice operator and [:] range slice operator recognize that a string is
simply a list containing an individual character within each element, which can
be referenced by their index number.

Similarly, the in and not in membership operators iterate through each element
seeking to match the specified character.

The raw string operator, r, must be placed immediately before the opening quote
mark to suppress escape characters in the string, and is useful when the string
contains the backslash character.

A docstring is a descriptive string literal that occurs as the first statement
in a module, a function, a class, or a method definition. This should be
enclosed within triple single quote marks. Uniquely, the docstring becomes the
_doc_ special attribute of that object, so can be referenced using its name and
dot-suffixing. All modules should normally have docstrings, and all functions
and classes exported by a module should also have docstrings.

The membership operators performa case-sensitive match, so A in abc will fail.
The range slice returns the string up to, but not including, the final specified
index position.

def display(s):
    '''Display an argument value.'''
    print(s)
display(display.__doc__)
display(r'home\jason')
display('\nHello' + ' Andromeda')
display('C++ is cool, too!\n'[0:11])
display('C' in 'C++')
display('r' in 'Andromeda')

The doc keyword is preceded by 2 underscores and followed by 2 underscores.
Remember that strings must be enclosed within either single quote marks or
double quote marks. With range slice, if the start index number is omitted, zero
is assumed, and if the end index number is omitted, the string length is
assumed.

Formatting Strings
The python built-in dir() function can be useful to examine the names of
functions and variables defined in a module by specifying the module name within
its parentheses. Interactive mode can easily be used for this purpose by
importing the module name then calling the dir() function. 

Any defined names that begin and end with a double underscore are python
objects, whereas the others are programmer-defined. The __builtins__ module can
also be examined using the dir() function, to examine the names of functions and
variables defined by default, such as the print() function and a str object.

The str object defines several useful methods for string formatting, including
an actual format() method that performs replacements. A string to be formatted
by the format() method can contain both text and replacement fields marking
places where text is to be inserted from an ordered comma-separated list of
values. Each replacement field is denoted by {} braces, which may, optionally,
contain the index number position of the replacement in the list.

Strings may also be formatted using the C-style %s substitution operator to mark
places in a string where text is to be inserted from a comma-separated ordered
list of values.

book='{} and {}'.format('Chemistry', 'Electronics')
print('\nReplaced:', book)
book='{1} and {0}'.format('Chemistry', 'Electronics')
print('Replaced:', book)
book='%s and %s' %('Calculus', 'Proofs')
print('\nSubstituted:', book)

You cannot leave spaces around the index number in the replacement field. Other
data types can be substituted using %d for a decimal integer, and %f for a
floating-point number.

Modifying Strings


The python "str" object has many useful methods that can be dot-suffixed to its
name for modification of the string and to examine its contents. The most
commonly used string modification methods are listed below.

capitalize()        change string's first letter to uppercase
title()             change all first letters to uppercase
upper()             change the case of all letters to uppercase
lower()             change the case of all letters to lowercase
swapcase()          change to the inverse of the current case
removeprefix(sub)   remove substring from start of string
removesuffix(sub)   remove substring from end of string
join (seq)          merge into string into separator sequence
lstrip()            remove leading whitespace, trailing
rstrip()            remove trailing whitespace
strip(0)            remove leading and trailing whitespace
replace(old,new)    replace all occurrencies of old with new
ljust(w,c)          pad string to left to total column width by c
rjust(w,c)          pad string to right to total column width by c
center(w,c)         pad string each side to total column width by c
count(sub)          return the number of occurrences by sub
find(sub)           return the index number of the first occurrence of
                    sub
startswith(sub)     return true if sub is found at start
endswith(sub)       return true if sub is found at end
isalpha()           return true if all characters are letters only
isnumeric()         return true if all characters are numeric only
isalnum()           return true if letters or numbers only
islower()           return true if string characters are lowercase
isupper()           return true if string characters are uppercase
istitle()           return true if all first letters are uppercase
isspace()           return true if string contains only whitespace 
isdigit()           return true if string contains only digits
isdecimal()         return true if string contains only decimals

A space character is not alphanumeric so isalnum() returns false when examining
strings that contains spaces.

string = "age of mythology is a great game"
print("\nCapitalized:\t", string.capitalize())
print("\nTitled:\t\t", string.title())
print("\nCentered:\t", string.center(30,'*'))
print("\nUppercase:\t", string.upper())
print("\nJoined:\t\t", string.join('**'))
print("\njustified:\t", string.rjust(30,'*'))
print("\nReplaced:\t", string.replace('s', '*'))
 
With the rjust() method a right justified string gets padding added to
its left, and with the ljust() method a left justified string gets
padding added to its right.

Converting Strings
Before python 3.0, string characters were stored by their ascii numeric
code values in the range 0-127, representing only unaccented latin
characters. For example, the lowercase letter 'a' is assigned 97 as its
ascii code value. Each byte of computer memory can store values in the
range 0-255 but this is still too limited to represent all accented
characters and non-Latin characters. 

For example, accented characters used in Western Europe and the
cyrillic alphabet used for Russian cannot be represented in the range
128-255 because there are more than 127 such characters. Recent
versions of python overcome this limitation by storing string
characters as their unicode code point value to represent all
characters and alphabets in the numeric range 0-1,114,112. Characters
that are above the ascii range may require two bytes for their code
point value. 

The str object's encode() method can be used to convert from the
default unicode encoding, and its decode() method can be used to
convert back to the unicode default encoding. Python's unicodedata
module provides a name() method that reveals the unicode name of each
character. Accented and non-Latin characters can be referenced by
their unicode name or by decoding their unicode hexidecimal point
value.

The term ascii is an acronym for american standard code for
information interchange. You can use the character map app in Windows
accessories to select non-ascii characters. A string containing byte
addresses must be immediately prefixed by a 'b' to denote that string
as a byte literal. unicode names are uppercase and referenced by
inclusion between {} braces prefixed by a \N in this notation format.

Accessing Files

Accessing Files
The _builtins_ module can be examined using the "dir()" function to reveal that
it contains a file object that defines several methods for working with files,
including "open()", "read()", "write()", and "close()".

Before a file can be read or written, it must always be opened using the
"open()" method. This requires two string arguments to specify the name and
location of the file, and one of the following "mode" specifiers in which to
open the file:

r       open an existing file to read
w       open an existing file to write
a       Append text and opens/creates a text file for writing at the end of the
        file
r+      open a text file to read from or write to
w+      open a text file to write to or read from
a+      open or creates a text file to read from or write to at the end of the
        file

Where the mode includes  "b" after any of the file modes listed above, the
operation relates to a binary file rather than a text file: rb or w+b

Once a file is opened and you have a file object, you can get various details
related to that file from its properties.

name        name of the opened file
mode        mode in which the file was opened
closed      status boolean value of True or False
writeable() write permission boolean value of True or False

File mode arguments are string values so must be surrounded by quotes. You can
also use a "readlines()" method that returns a list of all lines.

file = open('document.txt', 'w')

print('File Name:', file.name)
print('File Open mode:', file.mode)

print('Readable:', file.readable())
print('Writable:', file.writable())

def get_status(f):
    if (f.closed != False):
        return 'Closed'
    else:
        return 'Open'
        
print('File Status:', get_status(file))
file.close()
print('\nfile Status:', get_status(file))

If your program tries to open a non-existant file in "r" mode, the interpreter
will report an error.

Reading and Writing Files
Once a file has been successfully opened it can be read or added to, or new text
can be written in the file, depending on the mode, specified in the call to the
open() method. Following this, the open file must then always be closed by
calling the close() method.

As you might expect, the read() method returns the entire content of the file,
and the write() method adds content to the file. You can quickly read the entire
contents in a loop, iterating line by line. Writing to an existing file will
automatically overwrite its contents. 

LaTeX =  "LaTeX is used to add math to the web\n"
LaTeX += "Fractions are made using this notation: \\frac[4}{5}\n"
LaTeX += "Exponents are made by: a^{4n}\n"
LaTeX += "Subscripts are made by: a_{4n}\n"

file = open('LaTeX.txt', 'w')
file.write(LaTeX)
file.close()
file = open('LaTeX.txt', 'r')

for line in file:
    print(line, end = '')
file.close()

Suppress the default newline provided by the print() function where the strings
themselves contain newlines. You can also use the obkect's readlines() method
that returns a list of all lines in a file - one line per element.

Updating File Strings
A file object's read() method will, by default, read the entire contents of the
file from the very beginning, at index position zero, to the very end - at the
index position of the final character. Optionally, the read() method can accept
an integer argument to specify how many characters it should read.

The position within the file, from which to read or at which to write, can be
finely controlled using the file object's seek() method. This accepts an integer
argument specifying how many characters to move position as an offset from the
start of the file.

The current position within the file can be discovered at any time by calling
the file object's tell() method to return an integer location.

When working with file objects it is good practice to use the Python "with"
keyword to group the file operational statements within a block. This technique
ensures that the file is properly closed after operations end, even if an
exception is raised on the way, and is much shorter than writing equivalent "try
except" blocks.

Storing Data
In Python, string data can easily be stored in text files using the
techniques demonstrated in the previous examples. Other data types, such as
numbers, lists, or dictionaries, could also be stored in text file but would
require conversion to strings first. Restoring that stored data to their
original data type on retrieval would require another conversion. An easier
way to achieve data persistence of any data object is provided by the pickle
method.

The process of pickling objects stores a string representation of an object that
can later be unpickled to its former state, and is a very common Python
programming procedure.

An object can be converted for storage in a file by specifying the object and
file as arguments to the pickle object's dump() method. It can later be restored
from that file by specifying the file name as the sole argument to the pickle
obkect's load() method.

Unless the storage file needs to be human readable for some reason, it is more
efficient to use a machine readable binary file.

Where the program needs to check for the existence of a storage file, the "os"
module provides a path object with an isfile() method that returns True if a
file is specified within its parentheses is found.

import pickle, os
if not os.path.isfile('pickle.dat'):
    data = [0,1]
    data[0] = input('Enter Topic:')
    data[1] = input('Enter Series:')
    file = open('pickle.dat', 'wb')
    pickle.dump(data,file)
    file.close()
else:
    file = open('pickle.dat', 'rb')
    data = pickle.load(file)
    file.close()
    print('\nWelcome Back To:', data[0], data[1])

Encapsulating Data

A class is a specified prototype describing a set of properties that
characterize an object. Each class has a data structure that can contain both
functions and variables to characterize the object.
 
The properties of a class are referred to as its data members. Class function
members are known as its methods, and class variable members are known as its
attributes.
 
Class members can be referenced throughout a program using dot notation,
suffixing the member name after the class name, with syntax of
class-name.method-() or class-name.attribute-name.
 
A class declaration begins with the class keyword, followed by a
programmer-specified name then a colon. Next, indented statements optionally
specifying a class document string, class variable attribute declarations, and
class method definitions, so the class block syntax looks like this:
 
class ClassName:
'''class-documentation-string'''
class-variable-declarations
class-method-definitions
 
The class declaration, which specifies its attributes and methods, is a
blueprint from which working copies can be made.
 
All variables declared within method definitions are known as instance variables
and are only available locally within the method in which they are declared.
They cannot be directly referenced outside the class structure.
 
Typically, instance variables contain data passed by the caller when an instance
copy of the class is created. As this data is only available locally for
internal use, it is effectively hidden from the rest of the program. This
technique of data encapsulation ensures that data is securely stored within the
class structure and is the first principle of object oriented programming.
 
All properties of a class are referenced internally by the dot notation prefix
self-so an attribute named sound is self.sound. Additionally, all method
definitions in a class must have self as their first argument, so a method named
talk is talk(self).
 
When a class instance is created, a special _init_(self) method is automatically
called. Subsequent arguments can be added in its parentheses if values are to be
passed to initialize its attributes.
 
It is conventional to begin class names with an uppercase character, and object
names with lowercase. The class documentation string can be accessed via the
special__doc__ docstring attribute with Classname__doc__. While a program class
cannot perfectly emulate a real-world object, the aim is to encapsulate all
relevant attributes and actions.
 
Objects
An instance of a class object is simply a copy of the prototype created by
calling that class name's constructor and specifying the required number of
arguments within its parentheses. The call's arguments must match those
specified by the __init__() method definition, other than a value for the
internal self argument.
 
The class instance object returned by the constructor is assigned to a variable
using the syntax instance-name=ClassName(args).
 
Dot notation can be used to reference the methods and class variable attributes
of an instance object by suffixing their name as instance-name.method-name() or
instance-name.attribute.name.
 
Typically, a base class can be defined as a python module file so it can be
imported into other scripts where instance objects can be easily created from
the master class prototype.
 
A constructor creates an instance of a class and is simply the class name
followed by parentheses containing any required argument values. You must not
pass an argument value for the self argument, as this is automatically
incorporated by python.
 
Class Attributes
An attribute of a class can be added, modified, or removed at any time using dot
notation to address the attribute. Making a statement that assigns a value to an
attribute will update the value contained within an existing attribute or create
a new attribute of the specified name containing the assigned value:
instance-name.attribute-name=value
del instance-name.attribute-name
 
Alternatively, you can use the following built in function to add, modify, or
remove an instance variable:
getattr(instance-name, 'attribute-name') - return the attribute value of the
class instance.
 
  • hasattr(instance-name, 'attribute-name') - return True if the attribute value
  • exists in the instance, otherwise return False.
  • setattr(instance-name, 'attribute-name', value) - update the existing attribute
  • value or create a new attribute in the instance.
  • delattr(instance-name, 'attribute-name') - remove the attribute from the
  • instance.
 
The name of attributes autmatically supplied by python always begin with an
underscore character to notationally indicate privacy so these should not be
modified or removed. You can add your own attributes named in this way to
indicate privacy if you wish, but in reality these can be modified like any
other attribute.
 
The attribute name specified to these built in functions must be enclosed within
quotes. 
 
Built-In Attributes
Each python class is automatically created with a number of built-in private
attributes whose values can be referenced using dot notation. For example, with
class-name.__doc__ to see the document string value of a specified class name.
 
The built-in dir() function can be used to display a list of all the built-in
attributes in a class specified within its parentheses by testing whether each
attribute name begins with an underscore.
 
The built-in __dict__ attribute contains a namespace dictionary of class
component keys and their associated values. The dictionary of a base class
includes its default __init__() method, and all class methods and attributes.
The dictionary of a class instance includes its instance attributes.
 
The function values stored in the dictionary are the machine addresses where the
functions are stored.
 
A class instance is first created so the __init__() method has been called to
increment the count value before the dictionary gets listed. The __weakref()__
attribute is simply used internally for automatic garbage collection of weak
references in the program for efficiency.
 

Ineritance

When a class instance object is created it is allocated a unique memory address
that can be seen using the built in id() function. Python automatically performs
garbage collection to free up memory space by periodically deleting un-neded
objects such as class instances, so their memory address becomes vacat. 

Whenever an object gets assigned a new name or gets placed in a container, such
as a list, its reference count increases. Conversely, whenever these are removed
or go out of scope its count decreases. The object becomes elegible for
collection when the count is zero. 

Destorying an instance of a class may call upon a destructor to execute a _del_
method, explicitly reclaiming occupied memory space and executing any specified
statements.

The second instance created here is allocated the memory address vacated when
the first instance was deleted. 

Inheriting Features
A python class can be created as a brand new class, like those in previous
examples, or can be derived from an existing class. Importantly, a derived class
inherits members of the parent class from which it is derived, in addition to
its own members.

The ability to inherit members from a base class allows derived classes to be
created that share certain common properties, which have been defined in the
base class. For example, a 'polygon' base class may define width and height
properties that are common to all polygons. Classes of 'rectangle' and
'triangle' could be derived from the polygon class, inheriting width and height
properties, in addition to their own members defining their unique features. 

The virtue of inheritance is extremely powerful , and is the second principle of
object oriented programming.

A derived class declaration adds () parentheses after its class name specifying
the name of its parent class. 

class polygon:
    width=0
    height=0
    def set_values(self, width, height):
        polygon.width=width
        polygon.height=height

Now, create a new file that declares a derived class with a method to return
manipulated class variable values.

from polygon import *
class rectangle(polygon):
    def area(self):
        return self.width * self.height

Create another new file that declares a derived class with a method to return
manipulated class variable values.

from polygon import *
class triangle(polygon):
    def area(self):
        return(self.width * self.height) / 2

Now, start a new file making features of both derived classes available. 

from rectangle import *
from triangle import *
rect=rectangle()
trey=triangle()
rect.set_values(4,5)
trey.set_values(4,5)
print("Rectangle Area:", rect.area())
print("Triangle Area:", trey.area())

A class declaration can derive from more than one class by listing multiple base
classes in the parentheses after its name in the declaration. Don't confuse
class instances and derived instances. An instance is a copy of a class,
whjereas a derived class is a new class that inherits properties of the base
class from which it is derived.

Overriding Base Methods
A method can be declared in a derived class to override a matching method in the
base class-if both method declarations have the same name and the same number of
listed arguments. This effectively hides the base class method as it becomes
inaccessible unless it is called explicitly, using the base class name for
identification. 

Where a method in a base class supplies a default argument value this can be
used in an explcit call to the base methods, or alternative values can be
supplied by overriding methods.

The method declaration in the derived class must exactly match that in the base
class to override it. 

Polymorphism
The three cornerstones of object oriented programming are encapsulation,
inheritance, and polymorphism. Examples earlier have demonstrated how data can
be encapsulated within a python class, and how derived classes inherit the
properties of their base class. This example introduces the final cornerstone
principle of polymorphism.

The term polymorphism describes the ability to assign a different meaning or
purpose to an entity according to its context.

In python, the + character entity can be described as polymorphic because it
represents either the arithmetical addition operator or the string concatenation
operator, in the context of character operands.

Perhaps more importantly, python class methods can also be polymorphic because
the python language uses duck typing.

In a duck typing language you can create a function to take an object of any
type and call that object's methods. If the object does indeed have the call
methods they are executed, otherwise the function signals a run-time error.

Like-named methods of multiple classes can be created and instances of those
same classes will execute the associated version.

Object-oriented programming with python allows data encapsulation, inheritance,
and polymorphism. Base class methods can be overridden by like-named emthods in
derived classes. Python does not support the technique of overloading found in
other languages-in which methods of the same name can be created with different
argument lists in a single class. 

A class can have only one method-method overloading is not supported in python.

A class is a data structure prototype describing object properties with its
methods and attribute members. Each class declaration begins with the class
keyword, and is followed by an indented code block that may contain a class
document string, class variables, and class methods.

Class variables have global scope, but instance variables have only local scope.
instance variables encapsulate data securely in a class structure, and are
initialized when a class instance is created.

Properties of a class are referenced by dot notation, and are addressed
internally using the self prefix. A class instance is a copy of the prototype
that automatically calls its __init__() method when the instance is first
created.

An attribute of a class can be added, modified, or removed using dot notation or
manipulated using the built-in functions getattr(), hasattr(), and delattr().
The name of attributes automatically supplied by python begins with an
underscore character to notionally indicate privacy.

The built-in __dict__ attribute contains a namespace dictionary of class
component keys and values. Python automatically performs garbage collection, but
the del keyword can remove objects and call the class destructor. A derived
class inherits the method and attribute members of the parent base class from
which it is derived.

A method of a derived class can override a matching method of the same name in
its parent class. Python is a duck-typed language that supports polymorphism for
like-named methods of multiple classes.

Sending Web Responses

Sending Web Responses
Whenever a user asks to view an online web page in their browser it requests the
page from the web server, and receives the page in response, via the http
protocol.

Where a requested web page address is an html document, with an .html file
extension, the web server response will return that file to the browser so its
contents can be displayed.

Where python is installed on the computer hosting the web server, the web server
can be configured to recognize python scripts and call upon the python
interpreter to process script code before sending an html response to the web
server, for return to the browser client.

A python script requested by a web server can generate a complete html document
response by describing the content type on the first line as
"content-type:text/html/r/n/r/n" so the web browser will parse the markup
content for display on the screen.

The content-type output description gets sent as an http header to the browser,
and must appear on the first line.

Enclose html attribute values within double quote marks so they do not get
confused with the single quote marks enclosing the strings.

Handling Values
Values can be passes to a python script on the web server when the browser makes
an http request. Those values can be used in the script and echoed in a response
returned to the browser.

Python's cgi module can be used to easily handle data passes from the web
browser by an http request. This provides a "fieldstorage()" constructor that
creates an object storing the passed data as a dictionary of key:value pairs.
Any individual value  can then be retrieved by specifying its associated key
name within the parentheses of the "fieldstorage" object's "getvalue()" method. 

The browser can submit data to the script using a "get" method that simply
appends key:value pairs to the script's url address. These follow a ? question
mark character after the file name and multiple pairs must be separated by an &
ampersand character. 

The request string in the get method is lmited to 1024 characters so is
unsuitable for passing lots of key:value pairs. The values appended to the url
are visible in the browser address field of the response, so the get method
should not be used to send passwords or other sensitive data values to the web
server.

Submitting Forms
Passing data from a web page to a web server using the get method to append
key:value pairs to a url is simple, but has some limitations - the request
string length cannot exceed 1024 characters, and the values appear in the
browser address field.

As a more reliable alternative, the browser can submit data to the data script
using a post method that sends the information to the web server as a separate
message not appended to the url.

Python's cgi module can be used to handle form data sent from the browser with
the post method in exactly the same way as data passed from the browser with the
get method. This module's fieldstorage() constructor can create an object to
store the posted data as a dictionary of key:value pairs for each form field.
Any individual value can be retrieved by specifying its associated key name to
the object's getvalue() method.

Providing Text Areas
Large amounts of user-input text data can be passed from a web page to a web
server using the html <textarea> tags and the form post method. This tag has no
value attribute so a default value may not be provided. It is useful to have the
python script test whether the text area has been left blank and provide a
default value when the user has entered no text.

The average character width may vary between browsers - so the physical size of
the text area field may vary too. You can use the F12 developer tools in your
web browser to examine the http request and response components.

Checking Boxes
An html form can provide a visual checkbox on/off switch that the user can
toggle to include its associated data for submission to the web server. The
python script nominated to handle the form data can test whether each checkbox
has been checked, simply by testing if a value has been received from the
checkbox of that name.

The "checked" keyword can be added in any checkbox <input> element to make it
checked by default.

Choosing Radio Buttons
An html form can provide a 'radio button" group from which the user can select
just one button to submit its associated data to the web server. Unlike
checkboxes, radio buttons that share a common name are mutually exclusive, so
when one button in the group is selected, all other buttons in that group are
switched off. The python script nominated to handle the form data can test the
value submitted for the radio button group name and supply an appropriate
response. 

Always include a "checked" attribute to automatically select one button in each
radio button group - to include a default choice. Radio button elements resemble
the buttons on old radios where each button selected a particular radio station.

Selecting Options
An html form can provide a drop-down list of possible options from which the
user can select a single option to include its associated data for submission to
the web server. The submitted value can then be retrieved by specifying its
associated list key name within the parentheses of the "fieldstorage" object's
"getvalue()" method. 

Typically, the first list option will be selected for submission by default,
unless you click open the drop-down list and select an alternative. You can
include the selected attribute in an <option> tag to automatically select one
option in each list - to include a default choice. 

Updating Files
An html form can provide a file selection facility, which calls opon the
operating system's "choose file" dialog, to allow the user to browse their local
file system and select a file. To enable this facility the html <form> tag must
include an 'enctype" attribute specifying the encoding type as
multiple/form-data.

The full path address of the file selected for upload is a value stored in the
fieldstorage object list that can be accessed using its associated key name.
Usefully, the file name can be stripped from the path address by the "os"
module's "path.basename()" method.

Notice that binary file mode is used here to copy the uploaded file.

Summary
Python can be installed on a web server host to process script code before
sending a response to a web browser client. A server-side python script can
generate an html document by describing the content type as
"content-type:text/html/r/n/r/n".

The cgi module provides a fieldstorage() constructor to create an object for
storing submitted data as key:value pairs. Any value stored in a fieldstorage
object can be retrieved by specifying its key name to the object's getvalue()
method.

The browser can send data to a script using the get method that appends
key=value pairs to its url address after a ? question mark. Multiple key=value
pairs of data can be submitted using the get method if each pair is separated by
an & ampersand character. 

The get method request string length cannot exceed 1024 characters and will be
visible in the browser address field. The browser can send data to a script
using the post method that submits key:value pairs as a separate message.

Data submitted from an html form can be stroed in a fieldstorage object as
key:value pairs for each form field. A server-side python script can provide
default values for submitted html form fields that the user has left blank.

Checkbox fields of an html form that are unchecked do not get submitted to the
web server. A selected radio button in a group provides the value to be
associated with the group name when the form gets submitted.

A selected item in a drop-down list provides the value to be associated with the
list name when the form gets submitted. An html form can allow file uploads only
if its "enctype" attribute specifies its encoding type as "multiple/form-data". 

Launching a Window

The standard python module that you can use to create graphical applications is
called "tkinter", a toolkit to interface with the system gui.

The tkinter module can be imported into a program like any other module to
provide attributes and methods for windowed apps. Every tkinter program must
begin by calling the tk() constructor to create a window object. The window's
size can be specified as a "widthxheight" string argument to the window object's
geometry() method. Similarly, the window's title can be specified as a title
string argument to the window object's title() method. If not specified, default
size and title values will be used.

Every tkinter program must also call the window object's mainloop() method to
capture events, such as when the user closes the window to quit the program.
This loop should appear at the end of the program as it also handles window
updates that may be implemented during execution.

With tkinter, all the graphical controls that can be included in the application
window, such as buttons or checkboxes, are referred to as widgets. Perhaps the
simplest widget is a non-interactive label object that merely displays text or an
image in the app interface. A label object can be created by specifying the
window object's name and text='string' as arguments to a Label() constructor. 

Once created, each widget, such as a label, must then be added to the window
using one of these geometry manager methods.


pack()-places the widget against a specified side of the window using Top,
Bottom, left, or Right constant values specified to its side=argument.

place()-places the widget at XY coordinates in the window using numerical values
specified to its x= and y= arguments.

grid()-places the widget in a cell within the window using numerical values
specified to its row= and column= arguments.


Optionally, the pack() method may include a fill argument to expand the widget
in available space. For example, with fill='x'. Alternatively, the pacl() method
may include padx and pady arguments to expand the widget along an axis by a
specified amount.

There can be only one call to the TK() constructor and it must be at the start
of the program code.

from tkinter import *
window=Tk()
window.title('Window Label')
label=Label(window, text='This is an introduction to interfaces in Python')
label.pack(padx=200, pady=50)
window.mainloop()

Widgets will not appear in the window when running the program unless they have
been added with a program manager.

Responding to Buttons
A button widget provides a graphical button in an application window that may
contain either text or an image to convey the button's purpose. A button object
is created by specifying the window name and options as arguments to a button()
constructor. Each option is specified as an option=value pair. The command
option must always specify the name of a function or method to call when the
user clicks that button. The most popular options are listed below, with a brief
description.

activebackground    background color when the cursor is over
activeforeground    foreground color when the cursor is over
bd            border width in pixels(default is 2)
bg            background color
font            font for button label
height            button height in text lines, or pixels for images
highlightcolor        border color when in focus
image            image to be displayed instead of text
justify            multiple text lines as Left, center, or Right
padx            horizontal padding
pady            vertical padding
relief            border style of Sunken, Ridge, Raised or Groove
state            enabled status of normal or Disabled
underline        index number in text of character to underline
width            button width in letters, or pixels for images
wraplength        length at which to wrap text

The values assigned to other options determine the widget's appearance. These
can be altered by specifying a new option=value pair as an argument to the
widget's configure() method. Additionally, a current option value can be
retrieved by specifying its name as a string argument to the widget's cget()
method.

You can also call a button's invoke() method to call the function nominated to
its command option. 

from tkinter import *
window=Tk()
window.title('Click this Button')
btn_end=Button(window, text='Close', command=exit)
def tog():
    if window.cget('bg')=='yellow':
        window.configure(bg='gray')
    else:
        window.configure(bg='yellow')
btn_tog=Button(window,text='Switch', command=tog)
btn_tog.pack(padx=150,pady=20)
btn_end.pack(padx=150,pady=20)
window.mainloop()

Only the function name is specified to the command option. Do not add trailing
parentheses in the assignment. The 'gray' color is the original default color of
the window.

Displaying Messages
A program can display messages to the user by calling methods provided in the
"tkinter.messagebox" module. This must be imported separately and its lengthy
name can be assigned a short alias by an "import as" statement.

A message box is created by supplying a box title and the message to be
displayed as the two arguments to one of these methods.

showinfo()            ok
showwarning()        ok
showerror()            ok
askquestion()        yes and no
askofcancel()        ok returns 1 and cancel
askyesno()            yes returns 1 and no
askretrycancel()    retry returns 1 and cancel

Those methods that produce a message box containing a single OK button return no
value when the button gets clicked by the user. Those that do not return a value
can be used to perform conditional branching by testing that value.

from tkinter import *
import tkinter.messagebox as box
window=Tk()
window.title('Message')
def dialog():
    var=box.askyesno('Message', 'Proceed?')
    if var==1:
        box.showinfo('Yes Box', 'Proceeding...')
    else:
        box.showwarning('No box', 'Canceling...')
btn=Button(window, text='Click', command=dialog)
btn.pack(padx=150, pady=50)
window.mainloop()

Options can be added as a third argument to these method calls. For example, add
'type=abortretryignore' to get three buttons.

Gathering Entries
An entry widget provides a single-line input field in an application where the
program can gather entries from the user. An entry object is created by
specifying the name of its parent container, such as a window or frame name, and
options as arguments to an Entry() constructor. Each option is specified as an
option=value pair. Popular options are listed below, together with a brief
description.

bd                    border width in pixels(default is 2)
bg                    background color
fg                    foreground color used to render the text
font                font for the text
highlightcolor        border color when in focus
selectbackground    background color of selected text
selectforeground    foreground color of selected text
show                hide password characters with show='*'
state                enabled status of Normal or Disabled
width                entry width in letters

Multiple widgets can be grouped in frames for better positioning. A frame object
is created by specifying the name of the window to a Frame() constructor. The
frame's name can then be specified as the first argument to the widget
constructors to identify it as that widget's container.

When actually adding widgets to the frame you can specify which side to pack
them to in the frame with Top, Bottom, left, or Right constants. For example,
'entry.pack(side=Left)'.

Typically, an entry widget will appear alongside a label describing the type of
input expected there from the user, or alongside a button widget that the user
can click to perform some action on the data they have entered, so positioning
in a frame is ideal.

Data currently entered into an entry widget can be retrieved by the program
using that widget's get() method.

from tkinter import *
import tkinter.messagebox as box
window=Tk()
window.title('Entry Box')
frame=Frame(window)
entry=Entry(frame)
def dialog():
    box.showinfo('Greetings', 'Welcome ' + entry.get())
btn=Button(frame, text='Enter Name', command=dialog)
btn.pack(side=RIGHT, padx=5)
entry.pack(side=LEFT)
frame.pack(padx=20, pady=20)
window.mainloop()

Use a label widget instead of an Entry widget if you want to display text that
the user cannot edit.

Listing Options
A Listbox widget provides a list of items in an application from which the user
can make a selection. A listbox object is created by specifying the name of its
parent container, such as a window or frame name, and options as arguments to a
Listbox() constructor. Popular options are listed below, together with a brief
description.

bd                    border width in pixels(default is 2)
bg                    background color
fg                    foreground color used to render the text
font                font for the text
height                number of lines in list(default is 10)
selectbackground    background color of selected text
selectmode            single(the default) or multiple selections
width                Listbox width in letters(default is 20)
yscrollcommand        attach to a vertical scrollbar

Items are added to the listbox by specifying a list index number and the item
string as arguments to its insert() method.

You can retrieve any item from a listbox by specifying its index number within
the parentheses of its get() method. Usefully, a listbox also has a
curselection() method that returns the index number of the currently selected
item, so this can be supplied as the argument to its get() method to retrieve
the current selection.

from tkinter import *
import tkinter.messagebox as box
window=Tk()
window.title('Listbox')
frame=Frame(window)
listbox=Listbox(frame)
listbox.insert(1, 'C++')
listbox.insert(2, 'Python')
listbox.insert(3, 'R')
def dialog():
    box.showinfo('Selection', 'Your Choice:')
    listbox.get(listbox.curselection())
btn=Button(frame, text='Choose', command=dialog)
btn.pack(side=RIGHT, padx=5)
listbox.pack(side=LEFT)
frame.pack(padx=30, pady=30)
window.mainloop()

If the selectmode is set to MULTIPLE, the curselection() method returns a tuple
of the selected index numbers.

Polling Radio Buttons
A Radiobutton widget provides a single item in an application that the user may
select. Where a number of radio buttons are grouped together, they user may
only select any one item in the group. With tkinter, radio button objects are
grouped together when they nominate the same control variable object to assign a
value to upon selection. An empty string variable object can be created for this
purpose using the "stringvar()" constructor or an empty integer variable object
using the "intvar()" constructor. 

A radio button object is created by specifying four arguments to a
"Radiobutton()" constructor.

1. name of the parent container, such as the frame name.
2. text for a display label, specified as a text=text pair.
3. control variable object, specified as a variable=variable pair.
4. value to be assigned, specified as a value=value pair.

Each radio button object has a select() method that can be used to specify a
default selection in a group of radio buttons when the program starts. A string
value assigned by selecting a radio button can be retrieved from a string
variable object by using its get() method.

from tkinter import *
import tkinter.messagebox as box
window=Tk()
window.title('Radio Button')
frame=Frame(window)
book=StringVar()
radio_1=Radiobutton(frame, text='Javascript', variable=book, value='web')
radio_2=Radiobutton(frame, text='C++', variable=book, value='microprocessor')
radio_3=Radiobutton(frame, text='R', variable=book, value='statistics')
radio_1.select()
def dialog():
    box.showinfo('Selection', 'Choice: ' + book.get())
btn=Button(frame, text='Choose', command=dialog)
btn.pack(side=RIGHT, padx=5)
radio_1.pack(side=LEFT)
radio_2.pack(side=LEFT)
radio_3.pack(side=LEFT)
frame.pack(padx=30, pady=30)
window.mainloop()

A Radiobutton object has a deselect() method that can be used to cancel a
selection programmatically.

Checking Boxes
A Checkbutton widget provides a single item in an application that the user may
select. Where a number of check buttons appear together the user may select one
or more items. Check button objects nominate an individual control variable
object to assign a value to whether checked or unchecked. An empty string
variable object can be created for this using the stringvar() constructor or an
empty integer variable object using the intVar() constructor.

A check button object is created  by specifying five arguments to a
Checkbutton() constructor.

1. name of the parent container, such as the frame name
2. text for a display label, as a text=text pair
3. control variable object, as a variable=variable pair
4. value to assign if checked, as an onvalue=value pair
5. value to assign if unchecked, as an offvalue=value pair

An integer value assigned by a check button can be retrieved from an integer
variable object by its get() method.

from tkinter import *
import tkinter.messagebox as box
window=Tk()
window.title('Check Button')
frame=Frame(window)
var_1=IntVar()
var_2=IntVar()
var_3=IntVar()
book_1=Checkbutton(frame, text='C++', variable=var_1, onvalue=1, offvalue=0)
book_2=Checkbutton(frame, text='R', variable=var_2, onvalue=1, offvalue=0)
book_3=Checkbutton(frame, text='Javascript', variable=var_3, onvalue=1, offvalue=0)
def dialog():
    str='Your Choice:'
    if var_1.get()==1:str+='For Microprocessors'
    if var_2.get()==1:str+='For Statistics'
    if var_3.get()==1:str+='For Web Sites'
    box.showinfo('Selection', str)
btn=Button(frame, text='Choose', command=dialog)
btn.pack(side=RIGHT, padx=5)
book_1.pack(side=LEFT)
book_2.pack(side=LEFT)
book_3.pack(side=LEFT)
frame.pack(padx=30, pady=30)
window.mainloop()

A Checkbutton object has select() and deselect() methods that can be used to
turn the state on or off. For example, check_1, select(). The state of any
Checkbutton object can be reversed by calling its toggle() method.

Adding Images
With the tkinter module, images in gif or pgm/ppm file formats can be displayed
on label, button, text, and canvas widgets using the PhotoImage() constructor to
create image objects. This simply requires a single file= argument to specify
the image file. It also has a subsample() method that can scale down a specified
image by stating a sample value to x= and y= arguments. For example, values of
x=2, y=2 samples every second pixel so the image object is half the size of the
original.

Once an image object has been created, it can be added to a label or button
constructor statement by an image= option. Text objects have an image_create()
method with which to embed an image into the text field. This requires two
arguments to specify location and image=. For example, '1.0' specifies the
first line and first character.

Canvas objects have a create_image() method that requires two arguments to
specify location and image=. Here, the location sets the x,y coordinates on the
canvas at which to paint the image.

from tkinter import *
window=Tk()
window.title('Image')
img=PhotoImage(file='galaxy.gif')
label=Label(window, image=img, bg='yellow')
small_img=PhotoImage.subsample(img, x=2, y=2)
btn=Button(window, image=small_img)
txt=Text(window, width=25, height=7)
txt.image_create('1.0', image=small_img)
txt.insert('1.0', 'Galaxies Are Cool')
can=Canvas(window, width=100, height=100, bg='cyan')
can.create_image((50,50), image=small_img)
can.create_line(0,0,100,100, width=25, fill='yellow')
label.pack(side=TOP)
btn.pack(side=LEFT, padx=10)
txt.pack(side=LEFT)
can.pack(side=LEFT, padx=10)
window.mainloop()

Notice that the text method is image_create() but the canvas method is
create_image(). Text and canvas widgets are both powerful and flexible. 

Summary
The tkinter module can be imported into a python program to provide attributes
and methods for windowed applications. Every tkinter program must begin by
calling Tk() to create a window and call its mainloop() method to capture
events.

The window object's title is specified by its title() method. A label widget is
created by specifying the name of its parent container and its text as arguments
to the Label() constructor.

Widgets can be added to an application using the pack(), grid(), or place()
geometry managers. A button widget is created by specifying the name of its
parent container, its text, and the name of a function to call when the user
pushes it, as arguments to the Button() constructor.

The tkinter.messagebox module can be imported into a python program to provide
attributes and methods for message boxes. Message boxes that ask the user to
make a choice return a value to the program for conditional branching.

The Frame() constructor creates a container in which multiple widgets can be
grouped for better positioning. The Entry() constructor creates a single line
text field whose current contents can be retrieved by its get() method.

Items are added to the Listbox object by its insert() method, and retrieved by
specifying their index numbers to its get() method. Radiobutton and Checkbutton
objects store values in the StringVar or IntVar object nominated by their
variable attribute.

The PhotoImage() constructor creates an image object that has a subsample()
method that can scale down an image. Images can be added to Button and Label
objects, embedded in Text objects, and painted on Canvas objects.