İçeriğe geç
academia.sh

Ders 15 / 16

Standart Kütüphane Turu

Aynı işin standart kitaplıkla ve elle yazımı üç eksende ölçülür: akışta satır aynı kalır ama var edilen nesne 800'e karşı 3'tür, ad ayırmada altı addan 2'si, gün eklemede altı tarihten 1'i sessizce ayrışır.

İçindekiler

Önceki derste ölçülen paketlerin hepsi ölçüm için üretildi: gövdeleri bir satırlıktı ve tek işleri kendilerini saydırmaktı. Oysa her koşumda hazır bulunan, hiçbir kurulum gerektirmeyen büyük bir modül ve paket kümesi vardır; dilin kendisiyle birlikte gelir ve arama yolunda zaten durur. Bu ders o kümenin kapsamına bakıyor.

Soru “hangi modül ne yapar” değil — bir başvuru listesi bu dersin işi değildir. Soru şudur: aynı iş standart kitaplıktan bir modülle ve elle yazıldığında ne fark eder? Ölçülen üç eksen var: kaç nesne var edilir, kaç nesne tutulur, ve kaç satır yazılır. Dördüncü bir şey de sayılır: elle yazımın kaç durumda sessizce ayrıştığı.

Kitaplığın Kapsamı

Standart kitaplık dilin parçasıdır ve dışarıdan bir şey getirmeden içe aktarılır. Kapsadığı alanlar birkaç öbekte toplanır.

Metin ve veri biçimleri: re örüntü eşlemeyi, textwrap metin sarmayı, unicodedata karakter özelliklerini verir; json, csv ve configparser yaygın veri biçimlerini okur ve yazar. Tarih ve takvim: datetime tarih ve zaman aritmetiğini, calendar takvim sorgularını, zoneinfo saat dilimlerini taşır.

Dosya sistemi ve kaynak: pathlib yol nesnelerini, shutil toplu dosya işlerini, tempfile geçici alanı, glob örüntüyle dosya seçmeyi verir. Veri yapıları: collections özelleşmiş kapları, heapq öncelikli erişimi, bisect sıralı listede yer bulmayı, array tek tipli sayı dizisini sağlar.

Fonksiyonel araçlar: itertools yineleyici birleştirme ve dilimlemeyi, functools sarmalama ve önbelleklemeyi, operator işleçlerin fonksiyon karşılıklarını verir. Sayı: math, statistics, decimal, fractions ve random ayrı sayı alanlarını kapsar. Tip ve sözleşme: typing, dataclasses, enum ve abc.

Sistem ve çalıştırma: sys, os, subprocess, argparse ve logging. Eşzamanlılık: threading, multiprocessing, asyncio ve concurrent.futures. Ağ ve aktarım: socket, http, urllib. Sıkıştırma ve özet: zipfile, tarfile, gzip, hashlib, hmac, secrets. Sınama: unittest ve doctest.

Bu bir liste olarak ezberlenmez; işe yarar okuma, bir işe başlarken o işin hangi öbeğe düştüğünü sormaktır. Öbek bulunduğunda modül de bulunur.

Kitaplığı İçe Aktarmanın Bedeli

Standart kitaplığın modülleri de bu konunun ilk iki dersinde ölçülen kuralın içindedir; ayrı bir düzenekleri yoktur. Bir kitaplık modülü ilk kez istendiğinde gövdesi bir kez koşar, modül nesnesi var edilir ve önbelleğe yazılır; aynı modülün sonraki bütün istekleri 0 gövde koşturur ve yeni nesne var etmez. İlk derste ölçülen is karşılaştırması bunu doğrudan gösteriyordu.

Aynı biçimde, kitaplığın paket olan parçaları için ikinci dersin peşin içe aktarma ölçümü geçerlidir: bir paketin alt modülü istendiğinde zincirdeki her düzeyin gövdesi koşar. Bu, kitaplığı kullanmanın bir bedeli olduğu anlamına gelir — ama bir kez ödenen bir bedeldir ve elle yazımın ödettiği bedelle aynı türden değildir. Elle yazım her çağrıda çalışır; içe aktarma bir kez çalışır, sonra yalnız bir sözlük araması kadar iş yapar.

