Object-Oriented Programming in Python

Overview of Object-Oriented Technology

  • Class: A blueprint for creating objects that share common attributes and methods. It defines properties and behaviors that all instances of that class will have.
  • Method: A function defined within a class.
  • Class Variable: A variable shared by all instances of a class. It is defined inside the class but outside any method. Class variables are often not used as instance variables.
  • Data Member: A class variable or instance variable that holds data related to the class and its objects.
  • Method Overriding: If an inherited method from a parent class doesn't meet the needs of the child class, it can be redefined. This process is called overriding.
  • Instance Variable: A variable defined inside a method, belonging only to the current instance of the class.
  • Inheritance: A mechanism where a derived class (child class) inherits fields and methods from a base class (parent class). It allows an object of a derived class to be treated as an object of the base class, modeling an "is-a" relationship.
  • Instantiation: The process of creating an instance (a concrete object) of a class.
  • Object: An instance of a class, defined by its data structure. Objects include both data members (class and instance variables) and methods.

Classes

A class represents a category of things that share common attributes and behaviors. For example, the general characteristics shared by all humans.

Syntax

class ClassName:
    """
    Docstring describing the class.
    """
    variable_name = variable_value  # Static variable or field, common to all instances
    
    def __init__(self):
        pass
    
    def method_name(self):
        pass

Accessing Class Members

  1. To view all variables (fields) and methods (functions) of a class:

    ClassName.__dict__
    
  2. Manipulating static variables (static fields) using the class name: It is best not to use __dict__ for this purpose.

    • Not recommended: Using ClassName.__dict__ to read all members or manipulate individual ones (add, delete, modify).
    • Recommended: Use ClassName.variable_name for accessing and modifying static variables.
    # Accessing static variables via class name
    print(Person.level)
    Person.create = 'creative'
    del Person.mind
    Person.level = 'modified'
    
  3. Manipulating methods (dynamic methods) of a clas:

    • Not recommended: Via ClassName.__dict__.
    • Recommended: Via ClassName.method_name.

Example

class Person:
    '''
    This class defines a human.
    '''
    level = 'Advanced Animal'
    mind = 'Has Thoughts'
    language = 'Has Language'

    def __init__(self):
        pass
    
    def work(self):
        print('Starting work!')
    
    def eat(self):
        pass

Class Objects

Class objects support two operations: attribute reference and instantiation.

  • Attribute Reference: Uses the standard syntax obj.name.
  • Instantiation: Creates an instance of the class.
class MyClass:
    """A simple class example"""
    i = 12345
    
    def f(self):
        return 'hello world'

# Instantiate the class
x = MyClass()   # x is an abstract object, MyClass() is instantiation

# Access class attributes and methods
print("Attribute i of MyClass:", x.i)
print("Method f output of MyClass:", x.f())

Output:

Attribute i of MyClass: 12345
Method f output of MyClass: hello world

Many classes prefer to create objects with an initial state. Therefore, a class may define a special method named __init__() (the constructor):

def __init__(self):
    self.data = []

When a class defines an __init__() method, class instantiation automatical invokes __init__() for the newly created instance. Example:

x = MyClass()

The __init__() method can have parameters. The parameters are passed to the class during instantiation. Example:

class Complex:
    def __init__(self, realpart, imagpart):
        self.r = realpart
        self.i = imagpart

x = Complex(3.0, -4.5)
print(x.r, x.i)   # Output: 3.0 -4.5

self Represents the Instance, Not the Class

Class methods differ from ordinary functions only in that they must have an extra first parameter name, conventionally called self. self is the memory address of the object.

class Test:
    def prt(self):
        print(self)
        print(self.__class__)

t = Test()
t.prt()

Output:

<__main__.Test instance at 0x100771878>
__main__.Test

The result clearly shows that self represents an instance of the class, the address of the current object, while self.__class__ points to the class.

self is not a Python keyword; you can replace it with another name, like runoob, and it will still work:

class Test:
    def prt(runoob):
        print(runoob)
        print(runoob.__class__)

t = Test()
t.prt()

Output:

<__main__.Test instance at 0x100771878>
__main__.Test

Class Methods

Inside a class, you use the def keyword to define a method. Unlike regular funcsions, class methods must include the parameter self as the first parameter, representing the class instance.

# Class definition
class People:
    # Basic attributes
    name = ''
    age = 0
    # Private attribute (cannot be accessed directly outside the class)
    __weight = 0
    
    # Constructor method
    def __init__(self, n, a, w):
        self.name = n
        self.age = a
        self.__weight = w
    
    def speak(self):
        print("%s says: I am %d years old." % (self.name, self.age))

# Instantiate the class
p = People('John', 10, 30)
p.speak()

Output:

John says: I am 10 years old.

Instance Objects

Consider the following code:

