DEV Community

Tomer Raitz
Tomer Raitz

Posted on • Edited on

Tricky Python Questions

In the last two years, I've used Python extensively as my main programming language. Dive into these tricky Python questions, inspired by real-world issues and online challenges, to test and enhance your coding skills.

So are you ready to get your mind blow away (from Python question)?

Alt Text

Questions

Notice 1!: To each question, there is an answer with an explanation (link below each item).
Notice 2!: For each question think what will be the output.

Question 1
exapmle_dict = dict()
exapmle_dict.a = "string"
print(exapmle_dict)
Enter fullscreen mode Exit fullscreen mode

Go to answer 1

Question 2
class Json:
    def __init__(self, *args, **kwargs):
        import json

    def print_dict_as_json(self, obj):
        print(json.dumps(obj))

example_json = Json()
example_json.print_dict_as_json({"a": "string"})
Enter fullscreen mode Exit fullscreen mode

Go to answer 2

Question 3
def myFun(arg1, arg3, **kwargs):
    for key, value in kwargs.items():
        print("%s == %s" % (key, value))


my_dict = {'arg1':1, 'arg2': 2}
myFun(**my_dict, arg3=3)
Enter fullscreen mode Exit fullscreen mode

Go to answer 3

Question 4
def add_to_all_1(arr):
    for i in range(len(arr)):
        arr[i] +=1

def my_func():
    arr = [1,2,3]
    add_to_all_1(arr)
    arr2 = arr
    print(arr2)

my_func()
Enter fullscreen mode Exit fullscreen mode

Go to answer 4

Question 5
import gc


class MyClass:
    def __init__(self, name):
        self.name = name
        print(f"{self.name} object created")

    def __del__(self):
        print(f"\ncall by instance {self.name}")
        print("Objects in memory after deletion:")
        is_not_deleted = []
        for obj in gc.get_objects():
            if isinstance(obj, MyClass):
                is_not_deleted.append(obj.name)

        [print(f"  - {name}") for name in is_not_deleted] if len(is_not_deleted) else print("nothing")


gc.enable()

obj1 = MyClass("Object1")
obj2 = MyClass("Object2")


def create_obj_3():
    MyClass("Object3")


create_obj_3()

print("\nObjects in memory before deletion:")
for obj in gc.get_objects():
    if isinstance(obj, MyClass):
        print(f"  - {obj.name}")


Enter fullscreen mode Exit fullscreen mode

Go to answer 5

Question 6
def convert_tuple_to_list(_tuple, result_list=[]):
    for t in _tuple:
        result_list.append(t)
    return result_list

tuple_1 = (1,2,3)
tuple_2 = ('Banna', 'Orange', 'Apple')

print(convert_tuple_to_list(tuple_1))
print(convert_tuple_to_list(tuple_2))
Enter fullscreen mode Exit fullscreen mode

Go to answer 6

Answers

Answer To Question 1

If you said:

{"a": "string"}
Enter fullscreen mode Exit fullscreen mode

unfortunately, you are wrong, the answer is:

AttributeError: 'dict' object has no attribute 'a'
Enter fullscreen mode Exit fullscreen mode

If you like me and came from javascript first, the access dictionary (object in Javascript) is not by dot like in Javascript, you can access only by [], and inside the key you want to set "a".

Back to question 1

Answer To Question 2

If you said:

{"a": "string"}
Enter fullscreen mode Exit fullscreen mode

You are wrong again, the answer is:

...
NameError: name 'json' is not define
Enter fullscreen mode Exit fullscreen mode

You may know the differences between local and global scope in Python (if not you should read this: Python Scope). The __init__ is a function, the import is inside a local scope so it doesn't know what is json. You can fix it by import it globally like this:

import json

class Json:
    def print_dict_as_json(self, obj):
        print(json.dumps(obj))

example_json = Json()
example_json.print_dict_as_json({"a": "string"})
Enter fullscreen mode Exit fullscreen mode

