Skip to content
Kavachकवच

Coming From Another Language: Python

● Beginner6 minBefore this: Coming From Another Language

From Python: records instead of classes, errors in the signature instead of exceptions, and none only where a type allows it.

Here is one small program twice: in Python as you would write it, then in Kavach. Orders with a quantity and a price, a total that refuses an order with no quantity, and discount codes that may be missing. Both print the same three lines.

from dataclasses import dataclass


@dataclass
class Order:
    item: str
    qty: int
    cents: int

    def cost(self) -> int:
        return self.qty * self.cents


class BadQty(Exception):
    def __init__(self, item: str):
        self.item = item


def total(orders: list[Order]) -> int:
    for o in orders:
        if o.qty <= 0:
            raise BadQty(o.item)
    return sum(o.cost() for o in orders)


def main():
    codes = {"SPRING": 10, "VIP": 25}
    orders = [Order("pen", 3, 150), Order("cup", 1, 900)]

    try:
        total_ = total(orders)
    except BadQty:
        total_ = 0
    off = codes.get("SPRING", 0)
    print(f"total {total_}, with {off}% off {total_ * (100 - off) // 100}")
    print(f"WINTER gives {codes.get('WINTER', 0)}%")

    broken = [Order("kite", 0, 500)]
    try:
        print(f"total {total(broken)}")
    except BadQty as e:
        print(f"refused: no quantity for {e.item}")


main()
orders.py: python code
type Order {
    item: String
    qty: Int
    cents: Int

    fn cost(self) -> Int {
        self.qty * self.cents
    }
}

type OrderError = BadQty(item: String)

fn total(orders: [Order]) -> Int ! OrderError {
    for o in orders {
        if o.qty <= 0 {
            fail OrderError.BadQty(item: o.item)
        }
    }
    orders.sum(o => o.cost())
}

fn main() {
    const codes = ["SPRING": 10, "VIP": 25]
    const orders = [Order(item: "pen", qty: 3, cents: 150), Order(item: "cup", qty: 1, cents: 900)]

    const sum = total(orders) catch _ => 0
    const off = codes["SPRING"] ?? 0
    print("total {sum}, with {off}% off {sum * (100 - off) / 100}")
    print("WINTER gives {codes["WINTER"] ?? 0}%")

    const broken = [Order(item: "kite", qty: 0, cents: 500)]
    match total(broken) {
        ok(t) => print("total {t}"),
        err(OrderError.BadQty(item)) => print("refused: no quantity for {item}"),
    }
}

The program ran and printed:

kavach run orders.kav

total 1350, with 10% off 1215WINTER gives 0%refused: no quantity for kite
orders.kav: Kavach code, then what running it prints

What changes

In PythonIn KavachLearn it
class Order: with @dataclasstype Order { … }, its methods inside itRecords
raise BadQty(…) and exceptfail OrderError.BadQty(item: …), with ! OrderError in the signature, and catch or matchErrors
an exception passes up by itselftry passes it on, so every call that can fail is markedtry
Nonenone, only in a type that ends in ?Optionals
codes.get("SPRING", 0)codes["SPRING"] ?? 0Reading a value
f"total {x}""total {x}": every string can hold valuesInterpolation
sum(o.cost() for o in orders)orders.sum(o => o.cost())map, filter, sum
-7 // 2 is -4, rounded down-7 / 2 is -3, towards zero; div_floor rounds downArithmetic
b = a shares a listb = a copies itValues, Not References
types checked by a separate tool, if at allevery type checked before the program runsData Types
threads and the GIL, or asynciospawn starts a task, spawn cores runs it on any core; there is no asyncHow Tasks Run
pip and requirements.txtkavach.toml, and kavach addPackages
blocks by indentationblocks in braces, { … }Syntax

Habits from other languages get a clear error that says what to write instead: see Habits from other languages.