Search This Blog

Monday, February 14, 2022

Advanced Python Interview questions

 

Advanced Python Interview questions:

1) What is the difference between method and constructor ?

Method 

1) Name of method can be any name
2) Method will be executed if we call that method
3) Per object, method can be called any number of times.
4) Inside method we can write business logic

Construtor

1) __new__ and __init__ collectively form constructor.
2) Object initialization is controlled by an instance method called __init__ and which is also usually called as  Constructor. Once the object is created,we can make sure that every variable in the object is properly initialized by defining an __init__ method in our class, which means init-iate
3) Constructor will be executed automatically at the time of object creation.
4) Per object, Constructor will be executed only once
5) Inside Constructor we have to declare and initialize instance variables


2) Explain different types of methods in Python?
Python has three types of methods:
1) Instance Methods
2) Class Methods
3) Static Methods

1)Instance Methods:
  • This is called if the class has been instantiated.
  • Instance method has to be declared with self variable.Example -  def test(self):
  • By using self variable,method can o access instance variables.
  • Within the class we can call instance method by using self variable and from outside of the class we can call by using object reference.
class Student:
  def __init__(self,name)
       self.name=name
def display(self)
    print('My name is ',self.name) 

2) Class Methods
  • This method does not require self as argument and they use only class variable.
  • They need a parameter called cls. This stands for class and like self it gets automatically passed by python
  • This methods needs to be declared using @classmethod decorator.
  • We can call this method using classname or object reference variable
class Bird:
   legs = 2
@classmethod
def walk(cls,name):
 print('{} walks with {} legs...'.format(name,cls.lEgs))

Bird.walk('Crow')

3) Static Methods

  • These methods are general utility methods.
  • These methods do not use any instance or class variables.
  • This method does not require self or cls arguments at the time of declaration.
  • This can be declared exlicitly by using @staticmethod decorator
  • We can access static methods by using classname or object reference
class Mathfunc:
  @staticmethod
  def add(x,y)
     print('The Sum:',x+y)

Mathfunc.add(10,20)


3) 
Can tuple be used as dictionary keys?
Yes.
Only immutable elements can be used as dictionary keys.Hence only tuples and not lists can be used as keys.
d={}

t1 = (5,9)
t2 = (30,40,9)

d[t1] = 7
d[t2] = 90

print d[t1], d[t2]

Output:

7 90

4)Which OOP’s concept is not applicable in Python?
  •  Python Method overloading is not possible.
  • If we are trying to declare multiple methods with same name and different number of arguments then Python will always consider only last method.
5)How to handle Overloaded Method Condition  in Python?
Most of the times, if method with variable number of arguments required then we can handle with default arguments or with variable number of argument methods.

Default Arguments:  

class Test:
     def sum(self,a=None,b=None,c=None):
        if a!=None and b!= None and c!= None:
        print('The Sum of 3 Numbers:',a+b+c)
Variable Number of Arguments:
class Test:
  def sum(self,*a):
   for x in a:
   print(x)


6What is the difference between yield and return statement?
      Return
Yield
‘return’ statement causes the function to exit and arrives back the value to caller, then function loses its local state. Thus calling it next time it starts from first statement
‘yield’ statement cause the function to return back a generator object to the caller and maintains states between func calls .Thus resumes from where it left off when we call next() method again
It is used when function is ready to exit and return a value back to the caller
It is used to calculate series of results 1 by 1 on the fly
It will exit the function
It will not cause function to exit
It will terminate the loop immediately
Does not terminate the loop
Returns single value to the caller function
It returns generator object which can parse into list


7)Difference between str() and repr() 
Difference between __str__()  and __repr__()
  • str() internally calls __str__() function and hence functionality of both is same.
  • repr() internally calls __repr__() function and hence functionality of both is same.
str()
  • str() returns a string containing a nicely printable representation object. 
  • The main purpose of str() is for readability.It may not possible to convert result string to original object to original object
import datetime
today=datetime.datetime.now()
s=str(today)#converting datetime object to str
print(s)
d=eval(s)#converting str object to datetime
Output
2020-06-13 16:57:36.425246
Traceback (most recent call last):
  File "<string>", line 1
    2020-06-13 16:57:36.425246
          ^
SyntaxError: Invalid token

repr()
  • repr() returns a string containing a printable representation of object.
  •  The main goal of repr() is definite. We can convert result string to original object by using eval() function,which is possible in str() function.
import datetime
today=datetime.datetime.now()
s=repr(today)#converting datetime object to str
print(s)
d=eval(s)#converting str object to datetime
Output : datetime.datetime(2020, 6, 13, 16, 59, 18, 355503)

8) How to remove directory/directories in python?
Python provides inbuilt module os,which contains several functions to perform directory related operations.
import os
os.rmdir("mysub/mysub2")               #Remove single dir
print("mysub2 directory deleted")
os.removedirs("sub1/sub2/sub3")       # Remove multiple dirs
print("All 3 directories sub1,sub2 and sub3 removed")

9) Explain Garbage collection in Python?
  • Main objective of Garbage Collector is to destroy useless/unusable objects
  • Garbage collection is the process of cleaning computer memory which is currently being put to use by a running program when that program no longer needs that memory
  • With Garbage collection, that chunk of memory is cleaned so that other programs (or same program) can use it again.
Automatic garbage collection of cycles
Python handles its objects by keeping a count to the references each object have in the program, i.e each object stores how many times it is referenced in the program. This count is updated with the program runtime and when it reaches zero, this means it is not reachable from the program anymore. Hence, the memory for this object can be reclaimed and be freed by the interpreter.

Manual garbage collection

The garbage collector can be called manually in the following way:
import gc
collected = gc.collect()
print "Garbage collector: collected %d objects." % (collected)
gc.collect() returns the number of objects it has collected and deallocated. You can print this information in the following way:

By default Garbage collector is enabled, but we can disable based on our requirement. In this context we can use the following functions of gc module.