class Person:
    '''
    This class defines a human.
    '''
    level = 'Advanced Animal'
    mind = 'Has Thoughts'
    language = 'Has Language'

    def __init__(self, name, age, sex, area, hobby):  # Constructor
        self.name = name   # self.name is an object attribute
        self.age = age
        self.sex = sex
        self.area = area
        self.hobby = hobby

    def work(self, eye):
        self.eye = eye
        print('Starting work!')
    
    def eat(self):
        pass

aduan = Person('A Duan', 18, 'Male', 'Handan, Hebei', 'Not Female')

The line aduan = Person(...) is called instantiation. It gives an object its individual uniqueness compared to other objects.

Instantiation process:

  1. An object space is created, including a pointer to the class. The space address is returned to self.
  2. The __init__ method is automatically executed, with the empty object space passed to self and the remaining arguments passed to the corresponding parameters.
  3. The init method runs, encapsulating attributes into the object. The completed object is then returned to the class name call.

Object Attributes

  1. Finding all attributes in an object:

    aduan = Person('A Duan', 18, 'Male', 'Handan', 'Not Female')
    print(aduan.__dict__)
    
  2. Manipulating attributes of an object:

    aduan = Person('A Duan', 18, 'Male', 'Handan', 'Not Female')
    print(aduan.name)      # Read
    aduan.job = 'Student'  # Add
    del aduan.age          # Delete
    aduan.sex = 'Laddyboy' # Modify
    print(aduan.__dict__)
    
  3. Manipulating static variables (static fields) of a class via an object: Only read operations are allowed; add, delete, or modify operations are not permitted.

    aduan = Person('A Duan', 18, 'Male', 'Handan', 'Not Female')
    print(aduan.level)      # Read - class static field
    aduan.level = 'Medium Animal'  # This creates a new attribute in the object, does NOT change the class-level variable
    print(aduan.level)      # Prints the object's new attribute
    del aduan.level         # Deletes the object's attribute
    print(Person.__dict__)  # Class level remains unchanged
    
  4. Executing class methods from an object:

    aying = Person('A Ying', 17, 'Female', 'Hengshui', 'Driving...')
    print(aying)
    aying.work('Big Eyes')
    print(aying.__dict__)
    # 1. self is a positional parameter, conventionally named, representing the object space.
    # 2. Attributes can be added to an object even in non-__init__ methods, but the method must be executed first.
    

Namespaces: Class vs. Object

  • Class Namespace: Created when the class is defined. It holds class-level variables and methods.
  • Object Namespace: Created during instantiation. It holds object-specific attributes. Each object has its own independent namespace, linked to the class via a pointer. Objects cannot directly access or interfere with each other's namespaces.

Lookup Order

  • Object Lookup Order: First, it looks in the object's own namespace. If the variable or method is not found there, it looks in the class namespace via the class pointer stored in the object.
  • Class Lookup Order: Directly searches within the class itself.
class A:
    home = 'Oldboy Education'
    name = 'Wu Da'
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def job(self):
        print('I am driving...')

# Lookup order for objects
obj1 = A('oldboy', 1000)
print(obj1.name)   # Finds 'name' in object space first (from __init__)
print(obj1.job)    # Looks for 'job' in object space, not found -> looks in class space
print(obj1.home)   # Not in object space -> looks in class space

# Lookup order for class
print(A.name)      # Finds 'name' directly in class space (the class variable, not the instance one)

# Object independence
obj1 = A('oldboy', 1000)
obj2 = A('alex', 10000)
print(obj1.name)   # oldboy
print(obj2.name)   # alex

Composition

Composition means giving an object of one class an attribute that is an object of another class.

class GameRole:
    def __init__(self, name, ad, hp):
        self.name = name
        self.ad = ad
        self.hp = hp
    
    def attack(self, target):
        target.hp -= self.ad
        print(f'{self.name} attacks {target.name}, {target.name} loses {self.ad} HP. {target.name} has {target.hp} HP remaining.')
    
    def equip_weapon(self, weapon):
        self.weapon = weapon

class Sword:
    def __init__(self, name, ad):
        self.name = name
        self.ad = ad
    
    def fight(self, attacker, defender):
        defender.hp -= self.ad
        print(f'{attacker.name} uses {self.name} to slash {defender.name}. {defender.name} has {defender.hp} HP remaining.')

aduan = GameRole('A Duan', 10, 100)
mike = GameRole('Mike', 120, 300)

slaughter_knife = Sword('Slaughter Knife', 200)

# Less ideal: the action initiator should be the person, not the sword itself
# slaughter_knife.fight(aduan, mike)

# More logical: assign the weapon to the person first
aduan.equip_weapon(slaughter_knife)  # Encapsulate a weapon attribute for aduan
# Now use the weapon via the person
aduan.weapon.fight(aduan, mike)

mike.attack(aduan)

Tags: Object-Oriented Programming python Classes Objects Inheritance

Posted on Wed, 28 Oct 2026 16:30:10 +0000 by gckmac