Data AnalyticsPython foundations for analysts

Write a Python function with a clear input contract

PK
Pankit Kumar
Sr. Data Scientist at Parexel (a Goldman Sachs–backed company) · 20 September 2026 · 3 min read
Technically reviewed by Ishaan Sharma
In this article (7 sections)

A useful function contract states what inputs mean, which values are valid, what the function returns and how invalid input fails. Type hints help communicate that contract, but Python does not automatically enforce every annotation at runtime.

Keep parsing and calculation separate when they have different responsibilities. A monetary calculation should not quietly guess whether a comma means a thousands separator or a decimal separator.

Define the units before the signature

This exercise calculates one ordinary sale line. Quantity is a positive integer. Unit price and discount are integer paise. Discount is a total for the line, must be nonnegative and cannot exceed gross line value. Returns and credit notes are outside this function's contract.

python
def net_line_paise(quantity: int, unit_price_paise: int, discount_paise: int) -> int:
    """Return nonnegative sale-line value in paise; discount applies once per line."""
    values = (quantity, unit_price_paise, discount_paise)
    if any(type(value) is not int for value in values):
        raise TypeError("quantity, price and discount must be integers")
    if quantity <= 0:
        raise ValueError("quantity must be positive")
    if unit_price_paise < 0 or discount_paise < 0:
        raise ValueError("price and discount must be nonnegative")
    gross = quantity * unit_price_paise
    if discount_paise > gross:
        raise ValueError("discount exceeds gross line value")
    return gross - discount_paise

assert net_line_paise(2, 10000, 1000) == 19000
assert net_line_paise(1, 0, 0) == 0
assert net_line_paise(1, 10000, 10000) == 0

The explicit type check rejects booleans as well as strings and floats. That is deliberate because True is not an acceptable quantity input for this business function, even though Python's Boolean type has an integer relationship.

Make invalid input visible

Do not replace invalid quantities or discounts with a convenient default. Returning zero for a negative quantity would conceal a source or scope issue and could make an incomplete report look valid.

Test zero quantity, a negative price, excessive discount and a text amount. Each should produce the documented exception class. A caller can then reject the record, stop the batch or route it for review according to the workflow policy.

The contract distinguishes a valid zero-value sale from a failed calculation. A fully discounted valid line returns zero; a malformed line raises an exception.

Keep conversion at the boundary

CSV values arrive as strings. Parse them under an explicit source format before calling the calculation. A string such as 100.00 may represent rupees, while this function expects integer paise; the conversion needs a defined decimal and rounding policy.

The Python reporting lab demonstrates a separate parser accepting canonical INR decimal text. Its Order records use Decimal amounts rather than this function's integer-paise representation. Both approaches can be appropriate when units remain explicit and are not mixed.

Avoid hidden dependencies

The function uses only its arguments and returns a result. It does not read a global discount setting, modify a worksheet, print a report or write a file. That makes its behaviour easy to test and reuse.

If a later rule needs tax treatment or a product-specific discount limit, pass an explicit approved input or introduce a separately named policy function. Do not silently reach into a mutable global configuration that changes results without appearing in the call.

Document exceptions and examples

A concise docstring should explain units, allowed values, return meaning and exceptions where the surrounding project conventions require it. Include an example that exposes the line-discount rule, such as quantity two with a 1,000-paise total discount.

Python's function-definition tutorial explains argument and return mechanics. The business contract supplies the constraints those mechanics do not infer.

Test boundaries that distinguish meanings

Normal inputs establish expected arithmetic. Boundary cases establish whether zero price, full discount and minimum quantity are valid. Invalid-type cases establish whether callers must parse first.

Do not write only a test that copies the implementation's formula. The independently stated 19,000-paise result and the full-discount zero case make the intended behaviour reviewable without reading every line of code.

Exercise: extend the project to credit notes. Decide whether to create a separate function or a broader transaction contract, and explain how you will distinguish a legitimate negative movement from an invalid ordinary sale.

NeuraPath's Data Analytics with Generative AI course connects Python functions with reliable analytical rules. A clear contract lets another analyst use the calculation without guessing its units or failure behaviour.

Continue learning

This article is part of the Python foundations for analysts sequence. Use the neighbouring tasks when you need the prerequisite or the next application.

PK
Pankit Kumar
Lead Instructor, NeuraPath Academy

Pankit Kumar has 10 years in Data Science & AI, building and shipping production systems in regulated pharma and clinical environments. He is a freelance trainer at Boston Institute of Analytics, AnalytixLabs and Scaler, and has taught this material to thousands of working professionals.

This article is part of our Data Analytics with Generative AI programme — 3–4 months. The full analyst stack — Excel, SQL, Power BI and Python pipelines — then a generative-AI layer you can prove is right.

Explore Data Analytics with Generative AI
Counselling is free · no obligation

Not sure which programme fits?

Tell us your background and we will map it to the right entry point — including saying so when a cheaper programme is the better fit. A counsellor replies within one working day.