1) gc.isenabled()         Returns True if GC enabled
2) gc.disable()            To disable GC explicitly
3) gc.enable()             To enable GC explicitly

10) What is function decorator?

  • Decorators are used to wrap/cover a function within another function. It takes a function as argument and extend its functionality and return modified function with extended feature
  • The main objective of decorator is to extend the functionality of existing function without modifying it
def wish(name):
    print("Hello",name,"Good Morning")

This function can always print same output for any name
  • But we need modify this function to provide different message if name is “Seetha”,We can do this without modifying wish() function by using decorator.
def decor(func):
   def inner(name):
       if name=="Seetha":
          print("Hello Seetha Good Day!!")
      else:
          func(name)
   return inner

@decor
def wish(name):
    print("Hello",name,"Good Morning")
   
wish("Tina")
wish(“Seetha")

Output: Hello Tina Good Morning
               Hello Seetha Good Day!!

In the above program whenever we call wish() function automatically decor function will be executed.

11)What is lambda function ?

  • A function without any name. Nameless functions are called anonymous functions or lambda functions.
  • The main purpose of anonymous function is just for instant use or one time usage
  • It is a function-like callable that is not defined with a def statement.
  • Python lambdas are only a shorthand notation if you are too lazy to define a function.
Syntax of lambda Function:
lambda argument_list expression

Normal Function:

We can define by using def keyword.
def squareIT(n):
   return n*n

lambda Function:

We can define by using lambda keyword
lambda n:n*n

Advantages:

  1. By using Lambda Functions we can write concise code so that readability of the program will be improved.
  2. Lambda Function internally returns expression value and do not required to have return statement explicitly.
  3. Sometimes we can pass function as argument to another function. In such cases lambda functions are best choice.
  4. We can use lambda functions very commonly with filter(),map() and reduce() functions as these functions expect function as argument.
12) What are generator function ?
  • Generator is a function which contains yield statement/keyword
  • The difference between normal function and generator function is instead of returning one value with return statement, we can yield several values one at a time.
  • Based on yield statement, it allows to pause/freeze a function and return an immediate result. Generator function saves its execution context and so can be resumed later.
  • When generator function is called, the code in the function body is not executed but an iterator is returned
  • Return statement in the generator should stop the execution. Return can be called without arguments when it is used inside generator
Generators contains of two components:
  • generator-function
  • generator-iterator
Generator function is statements defined within function definition with yield statement
Generator iterator is what the function returns.Generally these two entities are treated as one and its called a generator

Example:
>>> def test_generator():
yield 1
...
>>> test_generator
<function test_generator at 19bb>

>>>test_generator()

<generator object at 163b>


13)Explain how to build command-line options in Python? OR How to read the values from the terminal?
  • The ‘argparse’ module is a command line interface. We will use ‘argparse’ module to read the values from the Terminal. 
  • The program defines what arguments it requires, and argparse will figure out how to parse those out of sys.argv.
Using the Python argparse library has four steps:
1)  Import the Python argparse library
2)  Create the parser
3)  Add optional and positional arguments to the parser
4)  Execute .parse_args()

Example:
import argparse
my_parser = argparse.ArgumentParser()
my_parser.add_argument('--input', action='store', type=int, required=True)
my_parser.add_argument('--id', action='store', type=int)

args = my_parser.parse_args()
print(args.input)

$ python test.py --in 42
42

Uses of the Python argparse Library
1) Setting the Name of the Program
2) Displaying a Custom Program Usage Help
3) Displaying Text Before and After the Arguments Help
4) Customizing the Allowed Prefix Chars
5) Setting Prefix Chars for Files That Contain Arguments to Be Included
6) Allowing or Disallowing Abbreviations
7) Using Auto Help

14)What are pros and cons of using generators?
Pros:
  • Saves Memory space - Iterators do not calculate the value of each item when instantiated. They compute it when its asked for. This is called lazy evaluation.Lazy evaluation is beneficial when we have large data set to compute. It allows us to use data immediately while the whole data set is being calculated.
  • Generators easy to implement as they inevitably implement next(), iter() & StopIteration or else had to be explicitly implemented.
  • Improves performance and are best suitable for reading data from large set of large files
  • Generators work best for web scraping and crawling 
Cons:
  • Generators can only be iterated over once. If we try to iterate over it again, no value will be returned. It will behave like an empty list.

15) Explain constructor overloading in Python? 
  • Constructor overloading is not possible in Python.
  •  If we define multiple constructors then the last constructor will be considered
class Test:
   def __init__(self):
       print('No-Arg Constructor')
   def __init__(self,a):
      print('One-Arg constructor')
t1=Test()
Output: Error

16) How to fetch shell environment variables in python?
>>> import os
>>> os.environ.keys( )
['WINBOOTDIR', 'PATH', 'USER', 'PP2HOME', 'CMDLINE', 'PYTHONPATH', 'TEMP', 'PROMPT', 'WINDIR', 'TMP']

17)What are abstract method?
  • Methods with only declaration and without implementation is called abstract method.
  • We can declare abstract method by using @abstractmethod decorator
  • @abstractmethod decorator is present in abc module. Hence it is required to import abc module, else it will throw an error.
class Sample:
@abstractmethod
 def test(self):
    pass
NameError: name 'abstractmethod' is not defined

from abc import *
class Sample:
@abstractmethod
def test(self):
    pass

18)Can we have Public, Protected and Private Attributes in Python?
Public:
In Python by default all attributes/members are Public. Hence it can be accessed anywhere within the class or from outside the class.
Ex : name = “Srishti”

class employee:
    def __init__(self, name, sala):
        self.name=name
        self.sala =sala

>>> e1=employee("Srishti",10000)
>>> e1.salary
10000
>>> e1.salary=20000
>>> e1.salary
20000

Protected:
  • Protected attributes/members of a class can be accessed within the class and available to its child classes only . No other environment is allowed  to access it 
  • We can specify an protected attribute in python by pre-fixing with _ (single underscore) symbol.

