Community Article
Community articles are authored by SitePoint Premium contributors. Content is screened before publication, and SitePoint reserves the right to moderate or remove articles that violate our guidelines. Views expressed are those of the authors and do not necessarily reflect those of SitePoint.
How developers can Build a Fixed-Share Inheritance Distribution Calculator
Published inPython·
September 8, 2026
·Updated:September 8, 2026
The AI briefing for Developers
Stay up to date with AI tools, model releases, and developer workflows that matter.
Weekly. Free. One click to leave.
SitePoint Premium
Stay Relevant and Grow Your Career in Tech
- Premium Results
- Publish articles on SitePoint
- Daily curated jobs
- Learning Paths
- Discounts to dev tools
7 Day Free Trial. Cancel Anytime.
Fixed-share inheritance systems show up in several legal traditions: a set of rules assigns specific fractions of an estate to specific classes of heirs, some heirs block others from inheriting entirely, and the numbers have to reconcile even when the fractions don’t divide the estate evenly. That combination, fixed fractions, conditional exclusion rules, and a normalization step when the math doesn’t land on exactly 100 percent, makes for a genuinely interesting rules-engine problem to implement, distinct from a typical calculator’s arithmetic.
This walkthrough builds one using the Islamic Faraid system as the worked example, since its rules are well documented and precise, but the underlying pattern, fixed shares, blocking logic, proportional reconciliation, applies to any fixed-share succession system you might need to model.
A necessary disclaimer before the code: this is a technical walkthrough of implementing a rules engine, not religious or legal guidance. Faraid is a detailed area of Islamic jurisprudence with real scholarly nuance, and an actual estate distribution should be reviewed by a qualified scholar, not decided by a demo script. The examples below cover common, well-established cases to illustrate the programming pattern, not the full ruleset.
Start with the data, not the calculation logic. A heir needs a relationship type, whether they’re present, and any conditions that affect their share, such as whether the deceased left children.
from dataclasses import dataclassfrom fractions import Fraction@dataclassclassHeir:relation:strpresent:boolcount:int=1classEstate:def__init__(self, net_value:float, heirs:list[Heir], deceased_gender:str):self.net_value = net_valueself.heirs ={h.relation: h for h in heirs if h.present}self.deceased_gender = deceased_genderUsing Fraction rather than floating point matters here, not as a style preference. Fixed shares are exact fractions, 1/2, 1/4, 1/8, 1/6, 2/3, and floating point arithmetic introduces rounding error that compounds across several heirs. A distribution that’s supposed to sum to exactly 1 can drift to 0.9999999999 with floats, which then breaks any code that checks whether shares are complete.
Some heirs receive a fixed fraction of the estate under specific conditions, spouse, parents, and daughters among them. This is naturally a lookup table keyed on relationship and context, rather than a long chain of conditionals.
defspouse_share(estate: Estate)-> Fraction:has_descendants =any(estate.heirs.get(r, Heir(r,False)).presentfor r in("son","daughter","grandson","granddaughter"))if estate.deceased_gender =="male":return Fraction(1,8)if has_descendants else Fraction(1,4)else:return Fraction(1,4)if has_descendants else Fraction(1,2)defmother_share(estate: Estate)-> Fraction:has_descendants =any(estate.heirs.get(r, Heir(r,False)).presentfor r in("son","daughter"))has_multiple_siblings = estate.heirs.get("siblings", Heir("siblings",False, count=0)).count >=2if has_descendants or has_multiple_siblings:return Fraction(1,6)return Fraction(1,3)Each function takes the same estate context and returns a fraction, which keeps the calling code uniform regardless of how complex an individual rule is internally. The mother’s share above is a good example of why this needs to be a function rather than a static table entry, her fraction depends on two independent conditions, not just her own presence.
Blocking Rules: Some Heirs Exclude Others
A rule that’s easy to miss if you model heirs independently: certain heirs, when present, remove other heirs from inheriting entirely, not just reduce their share. A son present blocks grandsons and, in most interpretations, blocks siblings of the deceased from inheriting at all.
BLOCKING_RULES ={"son":["grandson","granddaughter","brother","sister"],"father":["grandfather","brother","sister"],}defapply_blocking(estate: Estate)-> Estate:blocked =set()for blocker, blocked_relations in BLOCKING_RULES.items():if estate.heirs.get(blocker, Heir(blocker,False)).present:blocked.update(blocked_relations)estate.heirs ={relation: heirfor relation, heir in estate.heirs.items()if relation notin blocked}return estateRunning blocking logic before fixed-share calculation, not after, matters. If a blocked heir’s share gets calculated and then discarded, later normalization steps that check whether shares sum correctly will work against the wrong total.
Fixed shares are assigned independently, spouse, mother, daughters, each by their own rule, which means nothing guarantees they’ll sum to exactly the whole estate. When they add up to more than 100 percent, a proportional reduction applies to every fixed share equally.
defapply_awl(shares:dict[str, Fraction])->dict[str, Fraction]:total =sum(shares.values())if total <=1:return sharesreturn{relation: share / total for relation, share in shares.items()}This is a normalization problem that shows up well beyond inheritance calculators, anywhere fixed allocations are assigned independently and need to be scaled back proportionally when they overcommit a shared resource. The pattern is the same whether you’re allocating percentages of a budget, weights in a scoring system, or shares of an estate: sum what’s been assigned, and if it exceeds the whole, divide every share by that sum to bring the total back to exactly 1 while preserving each share’s relative proportion.
The reverse case, fixed shares summing to less than the whole estate with no residuary heir to absorb the remainder, is handled differently, typically by returning the surplus proportionally to the fixed-share heirs rather than leaving it unassigned. That reconciliation step is worth building as a distinct, explicitly named function rather than folding it into the same code path as apply_awl, since silently handling both directions in one function makes it easy to introduce a sign error that’s hard to catch in testing.
Testing Against Known Cases
Because the output here has real consequences if it’s wrong, and because the interacting rules are genuinely easy to get subtly wrong, this is a case where testing against known, worked examples matters more than testing against your own logic.
deftest_wife_with_children():estate = Estate(net_value=100000,heirs=[Heir("wife",True), Heir("son",True)],deceased_gender="male",)shares = calculate_shares(estate)assert shares["wife"]== Fraction(1,8)deftest_awl_reduces_proportionally():shares ={"a": Fraction(1,2),"b": Fraction(1,2),"c": Fraction(1,3)}reduced = apply_awl(shares)assertsum(reduced.values())==1assert reduced["a"]== reduced["b"]Testing that shares sum to exactly 1 after any normalization step is a cheap, high-value check, an easy class of bug is a normalization function that runs but leaves the total at 0.999 or 1.001 due to a logic error, and that kind of bug won’t announce itself unless something explicitly checks for it.
Applying the Pattern Beyond This Example
The three techniques here, a rule table keyed on context rather than a long conditional chain, exclusion logic applied before share calculation rather than after, and proportional normalization when independently-assigned shares don’t sum cleanly, generalize past inheritance law entirely. SitePoint’s React calculator tutorial is a good reference for the interface layer once the underlying logic is solid, and the data-modeling approach here follows the same separation of concerns used in building a PDF invoice generator with PHP, keep the calculation logic and its data structures independent of however the result eventually gets displayed or exported.
Scope
The example rules above cover common, well-established cases, spouse, parents, children, in typical configurations. A production implementation of this specific domain would need to handle grandparents, more distant relatives, the Umariyyatan special case for a specific mother-father-spouse combination, and school-of-thought (madhab) variation, which is a meaningfully larger scope than what’s shown here. Several existing calculators handle that fuller ruleset already; Holy Quran Learning’s inheritance calculator is one example if you want to see a fuller implementation’s output to test your own logic against, or if the goal is simply getting a distribution rather than building the engine yourself.
If you’re building this for real use rather than as a learning exercise, treat that as a hard scope boundary: implement and test the well-established core cases thoroughly, and be explicit in the UI about which scenarios aren’t covered, rather than silently returning an incomplete or incorrect distribution for an edge case the code doesn’t actually handle.
Frequently Asked Questions
Why use exact fractions instead of floating point for this kind of calculator?
Fixed shares are exact values (1/2, 1/4, 1/8, and so on), and floating point arithmetic introduces rounding error that compounds as more heirs are added. A total that should equal exactly 1 can drift slightly with floats, which breaks any validation logic checking that shares are complete.
Why does blocking logic need to run before share calculation?
If a blocked heir’s share is calculated and then discarded afterward, any later step that checks whether shares sum correctly is working against the wrong total. Removing blocked heirs first keeps every downstream calculation consistent.
Is the proportional reduction pattern (Awl) specific to inheritance calculators?
No. It’s a general normalization technique for any situation where independently assigned fixed allocations might exceed a shared total, budget percentages, scoring weights, reardless of domain
Should a tool like this be relied on for an actual estate distribution?
No. This walkthrough covers common, well-documented cases to illustrate a programming pattern. Real inheritance distribution involves scholarly interpretation, jurisdiction-specific legal requirements, and edge cases well beyond what’s shown here, and should be reviewed by a qualified scholar or legal professional.
Summary
Fixed-share distribution systems are a good exercise in rules-engine design specifically because the three hard parts, contextual rule lookup, exclusion logic, and proportional reconciliation, don’t show up together in most calculator tutorials. Modeling heirs as explicit data, applying blocking rules before share calculation, and handling the case where shares don’t sum cleanly with a proportional normalization step are patterns worth having in a general toolkit, well beyond this specific example. Where this walkthrough stops well short of a production system is real domain scope, actual inheritance law involves considerably more edge cases and scholarly nuance than shown here, and that gap is worth being explicit about rather than quietly ignoring.


