You are right: _ip is an instance of SysUtil, however there is nothing special about that first self parameter.
The behaviour of _ip does not depend on it being defined as an attribute of a ClientSetup instance, so lets consider this example:
>>> class A:
... def f(self):
... return
...
>>> a = A()
>>> type(A.f)
function
>>> type(a.f)
method
A.f is still a function until A is instantiated! We call this bounding. Definition: a bound method in Python is a function that has an object associated with it. (The concept of unbound method has been deprecated in Python 3.0).
That's it. In the above example, there is no conceptual difference between A.f and a generic function in a "non-class scope"
def g(self):
return
i.e. they can be called in the same way. g and A.f are just a function that accept an instance of A as first positional argument.
When you instantiate A into a, a.f is a method. In a method (bound to an instance) the first parameter self (may be named in another way) is implicitly passed as the instance itself. I.e. when calling a.f() self gets the value of a.
A simple function such A.f (or g) does not behave in such way, the first parameter is not implicit, since the function is not bound to any instance. However you can pass the instance explicitly, as you would do with a parameter in any normal function, i.e. A.f(a).
So... A.f(a) is the same as a.f().
In your case A is SysUtil. The line SysUtil.validateIP(self._ip, '127.0.0.1') could be replaced with self._ip.validateIP('127.0.0.1').
The above line-replacement is also recommended in terms of design style, as @RomanPerekhrest pointed out.
I suggest you to take a look at this docs.python.org article to a deeper insight at how Python classes work.
When would this be useful
This design choice would be useful when wanting to specify you want that very implementation to be executed. We may need this when the class is subclassed. In our example:
>>> class B(A):
... def f(self): # May depend on `A.f`.
... print('From `B.f`')
...
>>> b = B()
>>> b.f() # Would now print.
From `B.f`
Let's say we don't want to print anything, but still use an instance of B. We could do
>>> A.f(b) # Won't print.
SysUtil.validateIP(self._ip, '127.0.0.1')is incorrect approach in terms of good Python OOP practice and design