Syntax: _variablename = value
Eg: _name='Vanahalli'

class employee:
    def __init__(self, name, sala):
        self._name=name  # protected attribute 
        self._salary=sala # protected attribute

But it is just convention and in in reality protected attributes does not exist. Below operation is still possible
>>> e1=employee("Vanahalli", 10000)
>>> e1._salary
10000
>>> e1._salary=20000
>>> e1._salary
20000

Private:
  • Private attributes/members can be accessed within the class only. It is not accessible from outside the class or child classes
  • Private variables can be declared by explicitly pre-fixing double underscored __ . Any attempt to access it will result in AttributeError
syntax: __variablename=value

class employee:
    def __init__(self, name, sala):
        self.__name=name  # private attribute 
        self.__salary=sala # private attribute

>>> e1=employee("Bill",10000)
>>> e1.__salary
AttributeError: 'employee' object has no attribute '__salary'

19)How to Access Private Variables from Outside of the Class ?
  • Python internally performs name twisting of private variables/attributes. 
  • Every attribute with double underscore will be changed to object._classname__variable
  • Hence if we need to access private variables outside the class, we can do it as below. But this is not recommended.
class Sample:
def __init__(self):
    self.__x=20

x=Sample()
print(x._Sample__x)#20

20) What is the difference between del and None?
del
  • del is used to delete object and removes the binding of the variable
  • Since the variable will be removed, we cant access the variable  ( un bind operation)
a= “test”
del a
Print(a)  -> NameError: name a is not defined
None
  • In the case of None assignment, the variable will not be removed but the corresponding object is eligible for garbage collection ( re-bind operation).
  • Hence after assigning None value to the variable, we can still access it
a="test"
a=None
print(a) # None

21) Can tuples be modified?
Python tuple has amazing feature: they are immutable, but their values may change.
 This may happen when a tuple holds a reference to any mutable object, such as a list.

>>> t=(1,[1,2,3])
>>> t[1][2]=5
>>> t
(1, [1, 2, 5])
>>>

22)What is pass statement ?
  • pass is a keyword in Python.
  • To define an empty block we use pass keyword . It defined empty block with pass keyword
  • It is basically an empty/null statement  and doesn’t do anything
Example:
if True:
SyntaxError: unexpected EOF while parsing

if True: pass


def test():
SyntaxError: unexpected EOF while parsing

def test(): pass


use case of pass:
If we need parent class to contain a function with no implementation and expect child class method be responsible for code implementation, we can define parent class method using pass statement

23) What is super method in python?
super() is a built-in method which is used to call the super class constructors,variables and methods from the child class.
class Person1:
def __init__(self,name):
   self.name=name

def display(self):
  print('Name is :',self.name)

class Student1(Person1):
 def __init__(self,name,rollno):
   super().__init__(name)
   self.rollno=rollno

def display(self):
  super().display()
  print('Roll No:',self.rollno)

t1=Student1('Srishti',101)
t1.display()

Output:
Name is: Srishti
Roll No: 101

24) 
Explain about the special variable __name__?
  • Every python program will be added with a special variable __name__ 
  • This variable stores information about the program is executed as an individual program or as a module.
  • If the program is executed as individual program then this variable value will be __main__
  • If the program executed as a module from some other program then the value of this variable  will be name of module where it is defined.
  • Hence by using this __name__ variable we can identify whether the program executed directly or as module.
module1.py:
def func():
    if __name__=='__main__':
      print("The code executed as main pgm")
 else:
    print("The code executed as a module “)

func()

test.py:
import module1
module1.func()

 C:\Python>python module1.py
 The code executed as main pgm

 D:\Python>python test.py
The code executed as a module


25) What is shallow copy?
  • Shallow copy of any python object makes a copy of the object itself . It also creates reference to the objects contained in the list
  • Shallow copy can be achieved by slice operator
>>>Vowel = [‘a’,’e’,’I’,’o’,’u’]
>>>V_copy = Vowel[:]
>>> Vowel is V_copy
0
>>>Vowel == V_copy
1
We can use copy(object) func of the copy module
>>import copy
>>high = copy.copy(Vowel)
>>> high is Vowel, high == Vowel
(0,1)

26) what is use of setdefault() method?
  • The setdefault() method allows to set a value in dictionary for certain key if that key does not previously have a value 
  • It takes key to check for as the first element and value to set at the key as second.
  • If key does exits, then this method method returns key’s value.
msg = ' Srishti'
cnt = {}
for c in msg:
   cnt.setdefault(c, 0)
   cnt[c] = cnt[c] + 1
print(cnt)

Output
C:/TEST_PGMS> python test.py

{' ': 1, 'S': 1, 'r': 1, 'i': 2, 's': 1, 'h': 1, 't': 1}
  • The program loops over each character in the msg,counting how often each character seems. 
  • The setdefault() method call ensures that the key is in the cnt dictionary (with a default value of 0) so the program doesn’t toss a KeyError error when cnt[c] = cnt[c] + 1 is performed.
27) What are different types of function arguments in Python?

In a function func1 – x,y are called formal arguments and 1,2 are called actual arguments
def func1 (x , y): pass
func1(1,2)

There are 4 types are actual arguments are allowed in Python.
1. Positional argument
2. Keyword argument
3. Default argument
4. Variable length argument

1. Positional arguments: 
  • These are the arguments need to be passed to function in precise positional order.
  • The number of arguments and position of arguments must match. If we change the order the result would be changed. If number of arguments differ, it will result in Error
  • Positional-only parameters are placed before a / (forward-slash). The / is used to logically distinct the positional-only parameters from the rest of the parameters
def pos_only_arg(arg, /):
     print(arg)

def sub(x,y):
   print(x-b)

sub(20,40)
sub(40,20)

2. Keyword arguments/ named arguments                    
  • We can pass argument values by keyword and a = sign
  • Keyword is the key or parameter name and value is the value or object to be passed as that keyword
  • The order of the arguments does not matter but number of arguments must be matched
  • To notify parameters as keyword-only, representing parameters must be passed by keyword argument, place an * in the arguments list just before the first keyword-only parameter.
def kwd_only_arg(*, arg):
    print(arg)

def hello(name,msg):
   print("Hello",name,msg)
   hello(name="Satish",msg="Good Morning")

Output

Hello Satish Good Morning

Note: In a function call, we can have positional and keyword arguments together specified. Always Positional arguments must be at the beginning followed by keyword arguments if not we get Syntax error

def test(volume, number='hello', action='sum’, type='Red'): pass

Valid:
test(volume=10)                                          # 1 keyword argument
test(volume =100, action='done')                 # 2 keyword arguments
test(action='done’, volume =100)                # 2 keyword arguments
test('this', 'is', 'positional')                          # 3 positional arguments
test('hundred', number='I am number')       # 1 positional, 1 keyword

Invalid
test(actor='Deepika')                  # unknown keyword argument
test()                                        # required argument missing
test(volume=2.0, '200')              # non-keyword argument after a keyword argument
test(110, volume=220)              # duplicate value for the same argument

3. Default argument
  • Default arguments are those positional arguments that take default values if no explicit values are passed to these arguments from the function call.
  • Let's define a function with one default argument.
def find_one(int1=2, int2=3):
    result = int1 * int2
    return result

4. Variable length arguments
  •  We can create functions to accept any number of arguments. These functions can accept an unknown amount of input, also as successive entries or named arguments.
  • we can use the *args or **kwargs syntax to capture a variable number of arguments in functions. By adding * and ** (one or two asterisks) to the beginning of parameter name in the function definition we can specify an arbitrary/varibale number of arguments
def test_varargs(*args, **kwargs):
    print(args)
    print(kwargs)

*args: Receive multiple arguments as a tuple
**kwargs: Receive multiple keyword arguments as a dictionary

NOTE
When mingling the positional and named arguments, positional arguments should come before named arguments. Additionally, arguments of a fixed length come before arguments with variable length. So, we can order like below:
1) Known positional arguments
2) *args
3) Known named arguments
4) **kwargs

A function with all types of arguments will be like 
def all_in_one_function (number1, number2, *args, callmeback=None, msgs=[], **kwargs):
    pass

28) How to detect the scope of a Variable ?
  • Python has two built-in methods called globals() and locals(). 
  • They let us determine whether a variable is either part of the global namespace or local namespace. 
  • The following example shows how to use these methods:
def test():
     global address
    address = "bangalore"
    name = "Satish"
    
    print("Address in global:", 'Address' is globals())
    print("Address in local :", ' Address ' in locals())
    print("name in global :", 'name' in globals())
    print("name in local  :", 'name' in locals())
    return

address = "Gadag"
print (address)
test()

The output is as below and display the scope of the two variables address and name inside the function test():

$ python test.py
Gadag
Address in global: True
Address in local : False
name in global : False
name in local  : True

29) Explain different types of variables in python? 
A variable is an concept for the memory cells that contain the actual value. It is easy to remember the name of the memory cell than  to recall its physical memory address. 
All the variables are portion of the some namespace and hence have the some scope. 

Unless redefined as a local variable well along  a variable defined in the main program belongs to the global namespace, that can be accessed by any function in the Python program

Python supports 2 types of variables.
1. Global Variables
2. Local Variables
3. Nonlocal variable(only from Python3)

1. Global Variables
  • The variables which are declared outside of function are called global variables.
  • These variables can be accessed in all functions of that module.
  • A variable cannot be be both local and global inside any function. 
  • Python will decide that we want a local variable due to the assignment to s inside test(), so the first print statement before the definition of s throws the error message. Any variable which is altered or created inside a function is local, if it is not been declared as a global variable. 
  • To express Python that we want to use the global variable, we have to clearly tell this by using the keyword "global", as seen in the following example:
Example1:
def test():
    global s
    print(s)
    s = "Only in winter Bangalore weather is Good"
    print(s)

s = "I am looking for python course"
test()
print(s)

Output:
I am looking for python course
Only in winter Bangalore weather is Good 
Only in winter Bangalore weather is Good

Example2:
a=100 # global variable
def func1():
   print(a)

def func2():
    print(a)

func1()

func2()

Output

100
100

NOTE:We can use global keyword for the following  purposes:
1. To declare global variable inside function
2. To make global variable available to the function so that we can perform required alterations

2. Local Variables:
  • The variables which are declared inside a function are called local variables.
  • Local variables are available only for the function in which we its declared i.e from outside of function we cannot access.
def fun1():
   a=10
   print(a) # valid

def fun2():
   print(a) #invalid

 fun1()

 fun2()

 NameError: name 'a' is not defined

3) Nonlocal Variables
  • Nonlocal variables are used in nested functions whose local scope is not defined. This means that the variable can be neither in the local nor the global scope.
  • One difference to global variables is that its not possible to change variables from the module scope, i.e. variables which are not defined inside of a function by using the nonlocal statement.
  • We use nonlocal keyword to create nonlocal variables.
  def out():
      x = "out_func"

  def in():      
     nonlocal x
     x = "nonlocal_var"
     print("in:", x)

  
in()    
  print("out:", x)

 out()

Output:
In:nonlocal_var
out:out_func

30)Why is python string immutable
  • Improved performance. String is immutable hence we can allocate space for it during creation time and the storage necessities are fixed and remains unchanged.
  • Strings in Python are measured as “fundamental” as numbers
31)Difference between is and == 
• An is expression evaluates to True if two variables point to the same (identical) object.
• An == expression evaluates to True if the objects referred to by the variables are equal (have the same contents).
Example1:
>>> a = (1,2,3)
>>> b=(1,2,3)
>>> a == b
True
>>> a is b
False
>>> id(a), id(b)
(671301, 789098)

Example2:
>>> c=a
>>> c
('1',’2’,’3’)
>>> c == a
True
>>> c is a    # because c and a refer to the same object
True

32) Function vs Module vs Library
1. A group of lines with a name is called a function
2. A group of functions saved to a file  is called Module
3. A group of Modules is called Library

33)How to run Other Programs from Python Program

Method 1 OS Module contains system() function to run programs and commands.
os.system("commad string").The argument is any command which is executing from DOS.
import os
os.system("dir *.py")
os.system("py test.py")

Method 2:
To run an external command without interacting with it, as we do with os.system() we can use the call() function from subprocess module.
import subprocess
# Simple command
subprocess.call(['ls', '-1'], shell=True)

The command line arguments are passed as a list of strings, which avoids the need for escaping quotes or other special characters that might be interpreted by the shell.

The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several older modules and functions:
os.system
os.spawn*

34)Explain about the hashable objects in python?
  • An object is hashable if it has a hash value which never alters during its lifetime (it needs a __hash__() method) and can be compared to other objects (it needs an __eq__() or __cmp__() method).  Hashable objects which compare equal must have the same hash value.
  • Hashable objects are integers, floats, strings, tuples, and frozensets. Note that all hashable objects are also immutable objects.
  • Objects which are instances of user-defined classes are hashable by default, they all compare unequal, and their hash value is their id().
  • The key of a dictionary should be unique. Internally, the key is transformed by a hash function and become an index to a memory where the value is stored. Suppose, if the key is changed, then it will be pointing somewhere else and we lose the original value the the old key was pointing.
  • Tuples are not always hashable because tuples may hold references to unhashable objects such as lists or dicts. A tuple is only hashable if all of its items are hashable 
>>> t1 = (109, 'Z', frozenset([1, 2, 3]))
>>> t2 = (1, 'r', {1, 2, 3})
>>> hash(t1)  # OK!
1315572702399614049
>>> hash(t2)  # NOT OK!
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
  • Mutable objects are lists, dictionaries, and sets which are not hashable
35)  How to identify data type of any object in python?
We can retrieve type of any object by passing the object to type(obj) function.
>>> i=10
>>> type(i)
<class 'int'>
>>> x = (1,2)
>>> type(x)
<class 'tuple'>

36) What is Namedtuple?
  • Namedtuple is a tuple where each value has a pre-assigned name
  • Namedtuples are immutable containers similar to regular tuples. Once we save data in top-level attribute on a namedtuple, we cannot alter them by  updating the attribute. All attributes on a namedtuple object follow the principle -  “write once, read many”
  • Each object stored in namedtuple can be retrieved through a unique,human-readable identifier and we do not have to remember integer indexes.
  • A named tuple can be accessed like a class attribute
  • Named tuples that are available from the collections module can be used to access values with object notation as shown below:
>>> from collections import namedtuple
>>> student = namedtuple('student','name,marks')
>>> s1 = student('satish',150)
>>> s1.name
'satish'
>>> s1.marks
150
>>> type(s1)
<class '__main__.student'>

38)Why must dictionary keys be immutable?
  • The hash table implementation of dictionaries uses a hash value calculated from the key value to find the key. If the key were a mutable object, its value could alter and thus its hash could also change.
  • But since whoever changes the key object can’t tell that it was being used as a dictionary key, it can’t move the entry around in the dictionary. Then, when you try to look up the same object in the dictionary it won’t be found because its hash value is different. If you tried to look up the old value it wouldn’t be found either, because the value of the object found in that hash bin would be different.
  • If you want a dictionary indexed with a list, then convert the list to a tuple first,  the function tuple(L) creates a tuple with the same entries as the list L. Tuples are immutable and can therefore be used as dictionary keys.
39) How do you read an entire file?
  • Python provides numerous methods to read the entire contents of a file. 
  1. open the file and call the read() function. This will read the entire contents of the file until an EOF marker is met and returns the contents of the file as a string.
  2. open the file and use the readlines() function. This reads the entire contents of the file, separating each line into individual strings, until an EOF marker is reached. Once the end of the file is found, a list of strings representing each line is returned.
  3. In case of very large files we might want to read only a specific number of bytes at a time.Then use the read(bytes) function to read a specific number of bytes at a time, which can then be processed more easily. This will read a specific number of bytes from the file if possible and return them as a string. If the first character read is an EOF marker, null is returned.
filePath = "input.txt"

#Read entire file into a buffer
buffer = open(filePath, 'rU').read()
print buffer

#Read lines into a buffer
inList = open(filePath, 'rU').readlines()
print inList

#Read bytes 
file = open(filePath, 'rU')
bytes = file.read(5)
if bytes:
    print bytes

osx-$ python t.py
hi
hello
line
ends
here

['hi\n', 'hello\n', 'line\n', 'ends\n', 'here\n']
hi
he


40) How do you swap keys for Values in a dictionary?
  • This is useful when we are using dictionary in which we often need to look up items by value. Rather than searching through the entire dictionary each time, we could create an alternate dictionary that has the values swapped.
  • To swap the keys and values in a dictionary  iterate through the items in the dictionary using the iteritems method and use the values as keys assigning the original key as the value.
myDict = {'colour':'red', 'nu':6}
#Swap keys for value
swapDict = {}
for key, val in myDic.iteritems():
    swapDict[val] = key

print swapDic

OUTPUT:

{'red': 'colour', 6: 'nu'}

41) How do you list directory tree or walking the directory tree in python?

  • The walk(path) function will walk the directory tree, and for each directory in the tree create a three-tuple containing (1) the dirpath, (2) a list of dirnames, and (3) a list of filenames.
  • Every tuple contains 

  1. Index 0 - path to the directory
  2. Index 1 - Lists of the subdirectories
  3. Index 2 - files contained in the directory
import os
tree = os.walk('/Users/qauser')
for directory in tree:
    print(directory)

Output
('/tmp/test', [], ['file2', 'fil1'])

42) Explain zip() to process iterators in parallel ?
  • Zip aggregates two or more iterators with a lazy generator. The zip generator yields tuples containing the next value from each iterator. It takes iterables (can be zero or more) wrap them in a tuple and return it
  • It keeps yielding tuples until a wrapped iterator is exhausted. . This method works if the iterators are of the same length 
  • zip truncates its output silently if you supply it with iterators of different lengths.
  • Note: The zip_longest function from the itertools built-in module let us iterate over multiple iterators in parallel regardless of their lengths
Return Value from zip()
  • If we do not pass any parameter, zip() returns an empty iterator
  • If a single iterable is passed, zip() returns an iterator of tuples with each tuple having only one element.
  • If multiple iterables are passed, zip() returns an iterator of tuples with each tuple having elements from all the iterables.
  • Suppose, two iterables are passed to zip(); one iterable containing four and other containing six elements. Then, the returned iterator will contain four tuples. It is because iterator stops when the shortest iterable is exhausted.
n_list = [5, 6, 7]
s_list = ['five', 'six', 'seven']

# No iterables are passed
result = zip()

# Converting itertor to list
r_list = list(result)
print(r_list)

# Two iterables are passed
result = zip(n_list, s_list)
print(result)

# Converting itertor to set
result_set = set(result)
print(result_set)

Output:
 []
[(5, 'five'), (6, 'six'), (7, 'seven')]
set([(6, 'six'), (5, 'five'), (7, 'seven')])

43)How to pass command line arguments in python?
  • Python standard library called sys and we use an attribute/variable within the module called argv.
  • The sys.argv variable is a list containing the command-line parameters passed to the program on startup 
  • The first item in the sys.argv list will always be a string holding the program’s filename ('test.py'), and the second item will be the first command line argument
import sys
if __name__ == "__main__":
   print(sys.argv)

Output:
$ python a.py test this
['a.py', 'test', 'this']

44) How do you find the number of lines in a file?
  • When parsing files using Python, it's useful to know exactly how many lines are contained in the file. 
  • It is done by using readlines() to generate a list of lines and using the len() function to determine the number of lines in the list
filePath = "input.txt"
cnt = len(open(filePath, 'rU').readlines())
print "File %s has %d lines." % (filePath,cnt)

Output:
File input.txt has 4 lines.

45)How to raise your own errors?
  • We have to define and raise exceptions explicitly to indicate that error ,such type of exceptions are called User Defined Exceptions or Customized Exceptions
  • You can manually throw (raise) an exception in Python with the keyword raise. This is usually done for the purpose of error-checking.
  • Programmer is responsible to define these exceptions . Hence we need to raise explicitly based on the requirement by using "raise" keyword.
  • An exception can be a string, a class or an object
  • Note:
    raise keyword is best suitable for customized exceptions but not for pre defined
    exceptions
if line_count < 1:
   raise error

46) Explain generator function with an example?
A generator object is a Python iterator, so we can use it in for loop
Example:
def test_gen():
    z = 0
        while z < 2:
          yield z
          z += 1

>>>num = test_gen()
>>> type(num)
<class 'generator'>
>> for n in num:
...     print(num)
0
1
You can also step through one by one, using the built-in next() function:
>>> more_num = test_gen()
>>> next(more_num)
0
>>> next(more_num)
1

>>> next(more_num)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
  • StopIteration is built-in exception type. It inevitably raised once the generator stops yielding. 
  • It is a signal to for loop to stop looping. Instead we can pass a default value as the second argument to next():
>>> next(more_num, 40)
40

47)How to create dictionaries from lists
k = ['Toy', 'Game', 'Tiger']
v = ['Toys', 'Games', 'Tigers']
#create dict
dc = dict(zip(k, v))
print(dc)
# {'Game': 'Games', 'Tiger': 'Tigers', 'Toy': 'Toys'}
d = dict(enumerate(v))
print(d)
# {0: 'Toys', 1: 'Games', 2: 'Tigers'} 

48) Explain Python's documentation tool?
  • Sphinx is the most widespread Python documentation tool.
  • It converts the reStructured Text markup language into a range of output formats, including HTML, LaTeX (for printable PDF versions), manual pages, and plain text.
  • It can be  configured with commit hooks to the source repository so that rebuilding of the documentation will happen automatically
  • reStructured Text Sphinx uses reStructured Text and all Python documentation is written using it. If the content of the long_description argument to setuptools.setup() is written in reStructured Text, it will be condensed as HTML on PyPI—other formats will just be presented as text. 
  • Docstrings placed at the beginning of a module or at the top of an __init__.py file will also appear in help(). Sphinx’s autodoc feature can also automatically generate docu‐ mentation using appropriately formatted docstrings. 
Docstring and Block Comments 
# This is programmer note
def root(x):
 """Return the square root""" 
 …..
1)  The leading comment block is a programmer’s note. 
2)  The docstring describes the operation of the function or class and will be shown in an interactive Python session when the when the user types help(root).

49) What is Base case in recursive function?
  • A base case is a case, where the problem can be solved without further recursion. A recursion can end up in an infinite loop, if the base case is not met in the calls.
  • The base case returns a value without making any subsequent recursive calls. It does this for one or more special input values for which the function can be evaluated without recursion. For factorial(), the base case is n = 1.
50) How to count occurrences of a character in a Python string?

1. str.count() function

A simple and efficient solution is to get the number of occurrences of a character in string is using the str.count() method. This is best solution to count a single character in a string.

if __name__ == '__main__':
 
    s = "ABADACB"
     n = s.count('A')
    print(n)     # 3
 
2. collections.Counter class
If you need to find frequency of several characters, calling str.count() method for each character is not recommended. Instead, you should use collections. Counter Python class. It works by storing each character as dictionary keys and their counts as dictionary values.

import collections
 
if __name__ == '__main__':
 
    s = "ABADACB"
    counter = collections.Counter(s)
    n = counter['A']
    print(n)     # 3

The Counter class takes linear time to pre-process the string and offers constant time count operations. However, it occupies some space to store the frequency of each character.

3. Using Dictionary
As an alternate to the collections.Counter class, you can also construct a simple dictionary. The idea is to store each character as dictionary keys and their counts as dictionary values.

if __name__ == '__main__':
 
    s = "ABADACB"
 
    chars = dict.fromkeys(s, 0)
    for c in s:
        chars[c] += 1
 
    n = chars['A']
    print(n)     # 3

4. Regular Expressions
You can also use regular expressions to count the number of occurrences of a character in string. However, regular expressions should be best avoided for this trivial task.

import re
 
if __name__ == '__main__':
 
    s = "ABADACB" 
    n = len(re.findall('A', s))
    print(n)     # 3
 
5. Lambda expressions

Finally, here’s solution using lambda:

if __name__ == '__main__':
 
    s = "ABADACB" 
    n = sum(map(lambda x: 1 if x == 'A' else 0, s))
    print(n)     # 3

51) How do you return Multiple Values in Python
In Python, we can return multiple values from a function. Following are different ways
1) Using Object: This is similar to C/C++ and Java, we can create a class (in C, struct) to hold multiple values and return an object of the class.
# A Python program to return multiple   values from a method using class 
class Test: 
    def __init__(self): 
        self.str = "testfortst"
        self.x = 20   
  
# This function returns an object of Test 
def fun(): 
    return Test() 
      
# Driver code to test above method 
t = fun()  
print(t.str) 
print(t.x) 

Output:
testfortst
20

2) Using Tuple: A Tuple is a comma separated sequence of items. It is created with or without (). Tuples are immutable. See this for details of tuple and list.
# A Python program to return multiple  values from a method using tuple 
  
# This function returns a tuple 
def fun(): 
    str = "testfortst"
    x   = 20
    return str, x;  # Return tuple, we could also 
                    # write (str, x) 
  
# Driver code to test above method 
str, x = fun() # Assign returned tuple 
print(str) 
print(x) 

3) Using a list: A list is like an array of items created using square brackets. They are different from arrays as they can contain items of different types. Lists are different from tuples as they are mutable.

# A Python program to return multiple values from a method using list 
# This function returns a list 
def fun(): 
    str = "testfortst"
    x = 20   
    return [str, x];   
  
# Driver code to test above method 
list = fun()  
print(list) 

Output:
['testfortst',20]

4) Using a Dictionary: A Dictionary is similar to hash or map in other languages. See this for details of dictionary.
# A Python program to return multiple  values from a method using dictionary 
 # This function returns a dictionary 
def fun(): 
    d = dict();  
    d['str'] = "testfortst"
    d['x']   = 20
    return d 
  
# Driver code to test above method 
d = fun()  
print(d) 

Output:
{'x': 20, 'str': '"testfortst"'}

5) Using Data Class (Python 3.7+): In Python 3.7 and above the Data Class can be used to return a class with automatically added unique methods. The Data Class module has a decorator and functions for automatically adding generated special methods such as __init__() and __repr__() in the user-defined classes.

from dataclasses import dataclass 
  
@dataclass
class Book_list: 
    name: str
    perunit_cost: float
    quantity_available: int = 0
          
    # function to calculate total cost     
    def total_cost(self) -> float: 
        return self.perunit_cost * self.quantity_available 
      
book = Book_list("Introduction to programming.", 300, 3) 
x = book.total_cost() 
  
# print the total cost 
# of the book 
print(x) 
  
# print book details 
print(book) 
  
# 900 
Book_list(name='Python programming.', 
          perunit_cost=200, 
          quantity_available=3) 

Output:

900

Book_list(name='Introduction to programming.', perunit_cost=300, quantity_available=3)

Book_list(name='Python programming.', perunit_cost=200, quantity_available=3)

52)What are different  ays to remove duplicates from list
Method 1 : Naive method
In naive method, we simply traverse the list and append the first occurrence of the element in new list and ignore all the other occurrences of that particular element.
# Python 3 code to demonstrate  removing duplicated from list   using naive methods  
  # initializing list 
test_list = [1, 3, 5, 6, 3, 5, 6, 1] 
print ("The original list is : " +  str(test_list)) 
  
# using naive method  to remove duplicated   from list  
res = [] 
for i in test_list: 
    if i not in res: 
        res.append(i) 
  
# printing list after removal  
print ("The list after removing duplicates : " + str(res)) 

Method 2 : Using list comprehension
This method has working similar to the above method, but this is just a one-liner shorthand of longer method done with the help of list comprehension.

# Python 3 code to demonstrate  removing duplicated from list  using list comprehension 
# initializing list 
test_list = [1, 3, 5, 6, 3, 5, 6, 1] 
print ("The original list is : " +  str(test_list)) 
  
# using list comprehension to remove duplicated  from list  
res = [] 
[res.append(x) for x in test_list if x not in res] 
  
# printing list after removal  
print ("The list after removing duplicates : " + str(res)) 

Method 3 : Using set()
This is the most popular way by which the duplicated are removed from the list. But the main and notable drawback of this approach is that the ordering of the element is lost in this particular method.
# Python 3 code to demonstrate  removing duplicated from list   using set() 
 # initializing list 
test_list = [1, 5, 3, 6, 3, 5, 6, 1] 
print ("The original list is : " +  str(test_list)) 
  
# using set() to remove duplicated  from list  
test_list = list(set(test_list)) 
  
# printing list after removal  
# distorted ordering 
print ("The list after removing duplicates : " + str(test_list)) 

Method 4 : Using list comprehension + enumerate()
list comprehension coupled with enumerate function can also achieve this task. It basically looks for already occurred elements and skips adding them. It preserves the list ordering.

# Python 3 code to demonstrate removing duplicated from list  using list comprehension + enumerate() 
 # initializing list 
test_list = [1, 5, 3, 6, 3, 5, 6, 1] 
print ("The original list is : " +  str(test_list)) 
  
# using list comprehension + enumerate()  to remove duplicated  from list  
res = [i for n, i in enumerate(test_list) if i not in test_list[:n]] 
  