Bu yüzden “gereksiz içe aktarmadan kaçınmak” ile “gereksiz nesne var etmekten kaçınmak” ayrı iki iştir. Birincisi bir kereliktir ve modül sayısıyla ölçülür; ikincisi her çağrıda tekrar eder ve öğe sayısıyla ölçülür. Ölçümün ilk tablosu ikinci türdendir.

Üç İş, İki Yazım

Ölçüm üç iş üzerinde yapılıyor ve her iş iki kez yazılıyor. Birincisi iki kaynaktan gelen öğelerin ilk üçünü almak: elle yazımda iki liste kurulup birleştirilir ve baştan üç öğe dilimlenir; kitaplıkla yazımda itertools iki akışı zincirler ve baştan üç öğe alınır.

İkincisi bir dosya adını kök ve uzantı olarak ayırmak: elle yazımda ad son noktadan bölünür; kitaplıkla yazımda pathlib bir yol nesnesi kurar ve iki parçayı ondan okur. Üçüncüsü bir tarihe gün eklemek: elle yazımda ay uzunlukları ve artık yıl kuralı yazılır; kitaplıkla yazımda datetime iki nesneyi toplar.

Üç iş bilerek farklı türden seçilmiştir. Birincisinde iki yazım aynı sonucu verir ve ayrım yalnız maliyettedir; ikincisinde ve üçüncüsünde ise sonucun kendisi kimi girdide ayrılır. Bu, “kitaplık daha kısa yazdırır” gibi tek boyutlu bir okumayı baştan engeller: kazanç kimi işte nesnede, kimi işte satırda, kimi işte doğrulukta ortaya çıkar.

Satır sayısının dürüst ölçülmesi için altı yazımın hepsi birer kaynak metni olarak tutulur; satır sayısı o metinden sayılır ve işlevler aynı metinden üretilir. Böylece sayılan satırla koşan satır aynı olur.

Ölçümün varsayımları:

  • MP20Oge sınıfı ortak tanımdan alınmıştır; sayma düzeni değiştirilmemiştir ve sayaç her ölçümden önce sıfırlanır.
  • MP21 — Akış ölçümünde iki kaynağın her biri 400 değer taşır; toplam 800’dür.
  • MP22 — “Ara kapta tutulan”, işlev sonucu döndürdüğü anda ara listede duran öğe sayısıdır; tembel yazımda böyle bir liste kurulmadığı için 0 yazılır.
  • MP23 — Satır sayısı, işlevin kaynak metninin boş uçları atılmış satır sayısıdır; aynı metin koşturulan işlevi üretir.
  • MP24 — Altı ad ve altı tarih elle seçilmiştir; kenar durumları kapsayacak biçimde, rastgele değil.
  • MP25 — Kâhin standart kitaplığın sonucudur; elle yazım ona göre ayrışır ya da uyar.
  • MP26 — Elle yazılan artık yıl kuralı dörde bölünebilirlik kuralıdır; yüzyıl düzeltmesi bilerek yazılmamıştır.
  • MP27 — Gün ekleme ölçümündeki tarihler yıl, ay ve yüzyıl sınırlarını kapsar; sonuçlar yıl, ay, gün üçlüsü olarak karşılaştırılır.
  • MP28 — Ölçüm hiçbir dosyaya dokunmaz; yol nesneleri yalnız ad olarak kurulur ve dosya sistemine sorulmaz.

Ölçüm

"""Standart kitaplik: ayni is elle yazildiginda kac nesne ve kac satir."""

from datetime import date, timedelta
from itertools import chain, islice
from pathlib import PurePosixPath

SAYAC = {"uretilen": 0}


class Oge:
    """Her uretimi sayan oge; ortak tanimin sayma duzeni degismez."""

    def __init__(self, deger):
        SAYAC["uretilen"] += 1
        self.deger = deger


