In Python, an object is a container that holds pieces of data called "attributes". Each attribute has a name.
For example, if you have an object saved in the person
variable, writing person.name
retrieves the value held in the name
attribute.
A class is the "type" of a particular object. An object is an "instance" of a class.
# Create the simplest possible class
class Person:
pass
# Create an instance of the class
person = Person()
# Assign some data to an attribute of `person`
person.name = 'eden'
# Retrieve the data we just assigned
print(person.name)
That's most of what you need to know. An object is a container, a class is the type of an object.
There are a few important details, however.
The attributes of an object are not shared across other instances of the same class:
person1 = Person()
person1.name = 'eden'
person2 = Person()
person2.name # AttributeError
so person1
data is not shared with person2
or any other instance of Person
.
However, you can assign attributes to the class directly. These attribtes are shared across all instances, even if those instances already exist.
person1 = Person()
Person.species = 'human'
person2 = Person()
print(person1.species)
print(person2.species)
Usually we use instance attributes and not class attributes. Once in a while class attributes are useful, but if you have to ask, they probably aren't what you want. However, there is one specific case where class attributes are very important, which we will get to in a moment.
But first, we need to know some syntax. You can run normal code inside a class definition, and everything assigned there will be assigned to the class. As I said above, we usually don't want to do this, but just for the sake of illustration:
class Person:
species = 'human'
some_data_for_demonstration = []
for i in range(15):
if i % 5 == 0:
some_data_for_demonstration.append(i)
del i
person1 = Person()
print(person1.species)
print(person1.some_data_for_demonstration)
The important usage for this syntax is that you can define a function inside a class. Python has special handling for this case, and it forms the basis of OO programming in Python:
class Person:
def compute_age(self, current_year):
return current_year - self.birth_year
person = Person()
person.birth_year = 1999
print(person.compute_age(2019))
Note the difference between the function signature:
def compute_age(self, current_year)
and the function call:
person.compute_age(current_year)
In the signature, you have the first parameter that we called self
, and another parameter called current_year
. But you didn't need to pass an argument for self
when you called the function.
That's because when an attributes is a function, it's treated specially. Such a function is called a "method". When a class is instantiated, each method is "bound" to the instance. The practical result of this "binding" is that the instance is passed as the first argument of the method. So
person = Person()
person.compute_age(current_year)
is more or less equivalent to
person = Person()
Person.compute_age(person, current_year)
When a class has a method named __init__
, Python runs that method when the class is instantiated. So if we define an __init__
method for Person
:
class Person:
def __init__(self, name, birth_year):
self.name = name
self.birth_year = birth_year
Creating a Person
object is much easier:
person = Person('eden', 1999)
compared to what we had to write in the beginning:
person = Person()
person.name = 'eden'
person.birth_year = 1999