class m2:
    x, y = 4, 5 #This are class attributes
    def add(self, x, y ):
            return self.x + self.y # This are instance variables
    def add2(self, x, y ):
            return x + y # This are local variables
Class variables are common to each instance of the class. Instance variables are only avaible to that instance. And local variables are only avaible in the scope of the function.
In add, when you do self.x it's refering to the class variable x cause it's also part of the instance. In add2 it's refering to local variables
The same results could be achieved if those methods were class methods or static methods (With proper adjustments)
Class method:
class m2:
    x, y = 4, 5
    @classmethod
    def add(cls, x, y):
        return cls.c + cls.y #Here you're calling class attributes
    @classmethod
    def add2(cls, x, y):
        return x + y
Results:
>>> m.add(1,2)
9
>>> m.add2(1,2)
3
Static method:
class m2:
    x, y = 4, 5
    @staticmethod
    def add(x, y):
        return m2.c + m2.y #Here you need to call the class attributes through the class name
    @staticmethod
    def add2(x, y):
        return x + y
Results:
 >>> m2.add(1,2)
 9
 >>> m2.add2(1,2)
 3