Friday 30 August 2019

Python:Control Constructs and Exceptions

Conditionals and Loops:
if Statement
The if statement for Python will seem amazingly familiar. It is made up of three main components: the keyword itself, an expression that is tested for its truth value, and a code suite to execute if the expression evaluates to non-zero or true. The syntax for an if statement is:
Syntax:
if expression:
expr_true_suite

Example:
a=20;b=10
if a>b:
    print("a is grater")

The suite of the if clause, expr_true_suite, will be executed only if the above conditional expression results in a Boolean true value. Otherwise, execution resumes at the next statement following the suite.

Multiple Conditional Expressions
The Boolean operators and, or, and not can be used to provide multiple conditional expressions or perform negation of expressions in the same if statement.
Example:
a=20;b=10;c=8
if a>b and a>c:
    print("a is grater")
else statement:
Like other languages, Python features an else statement that can be paired with an if statement. The else statement identifies a block of code to be executed if the conditional expression of the if statement resolves to a false Boolean value. The syntax is what you expect:
Syntax:
if expression:
expr_true_suite
else:
expr_false_suite

Example:
uname='riyaj'
upass='rss'
loginid=input("enter login id:  ")
upassward=input("enter password:  ")
if uname == loginid and upass==upassward:
    print("password accepted")
else:
    print("Enter Valid username and password")

while Statement
It is a conditional
looping statement. In comparison with an if statement where a true expression will result in a single
execution of the if clause suite, the suite in a while clause will be executed continuously in a loop until
that condition is no longer satisfied.
syntax:
while expression:
suite_to_repeat
The suite_to_repeat clause of the while loop will be executed continuously in a loop until expression evaluates to Boolean False.
Example:
count = 0
while (count < 9):
    print ('The Value of Counter is :', count)
    count += 1

Example:
n = 100
s = 0
counter = 1
while counter <= n:
    s = s + counter
    counter += 1
print("Sum of 1 until %d: %d" % (n,s))

Example:
i = 0
while i < 6:
             i += 1
 if i == 3:
            break
print(i)

Example:
i = 0
while i < 6:
             i += 1
 if i == 3:
            continue
print(i)


The suite here, consisting of the print and increment statements, is executed repeatedly until count is no longer less than 9. With each iteration, the current value of the index count is displayed and then bumped up by 1.
else with while:
Similar to the if statement, the while loop of Python has also an optional else part. This is an unfamiliar construct for many programmers of traditional programming languages.
The statements in the else part are executed, when the condition is not fulfilled anymore. Some might ask themselves now, where the possible benefit of this extra branch is. If the statements of the additional else part were placed right after the while loop without an else, they would have been executed anyway, wouldn't they. We need to understand a new language construct, i.e. the break statement, to obtain a benefit from the additional else branch of the while loop.


syntax:
while condition:
             statement_1
             ...
             statement_n
else:
             statement_1
             ...
             statement_n

Example:
count = 0
while (count < 9):
    print ('The Value of Counter is :', count)
    count += 1
else:
    print("now counter is going having value greater than Nine i.e. :",count)
One line while loop:
while n > 0: n -= 1; print(n)

for Statement:
For loops are used for sequential traversal.

Syntax:
for <var> in <iterable>:
     <statement(s)>

<iterable> is a collection of objects—for example, a list or tuple. The <statement(s)> in the loop body are denoted by indentation, as with all Python control structures, and are executed once for each item in <iterable>. The loop variable <var> takes on the value of the next element in <iterable> each time through the loop.
Example:
fruits=['banana','mango','apple','kivi']
for fruit in fruits:
            print(fruit)

Example:
for l in "Shahu":
             print(l)

Example:
no=list(range(10))
for i in no:
             print(i)

for i in range(len(l)):
             print (l[i])

break Statement:
The break statement terminates the loop containing it. Execution Control of the program flows to the statement immediately after the body of the loop, if break statement is inside a nested loop (loop inside another loop), break will terminate the innermost loop.
The break statement can be used in both while and for loops.
  
Example:
for val in "anything":
    if val == "i":
        break
    print(val)
print("The end")


Example:
num=7;
count = num / 2
while count > 0:
    if num % count == 0:
        print (count, 'is the largest factor of', num)
        break
    count -= 1

The task of this piece of code is to find the largest divisor of a given number num. We iterate through all possible numbers that could possibly be factors of num, using the count variable and decrementing for every value that does not divide num. The first number that evenly divides num is the largest factor, and once that number is found, we no longer need to continue and use break to terminate the loop.
Example:
var = 10
while var > 0:             
   var = var -1
   if var == 5:
      break
   print ('Current variable value :', var)
print ("Good bye!")

continue statement
The continue statement is used to skip the rest of the code inside a loop for the current iteration only. Loop does not terminate but continues on with the next iteration.

