You don't necessarily need setter methods for your python classes. In python everything is public. This is just a concept copied from other languages that do object oriented programming.
So you could get away with setting the name, address or phone directly. It's just that it would be considered "unsafe" to do so.
To give you an example: If I had a class named "DateTime" and I wanted to set the time for an object of this type as "Tue 02-Dec-2020 13:45 UTC +0020", then I would really like to use a method "setTime" to do so. The alternative would be to take a look at the whole class, understand how it works, figure out myself how to break down the time string and individually set every single member variable of my object to the correct value. This is tedious, unsafe, looks bad and error prone. Which is why we opt to use classes and setter/getter methods to hide implementation details like the one I just mentioned. The bad thing is schools tend to require students to adopt this mentality without having first seen the worse alternative. Sort of like "Follow the beaten path! Not because it's better, but because I said so!"
The second thing you asked is what is the difference between __init__ and the setter/getter methods.
Here, you should remember that there are usually 2 types of methods in object oriented programming languages (this is because humans prefer syntactic sugar).
The first kind are the ones you have to explicitely call. In your case "getPhone", "setAddress" etc. In order to execute the code of these functions, you will have to write out the whole name: myobject.doSomething()
The second kind are sort of "trigger functions". You can't call them by name, because they have no name. Instead you have to do specific operations in order to trigger their execution. In your case, __init__ will be called at object initialization time, i.e. when you do
Some of these functions are allowed to take parameters, but, for example, __str__ is not. __str__ can be triggered by attempting to convert the object to a string, i.e. doing something like: . As you can see, there is no way to pass any arguments to the implicitly called __str__ method.
These keywords are baked into the python interpreter and there is a set number of them. Coming up with new names like __dosomething__ would not make any sense for the interpreter and it will just register your method as a regular one.