I've followed a tutorial where a Person class was used to illustrate the difference between class and instance variables. Something like:

class Person(object):
	def __init__(self, name):
		Person.population += 1
                print 'current population', Person.population


This example really illustrated the difference between class and instance variables to me; however, it also really confuses me. When I think about it, the Person class is holding the attributes for an individual. The concept of a population; however, is a group of people. Therefore, it seems natural in OOP that a container class, "People" would store the variable population. When you really think about it, "People" is a composition of "Person" objects. And furthermore, the population itself is not really an independent variable. Instead, it is a property of the real variable, which is a list of "Person" objects. Let me show you what I mean:

class Person(object):
	def __init__(self, name):
                print 'Instantiating person', name

class People(object):
        def __init__(self, persons):

        def add_member(self, person):
                print 'adding a crew member', person.name

        def getpop(self):
		print 'my population is now', len(self.persons) 
		return len(self.persons)        

crew=People([sally, joe])
print crew.population, 'is the new population'
print crew.population, 'is the new population'

I would argue that my People class is a more canonical way of representing a population of people because it holds a list of people and the population is merely a property of this list (i.e. the length of the list).

Let me ask 2 questions. First and simply, how do I implement an interface for Person in my People class so that People knows to expect a list of Person objects and not just any old python list. Aka, I can't pass the following:

crew=People([32, 'not a Person object, just a string here'])

Second, do you think that what I'm saying makes sense, or is there a better/preferred/standard way to do this without relying on properties and/or class composition? Are there recommended ways to build such container classes?

I think there are a lot of misconceptions about classes in your approach.

First, a more accurate name for class Person would be MinimalDataThatThisProgramNeedsToStoreAboutAPerson. It means that the purpose of a class Person is not to mimic a person from the real world but to provide some space in memory to handle some data relative this person. For example this program stores the person's name but not the person's parents names or date of birth because it does not need it. The argument that 'it is more natural' to do such or such way should not be pushed too far. The important question is 'what does this program need'.

Second, classes are a way of factorizing data, because all the instances can access the class members. It means that data common to all people are good candidates to be stored in the class object.

Third, storing instances in a container is common, but it is very different from storing the number of instances. The reason is that stored instances don't disappear unless there are removed from the container or the container is destroyed. Instances often have a short life. For example an instance may be created as a local variable in a function and it disappears when the function returns. Such temporary instances should not be stored. If your program only needs the number of instances created, don't store instances because you think that 'it is more natural'.

For your first question you can check the types of the arguments in the constructor with

assert all(isinstance(x, Person) for x in persons)

For the second question, I would say no. There are many container types in python. I would recommend using a standard container like a set, list or dict.

commented: very helpful +5

Thanks Gribouillis that was a very helpful answer.