basic example 

class Point:
   x = 0
   y = 0

p = Point()
p.x = 1
p.y = 7

print(vars(p))

The vars() function returns the __dict__ attribute of an object such as a class, a module e.t.c.  The __dict__ attribute stores the namespace dictionary associated with an object. 

When you access an attribute using dot notation (e.g., object.attribute), Python internally looks up the attribute in the object's __dict__ dictionary. If the attribute is found in the dictionary, its value is returned. Otherwise, the search in the object's class and then in the parent classes.

Namespaces such as modules, classes, instances, and functions have their own __dict__ attribute, which serves as their namespace dictionary. This dictionary is where the names and their associated objects are stored.

class Example():
    def __init__(self):
       self.x = 100
       self.y = 200

e = Example()
print(e.__dict__)

If the vars() function is called with an object, it returns the __dict__ dictionary . If it is called without any argument, the current local scope is used as the default.

Syntax:

vars(object[optional])

If the optional argument, namespace,  is not given, the function returns all the  variables in the current local scope.

def func():
    a = 50
    b = 100
    print(vars())

func()
class Example():
    def __init__(self):
       self.name = 'Instance'
       self.x = 500
       self.y = 1000
    def func(self):
        pass

e = Example()

print(vars(e))

The function  is usually used in debugging scenarios to inspect the values of variables at different points in the code. Additionally, you can modify the variables indirectly through the returned dictionary because the values in the dictionary are references to the original variables.

x = 100
y = 200
vars()['x'] = 1000
vars()['y'] = 2000
print(x)
print(y)

However, it's important to exercise caution when modifying variables indirectly as it can lead to unexpected behavior and make the code more difficult to understand and maintain.