KAYNAK = {
    "elle_akis": """
def elle_akis(a, b):
    hepsi = [Oge(d) for d in a] + [Oge(d) for d in b]
    return hepsi[:3], len(hepsi)
""",
    "kitaplikla_akis": """
def kitaplikla_akis(a, b):
    akis = chain((Oge(d) for d in a), (Oge(d) for d in b))
    return list(islice(akis, 3)), 0
""",
    "elle_ad_ayir": """
def elle_ad_ayir(ad):
    taban = ad.rsplit("/", 1)[-1]
    if "." not in taban:
        return taban, ""
    kok, nokta, son = taban.rpartition(".")
    return kok, nokta + son
""",
    "kitaplikla_ad_ayir": """
def kitaplikla_ad_ayir(ad):
    yol = PurePosixPath(ad)
    return yol.stem, yol.suffix
""",
    "elle_gun_ekle": """
def elle_gun_ekle(y, a, g, gun):
    uzunluk = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    for _ in range(gun):
        son = uzunluk[a - 1]
        if a == 2 and y % 4 == 0:
            son = 29
        g += 1
        if g > son:
            g, a = 1, a + 1
            if a > 12:
                a, y = 1, y + 1
    return y, a, g
""",
    "kitaplikla_gun_ekle": """
def kitaplikla_gun_ekle(y, a, g, gun):
    sonuc = date(y, a, g) + timedelta(days=gun)
    return sonuc.year, sonuc.month, sonuc.day
""",
}

AD_ALANI = {"Oge": Oge, "chain": chain, "islice": islice, "date": date,
            "PurePosixPath": PurePosixPath, "timedelta": timedelta}
for kaynak in KAYNAK.values():
    exec(kaynak, AD_ALANI)


def satir(ad):
    return len(KAYNAK[ad].strip().splitlines())


def akisi_olc(islev, n=400):
    SAYAC["uretilen"] = 0
    sonuc, ara = AD_ALANI[islev](range(n), range(n))
    return SAYAC["uretilen"], ara, len(sonuc)


ADLAR = ["veri.csv", "arsiv.tar.gz", ".gizli", "ad.", "klasor/ad.txt", "ad"]
TARIHLER = [(2024, 2, 28, 1), (2023, 2, 28, 1), (2100, 2, 28, 1),
            (2000, 2, 28, 1), (2024, 12, 31, 1), (2024, 1, 31, 45)]

print(f"{'iki kaynaktan ilk üç öğe':<26s} {'satır':>5s} {'var edilen':>10s}"
      f" {'ara kapta tutulan':>17s} {'döndürülen':>10s}")
for ad, etiket in (("elle_akis", "elle"), ("kitaplikla_akis", "kitaplıkla")):
    uretim, ara, dondurulen = akisi_olc(ad)
    print(f"  {etiket:<24s} {satir(ad):5d} {uretim:10d} {ara:17d}"
          f" {dondurulen:10d}")

print()
print(f"ad ayırma: elle {satir('elle_ad_ayir')} satır, "
      f"kitaplıkla {satir('kitaplikla_ad_ayir')} satır")
ayrisan = [(a, AD_ALANI["elle_ad_ayir"](a), AD_ALANI["kitaplikla_ad_ayir"](a))
           for a in ADLAR
           if AD_ALANI["elle_ad_ayir"](a) != AD_ALANI["kitaplikla_ad_ayir"](a)]
print(f"denenen ad {len(ADLAR)}, ayrışan {len(ayrisan)}")
for a, e, k in ayrisan:
    print(f"  {a:16s} elle {e}  kitaplıkla {k}")

print()
print(f"gün ekleme: elle {satir('elle_gun_ekle')} satır, "
      f"kitaplıkla {satir('kitaplikla_gun_ekle')} satır")
sapan = [(t, AD_ALANI["elle_gun_ekle"](*t), AD_ALANI["kitaplikla_gun_ekle"](*t))
         for t in TARIHLER
         if AD_ALANI["elle_gun_ekle"](*t) != AD_ALANI["kitaplikla_gun_ekle"](*t)]
print(f"denenen tarih {len(TARIHLER)}, sapan {len(sapan)}")
for t, e, k in sapan:
    print(f"  {t}  elle {e}  kitaplıkla {k}")
iki kaynaktan ilk üç öğe   satır var edilen ara kapta tutulan döndürülen
  elle                         3        800               800          3
  kitaplıkla                   3          3                 0          3

