Classes

Scriptling supports object-oriented programming with classes, single inheritance, the super() function, and a rich set of dunder (magic) methods.

In this section

Class Definition

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def greet(self):
        return "Hello, my name is " + self.name

    def is_adult(self):
        return self.age >= 18

Instantiation and Usage

# Create an instance
p = Person("Alice", 30)

# Access fields
print(p.name)  # "Alice"
print(p.age)   # 30

# Call methods
print(p.greet())       # "Hello, my name is Alice"
print(p.is_adult())    # True

# Modify fields
p.age = 31

The init Method

The __init__ method is the constructor, called when creating a new instance:

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

    def perimeter(self):
        return 2 * (self.width + self.height)

rect = Rectangle(10, 5)
print(rect.area())      # 50
print(rect.perimeter()) # 30

The self Parameter

self refers to the current instance and must be the first parameter of instance methods:

class Counter:
    def __init__(self):
        self.count = 0

    def increment(self):
        self.count += 1

    def get(self):
        return self.count

c = Counter()
c.increment()
c.increment()
print(c.get())  # 2

Inheritance

Scriptling supports single inheritance. A class can inherit from another class:

class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        return "Generic sound"

    def info(self):
        return "Animal: " + self.name

class Dog(Animal):
    def __init__(self, name, breed):
        # Call parent constructor
        super(Dog, self).__init__(name)
        self.breed = breed

    def speak(self):
        return "Woof!"

class Cat(Animal):
    def __init__(self, name, color):
        super(Cat, self).__init__(name)
        self.color = color

    def speak(self):
        return "Meow!"

# Usage
dog = Dog("Buddy", "Pug")
print(dog.name)    # "Buddy" (inherited field)
print(dog.breed)   # "Pug"
print(dog.speak()) # "Woof!" (overridden method)
print(dog.info())  # "Animal: Buddy" (inherited method)

cat = Cat("Whiskers", "Orange")
print(cat.speak()) # "Meow!"

The super() Function

Call parent class methods from a child class:

Parameterless super()

class Child(Parent):
    def __init__(self, value):
        super().__init__(value)  # Call parent __init__

super().__init__() is always safe: when no parent class defines __init__ it falls back to object.__init__, which takes no arguments (passing any raises TypeError, as in Python). super().__repr__(), __str__(), __eq__() and __ne__() likewise fall back to object’s versions.

Explicit super()

class Child(Parent):
    def __init__(self, value):
        super(Child, self).__init__(value)

Calling Parent Methods

class Animal:
    def speak(self):
        return "Generic sound"

class Dog(Animal):
    def speak(self):
        # Call parent method and extend
        return super(Dog, self).speak() + " and Woof!"

d = Dog("Buddy", "Pug")
print(d.speak())  # "Generic sound and Woof!"

Multiple Levels of Inheritance

class Animal:
    def __init__(self, name):
        self.name = name

class Mammal(Animal):
    def __init__(self, name, warm_blooded=True):
        super(Mammal, self).__init__(name)
        self.warm_blooded = warm_blooded

class Dog(Mammal):
    def __init__(self, name, breed):
        super(Dog, self).__init__(name)
        self.breed = breed

    def speak(self):
        return "Woof!"

dog = Dog("Buddy", "Golden Retriever")
print(dog.name)           # "Buddy"
print(dog.warm_blooded)   # True
print(dog.breed)          # "Golden Retriever"

Class and Instance Fields

class Account:
    # Class-level field (shared by all instances)
    bank_name = "First National"

    def __init__(self, owner, balance):
        # Instance fields (unique to each instance)
        self.owner = owner
        self.balance = balance

    def deposit(self, amount):
        self.balance += amount

a1 = Account("Alice", 100)
a2 = Account("Bob", 200)

print(a1.bank_name)  # "First National"
print(a2.bank_name)  # "First National"

print(a1.balance)    # 100
print(a2.balance)    # 200

A subclass can override a class-level field by assigning the same name in its own body, exactly as it can override a method. The base class keeps its value:

class Animal:
    sound = "..."

class Cat(Animal):
    sound = "meow"

print(Cat.sound, Cat().sound, Animal.sound)   # meow meow ...

Instance Attributes as a Dict (__dict__)

obj.__dict__ (and vars(obj)) gives an instance’s attributes as a dict, in the order they were first assigned. Writing to it writes through to the object, so the common idioms work:

class Bag:
    def __init__(self, **kw):
        self.__dict__.update(kw)      # set attributes from keyword arguments

b = Bag(x=1, y=2)
print(b.x, b.__dict__)                # 1 {'x': 1, 'y': 2}

b.__dict__["z"] = 3                   # same as b.z = 3
del b.__dict__["x"]                   # same as del b.x
print(vars(b))                        # {'y': 2, 'z': 3}

import json
print(json.dumps(b.__dict__))         # {"y": 2, "z": 3}

Like Python, writes through __dict__ bypass property setters. Two differences: each access returns a fresh view, so a reference you keep (d = obj.__dict__) does not show attributes assigned later (its own writes still apply); and assigning a whole new dict (obj.__dict__ = {...}) is an AttributeError — use obj.__dict__.clear() and update(), or setattr(). Names are not mangled, so self.__x appears as __x rather than _Class__x.

Nested Classes

Classes can be defined inside functions and inside other classes, and used like any other class:

def make_point(x):
    class Point:
        def __init__(self, x):
            self.x = x
    return Point(x)

class Outer:
    class Inner:
        LIMIT = 2

print(make_point(3).x)      # 3
print(Outer.Inner.LIMIT)    # 2

Limitations

No Multiple Inheritance

Only single inheritance is supported:

# NOT supported
class C(A, B):  # Error: multiple inheritance
    pass

Example: Complete Class

class BankAccount:
    def __init__(self, owner, initial_balance=0):
        self.owner = owner
        self.balance = initial_balance
        self.transactions = []

    def deposit(self, amount):
        if amount <= 0:
            raise ValueError("Deposit amount must be positive")
        self.balance += amount
        self.transactions.append(("deposit", amount))

    def withdraw(self, amount):
        if amount <= 0:
            raise ValueError("Withdrawal amount must be positive")
        if amount > self.balance:
            raise ValueError("Insufficient funds")
        self.balance -= amount
        self.transactions.append(("withdrawal", amount))

    def get_balance(self):
        return self.balance

    def get_statement(self):
        return {
            "owner": self.owner,
            "balance": self.balance,
            "transactions": self.transactions
        }

# Usage
account = BankAccount("Alice", 100)
account.deposit(50)
account.withdraw(30)
print(account.get_balance())  # 120
print(account.get_statement())

See Also