7: Class, Methods and Constructors¶
Summary¶
Unlike in other languages, in Python a class is an object
A class is a callable, which means it can be called like a function
When called as a function a class returns an instance
- At its simplest, an instance has no attributes
Any attributes you try to access on the instance are resolved by attributes on the class object
If you assign to an attribute then it is created as an instance attribute
Function attributes defined on the class object are converted into method objects when accessed via an instance
- Methods call the function object using self, the instance, as the first parameter
What this means is that you write function attributes with an explicit self parameter, but when you call a methods you do not specify self
- Methods are bound to their instance when first accessed
This is a form of early binding
In addition to instance methods, you can also create static and class methods
The initializer __init__ can be used to add attributes to an instance and to initialize them
You can create multiple constructors using class methods
- In Python it makes sense to place all methods in the class body and all data attributes in the __init__
This allows methods to be shared by all instances and data to be unique to each instance
Program¶
# Demonstration of Classes, Methods, Constructors, Static and Class Methods
class Student:
# Class attribute (shared by all instances)
school_name = "Spencerport High School"
# Initializer (constructor)
def __init__(self, name, age, gpa):
# Instance attributes (unique to each instance)
self.name = name
self.age = age
self.gpa = gpa
# Instance method (uses self)
def introduce(self):
return f"Hi, I'm {self.name}, I'm {self.age} years old and my GPA is {self.gpa}."
# Instance method that modifies instance attribute
def update_gpa(self, new_gpa):
self.gpa = new_gpa
# Class method (alternative constructor)
@classmethod
def from_string(cls, data_string):
name, age, gpa = data_string.split(",")
return cls(name.strip(), int(age.strip()), float(gpa.strip()))
# Static method (does not use instance or class directly)
@staticmethod
def is_honor_roll(gpa):
return gpa >= 3.5
# -----------------------------
# Demonstration Code
# -----------------------------
# 1. A class is an object
print("Student is an object:", type(Student))
# 2. A class is callable (like a function)
print("Is Student callable?", callable(Student))
# 3. Calling a class returns an instance
student1 = Student("Brayden", 18, 3.8)
print("Type of student1:", type(student1))
# 4. Instance attributes are unique
student2 = Student("Alex", 17, 3.2)
# 5. Access class attribute (shared)
print("School name (student1):", student1.school_name)
print("School name (student2):", student2.school_name)
# 6. Instance method (self automatically passed)
print(student1.introduce())
# 7. Methods are bound to their instance (early binding)
method_reference = student1.introduce
print("Bound method:", method_reference)
print("Calling bound method:", method_reference())
# 8. Modify instance attribute
student2.update_gpa(3.6)
print(student2.introduce())
# 9. Static method (no self)
print("Is student1 honor roll?", Student.is_honor_roll(student1.gpa))
# 10. Class method (alternative constructor)
student3 = Student.from_string("Jordan, 19, 3.9")
print(student3.introduce())
# 11. Demonstrate class vs instance attribute resolution
print("Accessing class attribute via instance:", student1.school_name)
# Create instance attribute with same name
student1.school_name = "Different School"
print("After overriding:")
print("student1 school:", student1.school_name)
print("student2 school (still class attribute):", student2.school_name)
print("Class school name:", Student.school_name)
Program Output¶
(docs-env) root@BMitchellLTOP:~/git/sphinx_students/source/programming_lang/book/programs# python3 chapterSeven.py
Student is an object: <class 'type'>
Is Student callable? True
Type of student1: <class '__main__.Student'>
School name (student1): Spencerport High School
School name (student2): Spencerport High School
Hi, I'm Brayden, I'm 18 years old and my GPA is 3.8.
Bound method: <bound method Student.introduce of <__main__.Student object at 0x79e6ca02b5d0>>
Calling bound method: Hi, I'm Brayden, I'm 18 years old and my GPA is 3.8.
Hi, I'm Alex, I'm 17 years old and my GPA is 3.6.
Is student1 honor roll? True
Hi, I'm Jordan, I'm 19 years old and my GPA is 3.9.
Accessing class attribute via instance: Spencerport High School
After overriding:
student1 school: Different School
student2 school (still class attribute): Spencerport High School
Class school name: Spencerport High School