ad ayırma: elle 6 satır, kitaplıkla 3 satır
denenen ad 6, ayrışan 2
  .gizli           elle ('', '.gizli')  kitaplıkla ('.gizli', '')
  ad.              elle ('ad', '.')  kitaplıkla ('ad.', '')

gün ekleme: elle 12 satır, kitaplıkla 3 satır
denenen tarih 6, sapan 1
  (2100, 2, 28, 1)  elle (2100, 2, 29)  kitaplıkla (2100, 3, 1)

Aynı Satır, Farklı Nesne

İlk tablo bu dersin en aykırı sonucudur: iki yazımın satır sayısı eşit, ikisi de 3. Kitaplık burada yazı kısaltmıyor. Ayrıldıkları yer sayılan nesnede: elle yazım 800 öğe var ediyor, kitaplıkla yazım 3. Döndürülen ikisinde de 3.

Fark, işin hangi noktada yapıldığından geliyor. Elle yazımda iki liste kavramayla kuruluyor; kavrama kurulduğu anda bütün öğeleri var ediyor, sonra ikisi birleştiriliyor ve ancak en sonda ilk üçü alınıyor. Öbür yazımda itertools iki akışı tüketmeden zincirliyor ve baştan üç öğe istendiğinde yalnız üç öğe var ediliyor; geri kalan 797 hiç üretilmiyor.

Ara kap sütunu tutmayı ayrı gösteriyor: elle yazımda sonuç döndüğü anda 800 öğe hâlâ bir listede duruyor, kitaplıkla yazımda 0. Bu, kursun ikinci iddiasının standart kitaplık üzerinden görünen yüzüdür — burada tembel olan yazım, üretimi geciktirmekle kalmıyor, hiç istenmeyeni hiç üretmiyor, çünkü akış sonuna kadar tüketilmiyor.

Bu ayrımın sınırını yanlış okumamak gerekir. Kitaplığın zincirlediği akış üretimden kaçınmıyor; yalnız üretimi tüketime bağlıyor. Aynı akış sonuna kadar tüketilseydi o da 800 öğe var ederdi ve iki yazım arasındaki üretim farkı sıfırlanırdı; ayakta kalan tek fark, ara listede tutulan öğe sayısı olurdu. Kazancın kaynağı tembelliğin kendisi değil, istenenin azlığıdır: üç öğe istendi, üç öğe üretildi.

Buradan çıkan kural şudur: standart kitaplığın kazandırdığı şey her zaman satır değildir. Kimi modül yazıyı kısaltır, kimi de yazıyı aynı bırakıp var edilen nesneyi düşürür. İkisi ayrı kazançtır ve ayrı ölçülür. Bir modülü seçerken sorulacak soru “kaç satır kısaltır” değil, “hangi ekseni değiştirir” olmalıdır.

Satır Farkı ve Sessiz Ayrışma

İkinci ve üçüncü ölçümde tablo tersine dönüyor: satır farkı büyük. Ad ayırma elle 6, kitaplıkla 3 satır; gün ekleme elle 12, kitaplıkla 3. Dörtte bir oranında bir fark, ama asıl bedel satırlarda değil.

Ad ayırmada denenen 6 adın 2’si ayrışıyor. Baştan noktalı .gizli adında elle yazım kökü boş bırakıp uzantıyı .gizli sayıyor; kitaplık ise adın tamamını kök, uzantıyı boş kabul ediyor. Sonu noktalı ad. adında elle yazım uzantıyı . yapıyor, kitaplık yine adın tamamını kök sayıyor. Çok uzantılı arsiv.tar.gz ve dizinli klasor/ad.txt adlarında iki yazım uyuşuyor — ayrışma her durumda değil, yalnız kenarlarda.

Gün eklemede denenen 6 tarihin 1’i sapıyor ve sapma bir yüzyıl sınırında. Elle yazılan artık yıl kuralı dörde bölünebilirliğe bakıyor; 2100 dörde bölündüğü için elle yazım şubatı 29 gün sayıyor ve (2100, 2, 29) veriyor. Kitaplık (2100, 3, 1) veriyor, çünkü yüzyıl kuralını da uyguluyor. Yıl sınırı, artık yıl ve kırk beş günlük atlama gibi geri kalan beş durumda iki yazım aynı sonucu veriyor.