Example:
for val in "anything":
    if val == "i":
        continue
    print(val)

print("The end")

Example:
var = 10
while var > 0:             
   var = var -1
   if var == 5:
      continue
   print ('Current variable value :', var)
print ("Good bye!")
pass statement:
In Python programming, pass is a null statement. The difference between a comment and pass statement in Python is that, while the interpreter ignores a comment entirely, pass is not ignored. However, nothing happens when pass is executed. It results into no operation (NOP).We generally use it as a placeholder.
Suppose we have a loop or a function that is not implemented yet, but we want to implement it in the future. They cannot have an empty body. The interpreter would complain. So, we use the pass statement to construct a body that does nothing.

Example:
sequence = ['p', 'a', 's', 's']
for val in sequence:
    pass

Example:
for num in range(50):
    if num%2 != 0:
        pass
    else:
        print(num)
Errors And Exceptions:
What Are Exceptions?:
Errors:
Errors are either syntactical or logical in nature.
Syntax errors indicate errors with the construct of the software and cannot be executed by the interpreter or compiled correctly. These errors must be repaired before execution can occur.
Once programs are semantically correct, the only errors that remain are logical. Logical errors can either be caused by lack of or invalid input, or, in other cases, by the inability of the logic to generate, calculate, or otherwise produce the desired results based on the input. These errors are sometimes known as domain and range failures, respectively.
When errors are detected by Python, the interpreter indicates that it has reached a point where continuing to execute in the current flow is no longer possible. This is where exceptions come into the picture.
Exceptions:
Exception is an action that is taken outside of the normal flow of control because of errors.
This action comes in two distinct phases: The first is the error that causes an exception to occur, and the second is the detection (and possible resolution) phase.
The first phase takes place when an exception condition (sometimes referred to as exceptional condition) occurs. Upon detection of an error and recognition of the exception condition, the interpreter performs an operation called raising an exception. Raising is also known as triggering, throwing, or generating, and is the process whereby the interpreter makes it known to the current control flow that something is wrong. Python also supports the ability of the programmer to raise exceptions. Whether triggered by the Python interpreter or the programmer, exceptions signal that an error has occurred.
The current flow of execution is interrupted to process this error and take appropriate action, which happens to be the second phase.
The second phase is where exception handling takes place. Once an exception is raised, a variety of actions can be invoked in response to that exception. These can range anywhere from ignoring the error, to logging the error but otherwise taking no action, performing some corrective measures and aborting the program, or alleviating the problem to allow for resumption of execution. Any of these actions represents a continuation, or an alternative branch of control. The key is that the programmer can dictate how the program operates when an error occurs.
Exceptions in Python:
When error occurs in python a "traceback" notice appears along with a notice containing as much diagnostic information as the interpreter can give you, including the error name, reason, and perhaps even the line number near or exactly where the error occurred. All errors have a similar format, regardless of whether running within the Python interpreter or standard script execution, providing a consistent error interface. All errors, whether they be syntactical or logical, result from behavior incompatible with the Python interpreter and cause exceptions to be raised.
Example 1: NameError
>>> myfun
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    myfun
NameError: name 'myfun' is not defined

NameError indicates access to an uninitialized variable. The offending identifier was not found in the Python interpreter's symbol table.
Example 2: ZeroDivisionError: division by any numeric zero

>>> 1/0
Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>    1/0
ZeroDivisionError: division by zero
Any numeric division-by-zero will result in a ZeroDivisionError exception.
Example 3: SyntaxError: Python interpreter syntax error
>>> for
SyntaxError: invalid syntax
SyntaxError exceptions are the only ones that do not occur at run-time. They indicate an improperly constructed piece of Python code which cannot execute until corrected. These errors are generated at compile-time, when the interpreter loads and attempts to convert your script to Python bytecode. These may also occur as a result of importing a faulty module.

Example 4: IndexError: request for an out-of-range index for sequence
>>> mylist=[]
>>> mylist[0]
Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>    mylist[0]
IndexError: list index out of range

IndexError is raised when attempting to access an index that is outside the valid range of a sequence.
Example 5: IOError: input/output error
>>> f=open('myfile')
Traceback (most recent call last):
 File "<pyshell#6>", line 1, in <module>
   f=open('myfile')
FileNotFoundError: [Errno 2] No such file or directory: 'myfile'
  Attempting to open a nonexistent disk file is one example of an operating system input/output (I/O) error. Any type of I/O error raises an IOError exception.

Example  6: AttributeError: attempt to access an unknown object attribute
>>> myinst=myclass()
>>> myinst.name='shaikh'
>>> myinst.name
'shaikh'
>>> myinst.surname
Traceback (most recent call last):
  File "<pyshell#22>", line 1, in <module>
    myinst.surname
AttributeError: 'myclass' object has no attribute 'surname'

We stored a value in myinst.name, the bar attribute of instance myinst. Once an attribute has been defined, we can access it using the familiar dotted-attribute notation, but if it has not, as in our case with the surname (non-)attribute, an AttributeError occurs.
Detecting and Handling Exceptions:
Exceptions can be detected by incorporating them as part of a try statement. Any code suite of a TRy statement will be monitored for exceptions.
There are two main forms of the TRy statement: TRy-except and try-finally. These statements are mutually exclusive, meaning that you pick only one of them. A try statement can be accompanied by one or more except clauses, exactly one finally clause, or a hybrid try-except-finally combination.
try-except statements allow one to detect and handle exceptions. There is even an optional else clause for situations where code needs to run only when no exceptions are detected. Meanwhile, TRy-finally statements allow only for detection and processing of any obligatory cleanup (whether or not exceptions occur), but otherwise have no facility in dealing with exceptions. The combination, as you might imagine, does both.
try-except Statement:
The TRy-except statement (and more complicated versions of this statement) allows you to define a section of code to monitor for exceptions and also provides the mechanism to execute handlers for exceptions.
The syntax for the most general try-except statement is given below. It consists of the keywords along with the try and except blocks (try_suite and except_suite) as well as optionally saving the reason of failure:
Syntax:
try:
try_suite # watch for exceptions here
except Exception[, reason]:
except_suite # exception-handling code

Here are few important points about the above syntax.
·      A single try statement can have multiple except statements. This is useful when the try block  contains statements that may throw different types of exceptions.
·      You can also provide a generic except clause, which handles any exception.
·      After the except clause(s), you can include an else-clause. The code in the else-block executes if the code in the try: block does not raise an exception.
·      The else-block is a good place for code that does not need the try: block's protection.
Example: here we opens a file, writes content in the, file and comes out gracefully because there is no problem at all:


try:
   fh = open("testfile", "w")
  fh.write("This is my test file for exception handling!!")
except IOError:
  print ("Error: can\'t find file or read data")
else:
  print ("Written content in the file successfully")
  fh.close()
    
Example: This example tries to open a file where you do not have the write permission, so it raises an exception.
try:
   fh = open("testfile", "r")
  fh.write("This is my test file for exception handling!!")
except IOError:
  print ("Error: can\'t find file or read data")
else:
  print ("Written content in the file successfully")
  fh.close()

try Statement with Multiple excepts:

def ctofloat(obj):
    try:
        retval = float(obj)
    except ValueError:
        retval = 'could not convert non-number to float'
    except TypeError:
        retval = 'object type cannot be converted to float'
    return retval


except Statement with Multiple Exceptions:
We can also use the same except clause to handle multiple exceptions. except statements that process more than one exception require that the set of exceptions be contained in a tuple:
except (Exception1, Exception2)[, reason]:
suite_for_Exception1_and_Exception2
The above syntax example illustrates how two exceptions can be handled by the same code. In general, any number of exceptions can follow an except statement as long as they are all properly enclosed in a tuple:
except (Exc1[, Exc2[, ... ExcN]])[, reason]:
suite_for_exceptions_Exc1_to_ExcN
If for some reason, perhaps due to memory constraints or dictated as part of the design that all exceptions for our safe_float()function must be handled by the same code, we can now accommodate that requirement:
def safe_float(obj):
    try:
        retval = float(obj)
    except (ValueError, TypeError):
        retval = 'argument must be a number or numeric string'
    return retval
Now there is only the single error string returned on erroneous input:
>>> safe_float('Spanish Inquisition')
'argument must be a number or numeric string'
>>> safe_float([])
'argument must be a number or numeric string'
>>> safe_float('1.6')
1.6
>>> safe_float(1.6)
1.6
>>> safe_float(932)
932.0

Raising Exceptions:
In Python programming, exceptions are raised when corresponding errors occur at run time, but we can forcefully raise it using the keyword raise.
Example:
>>> raise NameError
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    raise NameError
NameError

Example:
try:
    a = int(input("Enter a positive integer: "))
    if a <= 0:
        raise ValueError("That is not a positive number!")
except ValueError as ve:
    print(ve)

try..finally :
Beside try and except blocks, we can also use try and finally blocks together.
The finally block contains statements that must be executed whether or not the exception is caught and raised in the try block.
try..finally is useful to release external resources and clear up the memories.
try:
   # perform operations
finally:
   #These statements must be executed

Example:
try:
   fp = open("test.txt",'r')
   fp.write("hi! here we are testing the code...")
   print("Data was written to the file..")
except IOError:
    print("unable to write data to file.. kindly change the mode")
finally:
    fp.close()
    print("file Closed")
 ==()==

2 comments: