Python interview questions

Python quiz questions

  • 1.

    Which statement of Python is used whenever a statement is required syntactically but the program needs no action?

    Answer:

    Pass – is no-operation / action statement in Python
    If we want to load a module or open a file, and even if the requested module/file does not exist, we want to continue with other tasks. In such a scenario, use try-except block with pass statement in the except block.
    Eg:

     try:import mymodulemyfile = open(“C:\myfile.csv”)except:pass
    View
  • 2.

    Explain how to overload constructors or methods in Python.

    Answer:

    Python’s constructor – _init__ () is a first method of a class. Whenever we try to instantiate a object __init__() is automatically invoked by python to initialize members of an object.

    View
  • 3.

    As Everything in Python is an Object, Explain the characteristics of Python’s Objects.

    Answer:

    • As Python’s Objects are instances of classes, they are created at the time of instantiation. Eg: object-name = class-name(arguments)
    • one or more variables can reference the same object in Python
    • Every object holds unique id and it can be obtained by using id() method. Eg: id(obj-name) will return unique id of the given object.
    every object can be either mutable or immutable based on the type of data they hold.
    • Whenever an object is not being used in the code, it gets destroyed automatically garbage collected or destroyed
    • contents of objects can be converted into string representation using a method

    View
  • 4.

    Explain Python’s pass by references Vs pass by value . (or) Explain about Python’s parameter passing mechanism?

    Answer:

    In Python, by default, all the parameters (arguments) are passed “by reference” to the functions. Thus, if you change the value of the parameter within a function, the change is reflected in the calling function.We can even observe the pass “by value” kind of a behaviour whenever we pass the arguments to functions that are of type say numbers, strings, tuples. This is because of the immutable nature of them.

    View
  • 5.

    Explain Python’s zip() function.?

    Answer:

    zip() function- it will take multiple lists say list1, list2, etc and transform them into a single list of tuples by taking the corresponding elements of the lists that are passed as parameters. Eg:

    list1 = ['A',
    'B','C'] and list2 = [10,20,30].
    zip(list1, list2) # results in a list of tuples say [('A',10),('B',20),('C',30)]

    whenever the given lists are of different lengths, zip stops generating tuples when the first list ends.

    View
  • 6.

    Whenever Python exists Why does all the memory is not de-allocated / freed when Python exits?

    Answer:

    Whenever Python exits, especially those python modules which are having circular references to other objects or the objects that are referenced from the global namespaces are not always de – allocated/freed/uncollectable.
    It is impossible to deallocate those portions of memory that are reserved by the C library.
    On exit, because of having its own efficient clean up mechanism, Python would try to deallocate/
    destroy every object.

    View
  • 7.

    Explain how Python does Compile-time and Run-time code checking?

    Answer:

    Python performs some amount of compile-time checking, but most of the checks such as type, name, etc are postponed until code execution. Consequently, if the Python code references a user -defined function that does not exist, the code will compile successfully. In fact, the code will fail with an exception only when the code execution path references the function which does not exists.

    View
  • 8.

    Does the functions help() and dir() list the names of all the built_in functions and variables? If no, how would you list them?

    Answer:

    No. Built-in functions such as max(), min(), filter(), map(), etc is not apparent immediately as they are
    available as part of standard module.To view them, we can pass the module ” builtins ” as an argument to “dir()”. It will display the
    built-in functions, exceptions, and other objects as a list.>>>dir(__builtins )
    [‘ArithmeticError’, ‘AssertionError’, ‘AttributeError’, ……… ]

    View
  • 9.

    Which command do you use to exit help window or help command prompt?

    Answer:

    quit
    When you type quit at the help’s command prompt, python shell prompt will appear by closing the help window automatically.

    View
  • 10.

    How are the functions help() and dir() different?

    Answer:

    These are the two functions that are accessible from the Python Interpreter. These two functions are used for viewing a consolidated dump of built-in functions.

    help() - it will display the documentation string. It is used to see the help related to modules, keywords, attributes, etc.
    
    To view the help related to string datatype, just execute a statement help(str) – it will display the documentation for 'str, module.
    ◦ Eg: >>>help(str) or
    >>>help() - it will open the prompt for help as help>
    
     to view the help for a module, help> module module name
    Inorder to view the documentation of 'str' at the help>, type help>modules str
    
    to view the help for a keyword, topics, you just need to type, help> “keywords python-
    keyword” and “topics list”
    
     dir() - will display the defined symbols.
     Eg: >>>dir(str) – will only display the defined symbols.
    View
  • 11.

    Compare Java & Python

    Answer:

    Criteria Java Python
    Ease of use Good Very Good
    Speed of coding Average Excellent
    Data types Static typed Dynamically typed
    Data Science & machine learning applications Average Very Good
    View
  • 12.

    Place the following functions below in order of their efficiency. They all take in a list of numbers between 0 and 1. The list can be quite long. An example input list would be [random.random() for i in range(100000)]. How would you prove that your answer is correct?

    
    def f1(lIn):
        l1 = sorted(lIn)
        l2 = [i for i in l1 if i<0.5]
        return [i*i for i in l2]
    
    def f2(lIn):
        l1 = [i for i in lIn if i<0.5]
        l2 = sorted(l1)
        return [i*i for i in l2]
    
    def f3(lIn):
        l1 = [i*i for i in lIn]
        l2 = sorted(l1)
        return [i for i in l1 if i<(0.5*0.5)]

    Answer:

    Most to least efficient: f2f1f3. To prove that this is the case, you would want to profile your code. Python has a lovely profiling package that should do the trick.

    import cProfile
    lIn = [random.random() for i in range(100000)]
    cProfile.run('f1(lIn)')
    cProfile.run('f2(lIn)')
    cProfile.run('f3(lIn)')
    

    For completion's sake, here is what the above profile outputs:

    >>> cProfile.run('f1(lIn)')
             4 function calls in 0.045 seconds
    
       Ordered by: standard name
    
       ncalls  tottime  percall  cumtime  percall filename:lineno(function)
            1    0.009    0.009    0.044    0.044 :1(f1)
            1    0.001    0.001    0.045    0.045 :1()
            1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
            1    0.035    0.035    0.035    0.035 {sorted}
    
    
    >>> cProfile.run('f2(lIn)')
             4 function calls in 0.024 seconds
    
       Ordered by: standard name
    
       ncalls  tottime  percall  cumtime  percall filename:lineno(function)
            1    0.008    0.008    0.023    0.023 :1(f2)
            1    0.001    0.001    0.024    0.024 :1()
            1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
            1    0.016    0.016    0.016    0.016 {sorted}
    
    
    >>> cProfile.run('f3(lIn)')
             4 function calls in 0.055 seconds
    
       Ordered by: standard name
    
       ncalls  tottime  percall  cumtime  percall filename:lineno(function)
            1    0.016    0.016    0.054    0.054 :1(f3)
            1    0.001    0.001    0.055    0.055 :1()
            1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
            1    0.038    0.038    0.038    0.038 {sorted}
    View
  • 13.

    Describe Python's garbage collection mechanism in brief.

    Answer:

    A lot can be said here. There are a few main points that you should mention:

    • Python maintains a count of the number of references to each object in memory. If a reference count goes to zero then the associated object is no longer live and the memory allocated to that object can be freed up for something else
    • occasionally things called "reference cycles" happen. The garbage collector periodically looks for these and cleans them up. An example would be if you have two objects o1 and o2 such that o1.x == o2 and o2.x == o1. If o1 and o2 are not referenced by anything else then they shouldn't be live. But each of them has a reference count of 1.
    • Certain heuristics are used to speed up garbage collection. For example, recently created objects are more likely to be dead. As objects are created, the garbage collector assigns them to generations. Each object gets one generation, and younger generations are dealt with first.

    This explanation is CPython specific.

    View
  • 14.

    Consider the following code, what will it output?

    
    class Node(object):
        def __init__(self,sName):
            self._lChildren = []
            self.sName = sName
        def __repr__(self):
            return "<Node '{}'>".format(self.sName)
        def append(self,*args,**kwargs):
            self._lChildren.append(*args,**kwargs)
        def print_all_1(self):
            print(self)
            for oChild in self._lChildren:
                oChild.print_all_1()
        def print_all_2(self):
            def gen(o):
                lAll = [o,]
                while lAll:
                    oNext = lAll.pop(0)
                    lAll.extend(oNext._lChildren)
                    yield oNext
            for oNode in gen(self):
                print(oNode)
    
    oRoot = Node("root")
    oChild1 = Node("child1")
    oChild2 = Node("child2")
    oChild3 = Node("child3")
    oChild4 = Node("child4")
    oChild5 = Node("child5")
    oChild6 = Node("child6")
    oChild7 = Node("child7")
    oChild8 = Node("child8")
    oChild9 = Node("child9")
    oChild10 = Node("child10")
    
    oRoot.append(oChild1)
    oRoot.append(oChild2)
    oRoot.append(oChild3)
    oChild1.append(oChild4)
    oChild1.append(oChild5)
    oChild2.append(oChild6)
    oChild4.append(oChild7)
    oChild3.append(oChild8)
    oChild3.append(oChild9)
    oChild6.append(oChild10)
    
    # specify output from here onwards
    
    oRoot.print_all_1()
    oRoot.print_all_2()

    Answer:

    oRoot.print_all_1() prints:

    <Node 'root'>
    <Node 'child1'>
    <Node 'child4'>
    <Node 'child7'>
    <Node 'child5'>
    <Node 'child2'>
    <Node 'child6'>
    <Node 'child10'>
    <Node 'child3'>
    <Node 'child8'>
    <Node 'child9'>
    

    oRoot.print_all_2() prints:

    <Node 'root'>
    <Node 'child1'>
    <Node 'child2'>
    <Node 'child3'>
    <Node 'child4'>
    <Node 'child5'>
    <Node 'child6'>
    <Node 'child8'>
    <Node 'child9'>
    <Node 'child7'>
    <Node 'child10'>
    View
  • 15.

    Consider the following code, what will it output?

    class A(object):
        def go(self):
            print("go A go!")
        def stop(self):
            print("stop A stop!")
        def pause(self):
            raise Exception("Not Implemented")
    
    class B(A):
        def go(self):
            super(B, self).go()
            print("go B go!")
    
    class C(A):
        def go(self):
            super(C, self).go()
            print("go C go!")
        def stop(self):
            super(C, self).stop()
            print("stop C stop!")
    
    class D(B,C):
        def go(self):
            super(D, self).go()
            print("go D go!")
        def stop(self):
            super(D, self).stop()
            print("stop D stop!")
        def pause(self):
            print("wait D wait!")
    
    class E(B,C): pass
    
    a = A()
    b = B()
    c = C()
    d = D()
    e = E()
    
    # specify output from here onwards
    
    a.go()
    b.go()
    c.go()
    d.go()
    e.go()
    
    a.stop()
    b.stop()
    c.stop()
    d.stop()
    e.stop()
    
    a.pause()
    b.pause()
    c.pause()
    d.pause()
    e.pause()

    Answer:

     

    The output is specified in the comments in the segment below:

    a.go()
    # go A go!
    
    b.go()
    # go A go!
    # go B go!
    
    c.go()
    # go A go!
    # go C go!
     
    d.go()
    # go A go!
    # go C go!
    # go B go!
    # go D go!
    
    e.go()
    # go A go!
    # go C go!
    # go B go!
    
    a.stop()
    # stop A stop!
    
    b.stop()
    # stop A stop!
    
    c.stop()
    # stop A stop!
    # stop C stop!
    
    d.stop()
    # stop A stop!
    # stop C stop!
    # stop D stop!
    
    e.stop()
    # stop A stop!
     
    a.pause()
    # ... Exception: Not Implemented
    
    b.pause()
    # ... Exception: Not Implemented
    
    c.pause()
    # ... Exception: Not Implemented
    
    d.pause()
    # wait D wait!
    
    e.pause()
    # ...Exception: Not Implemented
    View
  • 16.

    What do these mean to you: @classmethod@staticmethod@property?

    Answer Background Knowledge:

    These are decorators. A decorator is a special kind of function that either takes a function and returns a function, or takes a class and returns a class. The @ symbol is just syntactic sugar that allows you to decorate something in a way that's easy to read.

    @my_decorator
    def my_func(stuff):
        do_things
    
    

    Is equivalent to

    def my_func(stuff):
        do_things
    
    my_func = my_decorator(my_func)
    

    You can find a tutorial on how decorators in general work here.

    Actual Answer:

     

    The decorators @classmethod@staticmethod and @property are used on functions defined within classes. Here is how they behave:

    class MyClass(object):
        def __init__(self):
            self._some_property = "properties are nice"
            self._some_other_property = "VERY nice"
        def normal_method(*args,**kwargs):
            print("calling normal_method({0},{1})".format(args,kwargs))
        @classmethod
        def class_method(*args,**kwargs):
            print("calling class_method({0},{1})".format(args,kwargs))
        @staticmethod
        def static_method(*args,**kwargs):
            print("calling static_method({0},{1})".format(args,kwargs))
        @property
        def some_property(self,*args,**kwargs):
            print("calling some_property getter({0},{1},{2})".format(self,args,kwargs))
            return self._some_property
        @some_property.setter
        def some_property(self,*args,**kwargs):
            print("calling some_property setter({0},{1},{2})".format(self,args,kwargs))
            self._some_property = args[0]
        @property
        def some_other_property(self,*args,**kwargs):
            print("calling some_other_property getter({0},{1},{2})".format(self,args,kwargs))
            return self._some_other_property
    
    o = MyClass()
    # undecorated methods work like normal, they get the current instance (self) as the first argument
    
    o.normal_method 
    # >
    
    o.normal_method() 
    # normal_method((<__main__.MyClass instance at 0x7fdd2537ea28>,),{})
    
    o.normal_method(1,2,x=3,y=4) 
    # normal_method((<__main__.MyClass instance at 0x7fdd2537ea28>, 1, 2),{'y': 4, 'x': 3})
    
    # class methods always get the class as the first argument
    
    o.class_method
    # >
    
    o.class_method()
    # class_method((,),{})
    
    o.class_method(1,2,x=3,y=4)
    # class_method((, 1, 2),{'y': 4, 'x': 3})
    
    # static methods have no arguments except the ones you pass in when you call them
    
    o.static_method
    # 
    
    o.static_method()
    # static_method((),{})
    
    o.static_method(1,2,x=3,y=4)
    # static_method((1, 2),{'y': 4, 'x': 3})
    
    # properties are a way of implementing getters and setters. It's an error to explicitly call them
    # "read only" attributes can be specified by creating a getter without a setter (as in some_other_property)
    
    o.some_property
    # calling some_property getter(<__main__.MyClass instance at 0x7fb2b70877e8>,(),{})
    # 'properties are nice'
    
    o.some_property()
    # calling some_property getter(<__main__.MyClass instance at 0x7fb2b70877e8>,(),{})
    # Traceback (most recent call last):
    #   File "", line 1, in 
    # TypeError: 'str' object is not callable
    
    o.some_other_property
    # calling some_other_property getter(<__main__.MyClass instance at 0x7fb2b70877e8>,(),{})
    # 'VERY nice'
    
    # o.some_other_property()
    # calling some_other_property getter(<__main__.MyClass instance at 0x7fb2b70877e8>,(),{})
    # Traceback (most recent call last):
    #   File "", line 1, in 
    # TypeError: 'str' object is not callable
    
    o.some_property = "groovy"
    # calling some_property setter(<__main__.MyClass object at 0x7fb2b7077890>,('groovy',),{})
    
    o.some_property
    # calling some_property getter(<__main__.MyClass object at 0x7fb2b7077890>,(),{})
    # 'groovy'
    
    o.some_other_property = "very groovy"
    # Traceback (most recent call last):
    #   File "", line 1, in 
    # AttributeError: can't set attribute
    
    o.some_other_property
    # calling some_other_property getter(<__main__.MyClass object at 0x7fb2b7077890>,(),{})
    # 'VERY nice'
    View
  • 17.

    What does this stuff mean: *args**kwargs? And why would we use it?

    Answer:

    Use *args when we aren't sure how many arguments are going to be passed to a function, or if we want to pass a stored list or tuple of arguments to a function. **kwargs is used when we dont know how many keyword arguments will be passed to a function, or it can be used to pass the values of a dictionary as keyword arguments. The identifiers args and kwargs are a convention, you could also use *bob and **billy but that would not be wise.

    Here is a little illustration:

    
    def f(*args,**kwargs): print(args, kwargs)
    
    l = [1,2,3]
    t = (4,5,6)
    d = {'a':7,'b':8,'c':9}
    
    f()
    f(1,2,3)                    # (1, 2, 3) {}
    f(1,2,3,"groovy")           # (1, 2, 3, 'groovy') {}
    f(a=1,b=2,c=3)              # () {'a': 1, 'c': 3, 'b': 2}
    f(a=1,b=2,c=3,zzz="hi")     # () {'a': 1, 'c': 3, 'b': 2, 'zzz': 'hi'}
    f(1,2,3,a=1,b=2,c=3)        # (1, 2, 3) {'a': 1, 'c': 3, 'b': 2}
    
    f(*l,**d)                   # (1, 2, 3) {'a': 7, 'c': 9, 'b': 8}
    f(*t,**d)                   # (4, 5, 6) {'a': 7, 'c': 9, 'b': 8}
    f(1,2,*t)                   # (1, 2, 4, 5, 6) {}
    f(q="winning",**d)          # () {'a': 7, 'q': 'winning', 'c': 9, 'b': 8}
    f(1,2,*t,q="winning",**d)   # (1, 2, 4, 5, 6) {'a': 7, 'q': 'winning', 'c': 9, 'b': 8}
    
    def f2(arg1,arg2,*args,**kwargs): print(arg1,arg2, args, kwargs)
    
    f2(1,2,3)                       # 1 2 (3,) {}
    f2(1,2,3,"groovy")              # 1 2 (3, 'groovy') {}
    f2(arg1=1,arg2=2,c=3)           # 1 2 () {'c': 3}
    f2(arg1=1,arg2=2,c=3,zzz="hi")  # 1 2 () {'c': 3, 'zzz': 'hi'}
    f2(1,2,3,a=1,b=2,c=3)           # 1 2 (3,) {'a': 1, 'c': 3, 'b': 2}
    
    f2(*l,**d)                   # 1 2 (3,) {'a': 7, 'c': 9, 'b': 8}
    f2(*t,**d)                   # 4 5 (6,) {'a': 7, 'c': 9, 'b': 8}
    f2(1,2,*t)                   # 1 2 (4, 5, 6) {}
    f2(1,1,q="winning",**d)      # 1 1 () {'a': 7, 'q': 'winning', 'c': 9, 'b': 8}
    f2(1,2,*t,q="winning",**d)   # 1 2 (4, 5, 6) {'a': 7, 'q': 'winning', 'c': 9, 'b': 8} 
    View
  • 18.

    What is monkey patching and is it ever a good idea?

    Answer:

    Monkey patching is changing the behaviour of a function or object after it has already been defined. For example:

    import datetime
    datetime.datetime.now = lambda: datetime.datetime(2012, 12, 12)
    

    Most of the time it's a pretty terrible idea - it is usually best if things act in a well-defined way. One reason to monkey patch would be in testing. The mock package is very useful to this end.

    View
  • 19.

    What does this code output:

    def f(x,l=[]):
        for i in range(x):
            l.append(i*i)
        print(l) 
    
    f(2)
    f(3,[3,2,1])
    f(3)

    Answer:

    [0, 1]
    [3, 2, 1, 0, 1, 4]
    [0, 1, 0, 1, 4]

    View
  • 20.

    How do you keep track of different versions of your code?

    Answer:

    Version control! At this point, you should act excited and tell them how you even use Git (or whatever is your favorite) to keep track of correspondence with Granny. Git is my preferred version control system, but there are others, for example subversion.

    View

© 2017 QuizBucket.org