# printing list after removal  
print ("The list after removing duplicates : " + str(res)) 

Method 5 : Using collections.OrderedDict.fromkeys()
This is fastest method to achieve the particular task. It first removes the duplicates and returns a dictionary which has to be converted to list. This works well in case of strings also 

# Python 3 code to demonstrate  removing duplicated from list  
# using  collections.OrderedDict.fromkeys() 
from collections import OrderedDict 
  
# initializing list 
test_list = [1, 5, 3, 6, 3, 5, 6, 1] 
print ("The original list is : " +  str(test_list)) 
  
# using collections.OrderedDict.fromkeys()  to remove duplicated   from list  
res = list(OrderedDict.fromkeys(test_list)) 
  
# printing list after removal  
print ("The list after removing duplicates : " + str(res)) 


53)Explain Map,Reduce and filter function?
1) Map() Function
This function takes two arguments. The first argument in the function is the name of function and the second is the sequence or the list.

Syntax: map(func, seq)

Let’s take a look at map() function with example of a list.
a=[1,2,3,4]
b=[2,3,4,5]
c=map(lambda x,y:x+y, a,b)
print(list(c))
Output: [3, 6, 9, 12]

Note: If you don’t print it as a list(c) then chances are there that output will be printed as a map object. So you have to print it as a list.

Like the above example you can also evaluate some more mathematical expressions and check the list as a boolean output. For example, make a list with number divisible and non-divisible by 2. Now add that condition in the lambda function expression and then get the output as a list. You’ll find that it prints true and false output.

2) Filter() Function
Like map() function this filter() function also takes two arguments – func and list. Let’s take an example to see how the filter() function works.

b=[2,3,4,9]
c=filter(lambda x:x%3==0,b)
print(list(c))
Output: 3,9

You see filter() function removes the list items that are not divisible by 3. It only displays the two items that qualifies for the same. So the list argument in the filter function only returns value that are true as per the condition.

3) Reduce() function
Reduce function is not available in python 3.x. You can skip this section if you’re using the new version of python. In case if you wish to use this function, you can use functools.reduce() instead. Reduce() function takes two arguments and the seq/list item continually evaluates until the last item. This way the list/sequence is reduced as per the arithmetical expression condition.

Let’s take a look at example to see how it works.
a=[1,2,3,4]
reduce(lambda x,y:x>y, a)
Output: false

This sums up our small tutorial on python lambda functions. You can keep tab on python 3.x version updates to see changes to the lambda functions. 

54) Explain Underscore (_) in Python
Following are different places where _ is used in Python:

A. Single Underscore:
  1. In Interpreter
  2. After a name
  3. Before a name
B. Double Underscore:
  1. __leading_double_underscore
  2. __before_after__
A.Single Underscore
In Interpreter:
_ returns the value of last executed expression value in Python Prompt/Interpreter

>>> a = 10
>>> b = 10
>>> _
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_' is not defined
>>> a+b
20
>>> _
20
>>> _ * 2
40
>>> _
40
>>> _ / 2
20

For ignoring values:

Multiple time we do not want return values at that time assign those values to Underscore. It used as throwaway variable.
# Ignore a value of specific location/index
for _ in range(10)
    print ("Test")
  
# Ignore a value when unpacking
a,b,_,_ = my_method(var1)


After a name
Python has their by default keywords which we can not use as the variable name. To avoid such conflict between python keyword and variable we use underscore after name

>>> class MyClass():
...     def __init__(self):
...             print ("OWK")
  
>>> def my_defination(var1 = 1, class_ = MyClass):
...     print (var1)
...     print (class_)
  
>>> my_defination()
1
__main__.MyClass
>>>


Before a name
Leading Underscore before variable/function/method name indicates to programmer that It is for internal use only, that can be modified whenever class want.

Here name prefix by underscore is treated as non-public. If specify from Import * all the name starts with _ will not import. Python does not specify truly private so this ones can be call directly from other modules if it is specified in __all__, We also call it weak Private


class Prefix:
...     def __init__(self):
...             self.public = 10
...             self._private = 12
>>> test = Prefix()
>>> test.public
10
>>> test._private
12

Python class_file.py
def public_api():
    print ("public api")
  
def _private_api():
    print ("private api")


Calling file from Prompt
>>> from class_file import *
>>> public_api()
public api
  
>>> _private_api()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_private_api' is not defined
  
>>> import class_file
>>> class_file.public_api()
public api
>>> class_file._private_api()
private api


B. Double Underscore(__)

__leading_double_underscore
Leading double underscore tell python interpreter to rewrite name in order to avoid conflict in subclass. Interpreter changes variable name with class extension and that feature known as the Mangling.

testFile.py
class Myclass():
    def __init__(self):
        self.__variable = 10


Calling from Interpreter
>>> import testFile
>>> obj = testFile.Myclass()
>>> obj.__variable
Traceback (most recent call last):
File "", line 1, in
AttributeError: Myclass instance has no attribute '__variable'
nce has no attribute 'Myclass'
>>> obj._Myclass__variable
10

In Mangling python interpreter modify variable name with ___. So Multiple time It use as the Private member because another class can not access that variable directly. Main purpose for __ is to use variable/method in class only If you want to use it outside of the class you can make public api

class Myclass():
    def __init__(self):
        self.__variable = 10
    def func(self)
        print (self.__variable)

Calling from Interpreter
>>> import testFile
>>> obj = testFile.Myclass()
>>> obj.func()
10

__BEFORE_AFTER__
Name with start with __ and ends with same considers special methods in Python. Python provide this methods to use it as the operator overloading depending on the user.

Python provides this convention to differentiate between the user defined function with the module’s function

class Myclass():
    def __add__(self,a,b):
        print (a*b)

Calling from Interpreter

>>> import testFile
>>> obj = testFile.Myclass()
>>> obj.__add__(1,2)
2
>>> obj.__add__(5,2)
10