Or in a more advanced way:

class Json:
    import json as json
    def print_dict_as_json(self, obj):
        print(self.json.dumps(obj))

example_json = Json()
example_json.print_dict_as_json({"a": "string"})
Enter fullscreen mode Exit fullscreen mode

You can see using import inside class for more details.

Back to question 2

Answer To Question 3

If you said:

arg2 == 2
Enter fullscreen mode Exit fullscreen mode

You are right! In Python, we have 3 ways to pass an argument:

  • By the argument itself:
def myFun(arg1):
   print(arg1)

myFun('arg1')
Enter fullscreen mode Exit fullscreen mode
  • By *args - list or tuples of arguments ( allows us to pass a variable number of non-keyword arguments to a Python function):
def myFun(*arg1):
   print(*arg1)

my_tuple = ('arg1', 'arg2')
myFun(my_tuple)
Enter fullscreen mode Exit fullscreen mode

Back to question 3

Answer To Question 4

The answer is:

[2, 3, 4]
Enter fullscreen mode Exit fullscreen mode

For some people who know scopes and assignments, it can seem a pretty easy question. For those who don't know, python saves variable memory as a reference, so in this case, the arr will point to a reference in a memory -> the function will change the values (but still the same reference) -> arr2 will get the reference address of arr but after values were modified.

Back to question 4

Answer To Question 5

The answer is:

Object1 object created
Object2 object created
Object3 object created

call by instance Object3
Objects in memory after deletion:
  - Object1
  - Object2
  - Object3

Objects in memory before deletion:
  - Object1
  - Object2

call by instance Object1
Objects in memory after deletion:
nothing

call by instance Object2
Objects in memory after deletion:
nothing
Enter fullscreen mode Exit fullscreen mode

It was tricky for me to understand it as well, but let's try to break it down:

  • Why did Object3 call del at the beginning? The reason is simple: when Object3 was created inside the function create_obj_3(), it went out of scope as soon as the function execution finished. Python’s garbage collector identified that there were no more references to Object3, and since it was no longer in use, it triggered the del method. This is why you see Object3 being deleted immediately.
  • Why do we see Object3 in "Objects in memory after deletion"? This happens because the garbage collector doesn’t delete objects immediately when they go out of scope. Objects are marked for deletion, but the actual deletion process depends on when the garbage collector runs. The gc.collect() manually triggers the garbage collection process, but it doesn't guarantee that all objects will be deleted immediately. In your case, Object3 was eligible for garbage collection, but the actual deletion may have happened later, allowing it to still be seen in the list of "objects in memory after deletion."

Points to Clarify:

  1. Scope of Object3: The key thing is that Object3 was created in a local scope and went out of scope when the function completed. Python then decided it could be garbage-collected.
  2. GC Delays: Garbage collection doesn’t always happen immediately after an object becomes unreferenced. The collection happens when the garbage collector is ready, which could be after your call to gc.collect(), depending on when Python decides to run the cleanup process

Back to question 5

Answer To Question 6

Maybe some of you said:

[1, 2, 3]
['Banna', 'Orange', 'Apple']
Enter fullscreen mode Exit fullscreen mode

But the answer is:

[1, 2, 3]
[1, 2, 3, 'Banna', 'Orange', 'Apple']
Enter fullscreen mode Exit fullscreen mode

Why does this happen?
Python treats mutable default arguments (such as lists or dictionaries) as shared objects between function calls. Instead of creating a new list each time the function is called, Python reuses the same list.
To fix it you can just change the default value to None like this:

def convert_tuple_to_list(_tuple, result_list=None):
    if result_list is None:
        result_list = []
    for t in _tuple:
        result_list.append(t)
    return result_list
Enter fullscreen mode Exit fullscreen mode

Back to question 6

Thank you for reading this article. I hope you enjoyed and learned new things. If you have any questions or suggestions, please leave a comment.

Top comments (0)