In the below example of a Town class, the behavior of moving to/from a town is split up among the Town class and Inhabitant class. The code works. But I am wondering if there are compelling reasons to assign this behavior to only one class, e.g. allow the Town method
addpeople to update the Inhabitant attribute town so it's possible to track each inhabitant's place of residence.
There is actually a good reason to not assign this behavior to only one class and keep it similar to what you have - in object-oriented programming you really want to have each object maintain control over its own data. Your code can easily become very complicated and hard to debug if you change variables outside of the object that the variable belongs to. This is part of the concept of encapsulation that is central to object-oriented programming.
Another part of OOP that is relevant here is abstraction, i.e you want the interaction between objects in your code to make sense at a higher level. Just from looking at this sample code, I would guess that the inhabitants of the towns are more the focus of your program than the towns themselves. If the user is interacting more with the town, I would expect the town to be doing more of the work (
Inhabitant.move, for example).
So as you are writing your program, think about which entities will be the ones doing the work. When your code matches your intuitive abstraction of what is happening, it will be much easier for you to keep track of what is going on and not introduce bugs into your code.
One other piece of advice I would give you may or may not be helpful, depending on what this project is for. If this is a program you are going to be actually using, maintaining, and upgrading, write a throwaway prototype first. As Joel Cornett mentioned in the comment, "It depends on the use case", meaning that in order to know the best way to write the code you have to understand the situation. Some of this comes from experience, but unless you are perpetually writing pretty much the same program time and again, you will run into a situation that is not entirely familiar. Writing a prototype is an excellent way to get some experience with the specific problem that you are facing, because you often will not be able to see why one way or another will work better until you are fairly far into writing the program.
One thing that prevents people from creating a good system is that they get attached to their code. So if you choose to write a prototype, realize that it is a throwaway - something you write rapidly just for the purpose of getting a good feel for the problem. It can also help if you realize while you're writing it that it doesn't even have to work, as long as it helps you figure out what it would take for it to work well. Once you've written your prototype, you will have a much better feel for how you should have written your code. Then you can start over and write it correctly much faster.
In short, "It depends on the use case", so make sure you understand the use case and have the code match your understanding.