Decimal Modülü: Finansal Hesabın 'Tam Hassas' Aracı ve KDV Faciasının Çözümü
Float'la para hesaplamak — yıllar içinde bankaları sallayan klasik bug kaynağı. Python'un `decimal` modülü bu sorunu çözer: tam ondalık precision, kontrollü yuvarlama (ROUND_HALF_UP, ROUND_HALF_EVEN), context yönetimi. Bu derste: TR KDV hesabı, döviz çevirici, e-ticaret sepeti, PostgreSQL NUMERIC entegrasyonu — gerçek production pattern'leri.
Şükrü Yusuf KAYA
22 dakikalık okuma
Orta💰 Para işiyle uğraşıyorsan bu ders mecburi
Bir e-ticaret sitesi yapıyorsan, bir muhasebe yazılımı kuruyorsan, banka entegrasyonu kodluyorsan — float ile para tutmak disiplin sorunu. Yıllar içinde milyonlarca dolar kaybeden gerçek vakalar var (NASA Ariane 5 roket float overflow ile patladı 1996; bankalar yuvarlama bug'ları ile yıllar boyunca kuruşları kaybetti). Bu ders sana 'how to do it right' anlatıyor — junior dev'in profesyonel olduğu noktalardan biri.
Bir önceki ders'in tekrar — float neden para için kötü?#
>>> 0.1 + 0.2 0.30000000000000004 >>> 19.99 + 0.99 20.98 # Görünüşte sorun yok — ama: >>> total = 0.0 >>> for _ in range(100): ... total += 0.1 >>> print(total) 9.999999999999998 # 10.0 değil
100 küçük tutarın toplamı 10 değil 9.99999...; gerçek dünyada bu kuruş kaybı. Bir bankanın milyonlarca işlem yaptığını düşün — kuruş kuruş birikip büyük rakamlara ulaşır.
Daha kötüsü: yuvarlamada bias. Float "bankers rounding" yapıyor (en yakın çift sayıya). Türk vergi kanunu "yarıyı yukarı yuvarla" diyor. Davranışlar uyuşmuyor.
round(0.5)Çözüm: modülü.
decimaldecimal modülü — temelleri#
decimalDecimal, IEEE 754-2008 standardında tanımlı decimal floating-point. Yani:
- Sayıyı decimal tabanda saklıyor (binary değil) — 0.1 sonsuz tekrar etmiyor.
- Precision'ı sen kontrol ediyorsun (default 28 hane).
- Rounding mode'u sen seçiyorsun.
from decimal import Decimal, getcontext # String'den oluştur (önerilen) a = Decimal('0.1') b = Decimal('0.2') print(a + b) # 0.3 — TAM! print(a + b == Decimal('0.3')) # True # Precision (varsayılan 28 hane) print(getcontext().prec) # 28 # Bölme — hassas print(Decimal('1') / Decimal('3')) # 0.3333333333333333333333333333 (28 hane) # Float'la karşılaştır print(1/3) # 0.3333333333333333 (~16 hane)
🚨 Çok önemli: Decimal'ı string'den oluştur, float'tan değil!
# 🚫 KÖTÜ Decimal(0.1) # Decimal('0.1000000000000000055511151231257827021181583404541015625') # Float'tan oluşturuyor → float'un saklanan tam değeri Decimal'a geçiyor # ✅ İYİ Decimal('0.1') # Decimal('0.1') # Tam decimal değer # Veya integer'dan Decimal(10) / Decimal(100) # Decimal('0.1')
Bu hata yaygın; her zaman kontrol et: Decimal constructor'ına geçen şey string veya int olsun, asla float olmasın.
Context — precision, rounding, signal'lar#
Decimal'ın davranışı context ile yönetiliyor. Default context:
from decimal import getcontext print(getcontext()) # Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, # capitals=1, clamp=0, flags=[], # traps=[InvalidOperation, DivisionByZero, Overflow])
Önemli alanlar:
- prec: Anlamlı hane sayısı (toplamda — virgülden önce + sonra).
- rounding: Yuvarlama modu.
- Emin/Emax: Üs sınırları.
- traps: Hangi durumlarda exception fırlatılsın.
Precision değiştirme#
from decimal import Decimal, getcontext getcontext().prec = 6 print(Decimal('1') / Decimal('3')) # 0.333333 getcontext().prec = 50 print(Decimal('1') / Decimal('3')) # 0.33333333333333333333333333333333333333333333333333 # Default'a dön getcontext().prec = 28
Rounding modları#
from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN, ROUND_HALF_DOWN, \ ROUND_DOWN, ROUND_UP, ROUND_FLOOR, ROUND_CEILING, ROUND_05UP # Test sayısı x = Decimal('2.5') # 8 farklı yuvarlama modes = [ (ROUND_HALF_UP, "Yarı yukarı (klasik)"), # 0.5 → yukarı (ROUND_HALF_DOWN, "Yarı aşağı"), (ROUND_HALF_EVEN, "Yarı çift (bankers)"), # 0.5 → en yakın çift (ROUND_DOWN, "Sıfıra doğru (truncate)"), (ROUND_UP, "Sıfırdan uzağa"), (ROUND_FLOOR, "Sonsuz aşağı"), # negatif sayılar için fark (ROUND_CEILING, "Sonsuz yukarı"), (ROUND_05UP, "Sıfır veya 5 ise yukarı"), ] for mode, desc in modes: r = x.quantize(Decimal('1'), rounding=mode) print(f" {desc:30s} {x} → {r}")
Yarı yukarı (klasik) 2.5 → 3 Yarı aşağı 2.5 → 2 Yarı çift (bankers) 2.5 → 2 (3 çift olmadığı için) Sıfıra doğru (truncate) 2.5 → 2 Sıfırdan uzağa 2.5 → 3 Sonsuz aşağı 2.5 → 2 Sonsuz yukarı 2.5 → 3 Sıfır veya 5 ise yukarı 2.5 → 3
Türkiye finans uygulamaları genelde (kanunda "yarıyı yukarı yuvarla" geçer). Bankers rounding (default) bias'sız ama beklenmedik.
ROUND_HALF_UP# Default'u Türkiye için uygun yap getcontext().rounding = ROUND_HALF_UP
Local context (with statement)#
Default'u değiştirmek tehlikeli (global state). Tek bir hesap için local context kullan:
from decimal import localcontext a = Decimal('1') / Decimal('3') # 0.333... (28 hane, default) with localcontext() as ctx: ctx.prec = 6 b = Decimal('1') / Decimal('3') # 0.333333 (6 hane) c = Decimal('1') / Decimal('3') # 0.333... (28 tekrar) — local'dan çıkıldı
Modüler kod yazıyorsan, fonksiyon başında local context aç, kapat — başka kodun hesabını etkilemezsin.
quantize — sabit ondalık (fixed-point)#
quantizePara hesabı için en kritik metod: . Sayıyı belirli bir ondalık haneye yuvarlıyor.
quantizefrom decimal import Decimal, ROUND_HALF_UP price = Decimal('19.99') vat = Decimal('0.20') raw_total = price * (1 + vat) print(raw_total) # 23.988 (3 ondalık) # 2 ondalığa yuvarla — para format total = raw_total.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP) print(total) # 23.99 # 0 ondalık (tam sayı) whole = raw_total.quantize(Decimal('1'), rounding=ROUND_HALF_UP) print(whole) # 24 # 3 ondalık three_dec = Decimal('19.999').quantize(Decimal('0.001'), rounding=ROUND_HALF_UP) print(three_dec) # 19.999
Decimal('0.01')Decimal('0.001')Decimal('1')Para işinde her zaman ile final değeri yuvarla. Aksi halde 3 ondalıklı para tutarları çıkar — UI'da garip görünür.
quantize# 🚫 Yuvarlama unutulmuş def calculate_total(items): return sum(item.price * item.quantity for item in items) # Sonuç: 23.988 — UI'da "23.988₺" göstermek istemezsin # ✅ def calculate_total(items): raw = sum(item.price * item.quantity for item in items) return raw.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP) # Sonuç: 23.99 — temiz
Gerçek dünya: Türkiye KDV hesabı#
Türkiye'de 4 farklı KDV oranı var (2024+):
- %1: Temel gıda, kitap (sınırlı liste)
- %10: İnşaat malzemeleri, bazı hizmetler
- %20: Genel oran (mal/hizmetlerin çoğu)
- %0: İhracat, eğitim hizmetleri
Bir e-ticaret platformu yazıyorsun. Müşteri sepete ürün ekliyor, KDV hesabı yap.
from decimal import Decimal, ROUND_HALF_UP, getcontext from dataclasses import dataclass from typing import List # Default'u Türkiye finans için ayarla getcontext().rounding = ROUND_HALF_UP VAT_RATES = { "STANDARD": Decimal('0.20'), # Genel %20 "REDUCED_10": Decimal('0.10'), # %10 "REDUCED_1": Decimal('0.01'), # %1 "ZERO": Decimal('0.00'), # İhracat, eğitim } @dataclass class Product: name: str price: Decimal # KDV dahil mi hariç mi? Modele göre değişir vat_category: str quantity: int = 1 @property def vat_rate(self) -> Decimal: return VAT_RATES[self.vat_category] @property def line_total_excl_vat(self) -> Decimal: """KDV hariç satır toplamı.""" return (self.price * self.quantity).quantize( Decimal('0.01'), rounding=ROUND_HALF_UP ) @property def line_vat(self) -> Decimal: """Bu satırın KDV tutarı.""" return (self.line_total_excl_vat * self.vat_rate).quantize( Decimal('0.01'), rounding=ROUND_HALF_UP ) @property def line_total_incl_vat(self) -> Decimal: """KDV dahil satır toplamı.""" return self.line_total_excl_vat + self.line_vat @dataclass class Cart: items: List[Product] @property def subtotal(self) -> Decimal: return sum((item.line_total_excl_vat for item in self.items), Decimal('0')) @property def total_vat(self) -> Decimal: return sum((item.line_vat for item in self.items), Decimal('0')) @property def total(self) -> Decimal: return self.subtotal + self.total_vat def vat_breakdown(self) -> dict: """Her oran için ayrı toplam.""" breakdown = {} for rate_name, rate in VAT_RATES.items(): items_at_rate = [i for i in self.items if i.vat_category == rate_name] if not items_at_rate: continue base = sum((i.line_total_excl_vat for i in items_at_rate), Decimal('0')) vat = sum((i.line_vat for i in items_at_rate), Decimal('0')) breakdown[rate_name] = { "rate": rate, "base": base, "vat": vat, } return breakdown # Test cart = Cart([ Product("Ekmek", Decimal('5.00'), "REDUCED_1", quantity=2), Product("Süt", Decimal('25.00'), "REDUCED_10", quantity=1), Product("Bilgisayar", Decimal('15000.00'), "STANDARD", quantity=1), Product("Online kurs", Decimal('500.00'), "ZERO", quantity=1), ]) print(f"Subtotal: {cart.subtotal} ₺") print(f"Toplam KDV: {cart.total_vat} ₺") print(f"GENEL TOPLAM: {cart.total} ₺") print("\nKDV oranı kırılımı:") for rate_name, data in cart.vat_breakdown().items(): print(f" %{data['rate']*100:.0f} — Matrah: {data['base']}, KDV: {data['vat']}")
Bu kod production-ready Türk e-ticaret sepet hesabı. Decimal sayesinde:
- Hatasız (her hesap exact).
- Yuvarlama net (ROUND_HALF_UP).
- KDV detayı doğru.
- Faturada ne göstermen gerektiği belli.
Float'la yapsaydın: bazen 1 kuruş eksik/fazla; muhasebe uyumsuzluğu; gerçek Vergi Dairesi denetiminde gözüne batar.
Gerçek dünya: Döviz çevirici#
USD → TL conversion. Kurun tam değeri var (örn 33.4567).
from decimal import Decimal, ROUND_HALF_UP def convert_currency(amount, exchange_rate, from_decimals=2, to_decimals=2): """ Para çevir. amount: Decimal — kaynak para exchange_rate: Decimal — kur (örn 33.4567 USD/TL) """ raw = amount * exchange_rate return raw.quantize( Decimal('1') / (Decimal('10') ** to_decimals), rounding=ROUND_HALF_UP ) # 100 USD → ?TL (kur 33.4567) usd = Decimal('100.00') rate = Decimal('33.4567') tl = convert_currency(usd, rate) print(f"{usd} USD = {tl} TL") # 100.00 USD = 3345.67 TL # 1234.56 EUR → JPY (JPY ondalıksız genelde, kur 165.43) eur = Decimal('1234.56') eur_jpy = Decimal('165.43') jpy = convert_currency(eur, eur_jpy, to_decimals=0) print(f"{eur} EUR = {jpy} JPY") # 1234.56 EUR = 204253 JPY # Cross-rate (USD → EUR via TL) usd_tl = Decimal('33.4567') eur_tl = Decimal('36.2891') usd_eur = (usd_tl / eur_tl).quantize(Decimal('0.0001'), rounding=ROUND_HALF_UP) print(f"USD/EUR = {usd_eur}") # USD/EUR = 0.9220
Decimal('1') / Decimal('10') ** to_decimalsÖnemli: Kur API'sinden gelen veri string olmalı#
import requests # 🚫 Yanlış — float olarak parse data = requests.get("https://api.exchangerate.com").json() rate = Decimal(data["rate"]) # float'tan! precision kaybı # ✅ Doğru — string olarak al rate = Decimal(str(data["rate"])) # str ile float → string → Decimal
İdealde API ham response'unu string olarak döndüre — Stripe API böyle yapıyor ( yerine ).
"amount": "1999""amount": 1999.00Veritabanı entegrasyonu — PostgreSQL NUMERIC#
PostgreSQL'in tipi Decimal ile mükemmel çalışıyor.
NUMERIC(precision, scale)-- PostgreSQL şeması CREATE TABLE orders ( id SERIAL PRIMARY KEY, user_id INT NOT NULL, total NUMERIC(12, 2) NOT NULL, -- 10 hane.2 ondalık (max 9_999_999_999.99) vat_amount NUMERIC(12, 2) NOT NULL, exchange_rate NUMERIC(20, 8), -- döviz kuru için 8 ondalık created_at TIMESTAMP DEFAULT NOW() );
import psycopg2 from decimal import Decimal # Default psycopg2 NUMERIC'i Decimal olarak döner conn = psycopg2.connect("dbname=mydb user=me") cur = conn.cursor() # INSERT — Decimal doğal olarak çalışıyor total = Decimal('1234.56') cur.execute( "INSERT INTO orders (user_id, total, vat_amount) VALUES (%s, %s, %s)", (1, total, total * Decimal('0.18')) ) # SELECT — sonuç Decimal cur.execute("SELECT total, vat_amount FROM orders WHERE id = %s", (1,)) row = cur.fetchone() print(type(row[0])) # <class 'decimal.Decimal'> print(row[0] + row[1]) # toplam — exact
SQLAlchemy ile#
from sqlalchemy import Numeric, Column, Integer from sqlalchemy.orm import declarative_base Base = declarative_base() class Order(Base): __tablename__ = "orders" id = Column(Integer, primary_key=True) user_id = Column(Integer) total = Column(Numeric(12, 2)) # Decimal otomatik vat_amount = Column(Numeric(12, 2)) exchange_rate = Column(Numeric(20, 8)) # ORM kullanımı order = Order(user_id=1, total=Decimal('1234.56'), vat_amount=Decimal('222.22')) session.add(order) session.commit() # Dönerken Decimal loaded = session.query(Order).first() print(loaded.total + loaded.vat_amount) # Decimal aritmetik
PostgreSQL NUMERIC + Python Decimal → tam roundtrip. Hesaplama sırasında precision kaybı yok. Para tutan her tabloda NUMERIC kullan, FLOAT/DOUBLE PRECISION kullanma.
JSON serialization — Decimal'ı API'de göndermek#
JSON'da tipi var ama precision belirsiz. Decimal'i JSON'a koymak özel handling ister:
numberimport json from decimal import Decimal data = {"price": Decimal('19.99'), "vat": Decimal('3.998')} # 🚫 Default json.dumps(data) # TypeError: Object of type Decimal is not JSON serializable # ✅ Custom encoder ile string olarak class DecimalEncoder(json.JSONEncoder): def default(self, o): if isinstance(o, Decimal): return str(o) return super().default(o) print(json.dumps(data, cls=DecimalEncoder)) # {"price": "19.99", "vat": "3.998"} # Veya simplejson kütüphanesi (Decimal'i otomatik handle eder) import simplejson print(simplejson.dumps(data, use_decimal=True)) # {"price": 19.99, "vat": 3.998} (number olarak)
En iyi pratik: API response'unda string olarak gönder#
{ "amount": "19.99", "currency": "TRY" }
Stripe, PayPal, modern fintech API'ler bunu yapıyor. Avantaj:
- JSON parser float'a çevirip precision bozmuyor.
- Frontend tarafında da ile çalışabiliyorsun (decimal.js).
new Decimal(data.amount) - Currency ayrı field — UI biçimleme bağımsız.
FastAPI + Pydantic ile#
from decimal import Decimal from pydantic import BaseModel from fastapi import FastAPI class Order(BaseModel): amount: Decimal currency: str app = FastAPI() @app.post("/orders") def create_order(order: Order): return {"total": order.amount, "currency": order.currency} # Pydantic v2 default'ta Decimal'i string olarak serialize ediyor (3.10+) # {"total": "19.99", "currency": "TRY"}
Modern Python web framework'leri Decimal'i doğru handle ediyor — sen sadece type hint olarak belirtirsin, framework gerisini halleder.
DecimalPerformans — Decimal ne kadar yavaş?#
Decimal float'tan ~50-100x yavaş. Çünkü software emülasyon (CPU desteği yok).
import timeit from decimal import Decimal # Float t1 = timeit.timeit("0.1 + 0.2", number=1_000_000) print(f"Float: {t1:.3f}s") # ~0.05s (50 ns / op) # Decimal t2 = timeit.timeit( "Decimal('0.1') + Decimal('0.2')", setup="from decimal import Decimal", number=1_000_000 ) print(f"Decimal: {t2:.3f}s") # ~3-5s (3-5 µs / op) # Daha hızlı: Decimal nesneleri pre-create t3 = timeit.timeit( "a + b", setup="from decimal import Decimal; a = Decimal('0.1'); b = Decimal('0.2')", number=1_000_000 ) print(f"Decimal (pre-created): {t3:.3f}s") # ~0.5s
Decimal nesnesi yaratma maliyeti büyük. Eğer döngüde tekrar tekrar aynı sabit kullanıyorsan — bir kez yarat, döngüde kullan.
Pratik: Decimal yavaş ama çoğu uygulama bunu fark etmez#
- 1000 ürünlü sepet hesabı: ~3 ms (Decimal). Kullanıcıya görünmez.
- 1 milyon transaction toplam: ~3 saniye. Background job'da ezilir.
- Real-time HFT: Decimal ASLA kullanılmaz. Tutar 'int * 10000' formunda saklanır (sabit-ölçek integer) veya C/Rust'a geçilir.
Karar: Para görünüşlü iş yapan iş kodunda Decimal. Performance-critical veri pipeline'ında int * scale.
python
# Production-ready e-ticaret sepet helper'ı# Türkiye için optimize, Decimal ile from decimal import Decimal, ROUND_HALF_UP, getcontextfrom dataclasses import dataclass, fieldfrom typing import Optional # Türkiye finans default'ugetcontext().rounding = ROUND_HALF_UP def to_money(value, decimals=2) -> Decimal: """Herhangi bir sayıyı temiz para Decimal'ına çevir.""" if isinstance(value, Decimal): d = value elif isinstance(value, (int, float)): d = Decimal(str(value)) # float'tan str → Decimal (precision korumalı) elif isinstance(value, str): d = Decimal(value.replace(',', '.')) # Türkçe ondalık virgül else: raise ValueError(f"Cannot convert {type(value)} to money") quantizer = Decimal('1') / (Decimal('10') ** decimals) return d.quantize(quantizer, rounding=ROUND_HALF_UP) def format_money(value: Decimal, currency: str = "TRY") -> str: """Para gösterimi (Türkiye locale: 1.234,56 ₺).""" symbol = {"TRY": "₺", "USD": "$", "EUR": "€", "GBP": "£"}.get(currency, currency) # Tausend separator parts = str(value).split(".") integer_part = parts[0] decimal_part = parts[1] if len(parts) > 1 else "00" # Sondan üçer üçer ayır if integer_part.startswith("-"): sign, integer_part = "-", integer_part[1:] else: sign = "" grouped = "" for i, c in enumerate(reversed(integer_part)): if i and i % 3 == 0: grouped = "." + grouped grouped = c + grouped return f"{sign}{grouped},{decimal_part} {symbol}" # Testprint(to_money("19,99")) # 19.99print(to_money(19.99)) # 19.99 (str trick)print(to_money(0.1) + to_money(0.2)) # 0.30 (TAM) print(format_money(Decimal('1234567.89'))) # 1.234.567,89 ₺print(format_money(Decimal('-19.99'))) # -19,99 ₺print(format_money(Decimal('100'), "USD")) # 100,00 $to_money() ve format_money() yardımcıları — bunları projende kütüphane gibi kullan.
Bonus: Fraction — kesin rasyonel sayı#
Fractionfractionsfrom fractions import Fraction # Kesir oluşturma a = Fraction(1, 3) # 1/3 b = Fraction("1/3") c = Fraction("0.5") d = Fraction(0.5) # float'tan da OK (0.5 binary'de exact) print(a) # 1/3 print(a + a + a) # 1 — TAM (float'ta 0.9999...) # Aritmetik print(Fraction(1, 3) + Fraction(1, 4)) # 7/12 # Float'a dönüş print(float(a)) # 0.3333333333333333 # Decimal'dan Fraction from decimal import Decimal print(Fraction(Decimal('0.1'))) # 1/10
Decimal vs Fraction — ne zaman hangisi?#
| Durum | Decimal | Fraction |
|---|---|---|
| Para hesabı | ✅ | ❌ (kesir gösterimi UI için garip) |
| Tam rasyonel matematik (örn cebir, geometri) | ❌ | ✅ |
| Yuvarlama kontrolü | ✅ (modes var) | ❌ (her zaman tam) |
| Performans | Yavaş | Daha yavaş |
| JSON serialize | İyi | Kötü |
Karar: Para → Decimal. Saf matematik (örn 1/3 + 1/4 + 1/6 sonsuz hassas) → Fraction. Çoğu projede Decimal'a ihtiyaç var; Fraction nadir.
Yaygın tuzaklar#
1. Decimal(0.1) yapma#
# 🚫 Decimal(0.1) # 0.1000000000000000055511151231257827021181583404541015625 # float precision sızdı # ✅ Decimal('0.1') # 0.1
2. Float ile karıştırma#
# 🚫 total = Decimal('19.99') * 1.18 # TypeError veya float result total = Decimal('19.99') + 0.5 # decimal.InvalidOperation # ✅ total = Decimal('19.99') * Decimal('1.18') total = Decimal('19.99') + Decimal('0.5')
3. Quantize unutma#
# 🚫 total = sum(item.price * item.qty for item in items) # Sonuç: 1234.56789012 — UI'da garip # ✅ total = sum(...).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
4. Context global değiştirme#
# 🚫 getcontext().prec = 6 # global! Tüm modülleri etkiler # ✅ with localcontext() as ctx: ctx.prec = 6 # ... hesap
5. Database'de FLOAT kullanma#
-- 🚫 total FLOAT NOT NULL, -- precision kaybı total DOUBLE PRECISION NOT NULL, -- ✅ total NUMERIC(12, 2) NOT NULL, -- exact
6. JSON'da number tip#
// 🚫 {"amount": 19.99} // float parsed; precision kayıp riski // ✅ {"amount": "19.99"} // string; parse with Decimal(s)
7. Decimal'ı sıralama anahtarı yapma#
# OK sorted(items, key=lambda x: x.price) # Tehlikeli (eğer NaN olabiliyorsa) items_with_nan = [Decimal('NaN'), Decimal('1'), Decimal('2')] sorted(items_with_nan) # InvalidOperation hata verebilir
Decimal NaN ile karşılaştırma exception atıyor (float NaN sessizce False dönüyor). Trade-off — Decimal daha sıkı.
Bu derste neler kazandın?#
✓ Float'un finansal hesapta neden yetersiz olduğu (önceki dersten devam).
✓ Decimal modülü — IEEE 754-2008 decimal floating-point.
✓ vs kritik farkı.
Decimal('0.1')Decimal(0.1)✓ Context — prec, rounding mode, traps.
✓ 8 rounding mode — ROUND_HALF_UP (Türkiye), ROUND_HALF_EVEN (default bankers), ve diğerleri.
✓ ile fonksiyon-bazlı context yönetimi.
localcontext()✓ — fixed-point yuvarlama (para için kritik).
quantize✓ TR KDV hesabı production-ready Cart/Product modelleri.
✓ Currency converter — kur API entegrasyonu.
✓ PostgreSQL NUMERIC + Decimal mükemmel uyum.
✓ JSON serialization — string olarak göndermek.
✓ Performance — Decimal ~50x yavaş ama çoğu uygulamada fark etmez.
✓ Production helper'ları — to_money(), format_money().
✓ modülü kısa giriş (saf matematik için).
Fraction✓ 7 yaygın tuzak — Decimal(0.1), float karıştırma, quantize unutma, vb.
Sıradaki ders: ve . Python'da nasıl çalışır, truthiness kavramı (her şey "doğru veya yanlış" değerlendirilebilir), sentinel'ı, vs farkı, type hint'i. Sıkça karşına çıkacak küçük ama kritik konular.
boolNoneTrue/FalseNoneis None== NoneOptionalSık Sorulan Sorular
Evet, **gerçekten performance-critical** durumlarda yapılır. Stripe API tutarları cents olarak (`{"amount": 1999}` = $19.99) gönderir. Avantaj: int sınırsız, hızlı. Dezavantaj: her UI gösteriminde /100 yapman gerek, hesaplamada ölçek sürekli akılda — kafa karışıklığı yüksek. **Karar**: Tek-currency, çok hızlı işlem (örn HFT) → int. Multi-currency, business logic ağırlıklı (e-ticaret, muhasebe) → Decimal. Hibrit: DB'de int sakla, business logic'te Decimal'a çevir.
Yorumlar & Soru-Cevap
(0)Yorum yazmak için giriş yap.
Yorumlar yükleniyor...
İlgili İçerikler
Modül 1: Giriş ve Kurulum
Python Nedir, Neden Bu Kadar Popüler?
Öğrenmeye BaşlaModül 1: Giriş ve Kurulum
Python Sürümlerinin Tarihi: 2'den 3.14'e, AI Winter'lardan 'No-GIL' Devrimine
Öğrenmeye BaşlaModül 1: Giriş ve Kurulum