There are two questions hidden in this one.
While I have never met someone who does not religiously make all their class attributes private and define getters and setters, I have met some who are not sure why they do it. So, first, why do you always need getters and setters in Java? Some have rightfully told me that you actually don’t need getters and setters in Java, you can make all attributes public, which is of course technically correct but always leads to the question: so, why don’t you?
It is a good practice; because of encapsulation; to avoid other classes from
directly manipulating the internal state of our class. These are all correct
but a bit unsatisfying answers because what one would really want to know is
why. Why is it a good practice? Why would you want to avoid other classes from
manipulating your internal state and how are you doing so when defining a setter
that all it does is assign the value received as an argument to the
corresponding attribute? Other classes can still manipulate your internal state
all they want, they just need to call
instance.setAttribute(value) instead of
instance.attribute = value.
The real reason, at least to me, why you always need to define getters and setters in Java is because you might need to add some logic or additional behaviour in the future, even if, right now, all your getter does is return the value of its corresponding attribute. If you start by directly accessing the attribute you will end up with those direct accesses spread across a lot of methods in different classes and even packages. If you eventually need to add any logic to it, you will have to make that change in a lot of different places.
As an example, consider a
class Animal with a boolean attribute
When you start writing your program there is no additional logic so you skip
the getter, make the attribute
public and just access it directly everywhere
you need it. Everything works fine. Later, the government drafts a new law
stating that an animal should only be considered vaccinated if it has received
the vaccine in the last three years. If you had a getter and were using it
accross all your code, the change would be simple: just add the additional logic
to the getter. But, as you don’t, you will now have to create the getter
isVaccinated() and change every line of your code where you were directly
accessing the attribute to, now, call the getter instead.
Makes sense? So, why don’t we always need to define them in Python? In
Python, as in other languages that have Properties, like C# and Kotlin, you
can start without any getters or setters because if you later need to add some
logic you can simply write a getter or setter for that attribute without having
to change anything on the call site, i.e., when a getter is defined for some
instance.attribute will no longer be simply the value of
attribute but rather the value returned by the getter you have now defined.