İki ölçümün ortak dersi budur: elle yazım yanlış sonucu gürültüyle vermez. Hiçbir istisna fırlamıyor, hiçbir uyarı çıkmıyor; sonuç yalnızca sessizce başka. Denenen durumların çoğunda uyuşma olduğu için sınama kümesi kenarları içermiyorsa ayrışma hiç görünmez. Standart kitaplığın esas kazandırdığı şey, o kenar durumların zaten yazılmış olmasıdır.

İki Ayrışmanın Aynı Türden Olmadığı

Sayılar aynı sütunda dursa da iki ayrışma aynı şey değildir ve karıştırılmaları bu ölçümün en kolay yanlış okumasıdır.

Gün eklemedeki sapma bir yanlıştır. Takvim kuralı dilin bir tercihi değil, dışarıda tanımlı bir kuraldır; yüzyıl düzeltmesini yazmayan yazım o kurala uymamıştır ve verdiği tarih hiçbir okumada doğru değildir. Burada kitaplık kâhindir, çünkü kuralın tamamını uygular.

Ad ayırmadaki ayrışma ise bir sözleşme farkıdır. Baştan noktalı bir adın uzantısı olup olmadığı takvim gibi dışarıdan belirlenmiş bir olgu değildir; kitaplık bir kural seçmiştir, elle yazım başka bir kural seçmiştir. Gizli dosya adlarının uzantısız sayılması yaygın bir sözleşmedir ve kitaplık onu uygular; ama bir uygulama bunun tersine ihtiyaç duyabilir. Ayrışan 2 durum, elle yazımın kusuru değil, iki sözleşmenin ayrıldığı noktadır.

Buradan çıkan ölçüt şudur: bir işi elle yazma kararı, kitaplığın sözleşmesinin işe uymadığını gösterebildiğinde doğrudur. Kitaplığın ne yaptığı bilinmeden yazılan elle çözüm bu ölçütü karşılamaz; farkı bilerek yazılan çözüm karşılar. İki durumun kaynak metni aynı görünür, ayrımı yapan tek şey farkın ölçülmüş olmasıdır.

Özet

  • Standart kitaplık dilin parçasıdır; metin, veri biçimi, takvim, dosya sistemi, veri yapısı, fonksiyonel araç, sayı, sistem, eşzamanlılık, ağ ve sınama öbeklerini kapsar.
  • Akış işinde iki yazımın satır sayısı eşittir (3 ve 3) ama elle yazım 800 öğe var eder, tembel yazım 3; ara kapta tutulan 800’e karşı 0’dır.
  • Kitaplığın kazancı her zaman satır değildir: kimi modül yazıyı kısaltır, kimi de var edilen nesneyi düşürür; iki kazanç ayrı ölçülür.
  • Ad ayırmada elle yazım 6 satır tutar ve denenen 6 addan 2’sinde kitaplıktan ayrışır; ayrışma yalnız kenar adlardadır.
  • Gün eklemede elle yazım 12 satır tutar ve denenen 6 tarihten 1’inde sapar; sapma yüzyıl kuralının yazılmamasından gelir.
  • Elle yazımın yanlışı istisna fırlatmaz; sonuç sessizce başka çıkar, bu yüzden kenar durumları içermeyen bir sınama kümesi ayrışmayı hiç göstermez.

Sonraki Adım

Bu derste her şey içe aktarıldı: kitaplık modülleri de, ölçüm işlevleri de bir gövdenin içinde tanımlandı ve dışarıdan çağrıldı. Oysa aynı dosya iki ayrı biçimde çalışabilir — biri içe aktarılan modül olarak, öbürü doğrudan koşturulan betik olarak. İki biçimde de aynı gövde koşar ama modülün kendi adı değişir, ve o ada bakan bir blok yalnız bir durumda çalışır. Sonraki ders bu ikiliği ölçüyor: aynı dosya iki biçimde koşturulduğunda kaç modül nesnesi var edilir, ve bir modül yeniden yüklendiğinde eski nesnelere ne olur?

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat