İçeriğe geç
academia.sh

Ders 16 / 16

Yeniden Yüklenebilirlik ve Ana Blok

Aynı dosya içe aktarıldığında bir, betik olarak koşturulduğunda ikinci bir modül nesnesi var eder ve ana blok yalnız ikincisinde çalışır; yeniden yükleme modül nesnesini korur ama içindeki her işlevi yeniler.

İçindekiler

Önceki 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 buraya kadar ölçülen biçimdir — dosya bir modül olarak istenir, gövdesi koşar ve adları başkalarının kullanımına açılır. Öbürü doğrudan koşturmadır: dosya bir betik olarak başlatılır ve programın giriş noktası olur.

İki biçimde de aynı gövde koşar. Ayrılan tek şey, modülün kendi adına ne yazıldığıdır ve o ada bakan bir blok yalnız bir durumda çalışır. Bu dersin sorusu şudur: aynı dosya iki biçimde koşturulduğunda kaç modül nesnesi var edilir, hangi kayıt hangisini tutar, ve bir modül yeniden yüklendiğinde ondan alınmış eski nesnelere ne olur?

Modülün Kendi Adı

Her modül nesnesinin sözlüğünde __name__ adında bir giriş vardır ve içe aktarma bu girişi modülün önbellekteki adıyla doldurur. Bir dosya içe aktarıldığında oraya dosyanın modül adı yazılır. Aynı dosya doğrudan koşturulduğunda ise oraya "__main__" yazılır, çünkü o koşumun bir içe aktarma adı yoktur — istenmemiş, başlatılmıştır.

Ana blok (main block) bu ayrımı okuyan koşuldur. Gövdenin sonunda __name__ değerini "__main__" ile karşılaştıran bir blok, dosya betik olarak koşturulduğunda çalışır, içe aktarıldığında çalışmaz. Bir dosyanın hem kitaplık hem giriş noktası olabilmesinin yolu budur: tanımlar gövdede durur ve herkese açıktır, çalıştırma ise bloğun içinde durur ve yalnız doğrudan koşumda işler.

Bunun ölçülebilir bir sonucu vardır ve ilk derste kurulan kuralla çelişmez, ondan çıkar: önbellek kaydı ada göre tutulur. Betik olarak koşan dosya __main__ adıyla kaydedilir, içe aktarılan aynı dosya kendi adıyla. İki ayrı ad, iki ayrı kayıt, iki ayrı modül nesnesi demektir — aynı dosyadan.

Yeniden Yükleme Neyi Değiştirir

Modül önbelleği bir kaydı sildiğinde sonraki istek yeni bir nesne var eder; bu ilk derste ölçüldü. Yeniden yükleme ise başka bir iştir: gövdeyi yeniden koşturur ama var olan modül nesnesinin sözlüğüne yazar. Modül nesnesi aynı kalır, içindeki adlar tazelenir.

Ayrımın iki gözlenebilir sonucu vardır ve ölçüm ikisini de sınıyor: gövde yeniden koştuğu için her tanım yeni bir nesne üretir, ve yazma işlemi sözlüğü boşaltmadan yapılır.

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

  • MP29 — Ölçüm depoya dosya bırakmaz; kaynaklar geçici bir dizinde üretilir ve dizinin yolu basılmaz.
  • MP30 — Ölçülen dosya her koşumunda kendi adını ortak bir listeye yazar; sayan taraf ölçülen dosyanın kendisidir.
  • MP31 — Betik koşumu ayrı bir süreç açmaz. Aynı yorumlayıcıda, modülün kendi adı __main__ olacak biçimde koşturulur; ölçüm bu yüzden ortak listeyi okuyabilir.
  • MP32 — Ana blok yalnız listeye bir kayıt düşer; içinde başka iş yapılmaz.
  • MP33 — Yeniden yüklemeden önce kaynak metninde tek bir dizge değiştirilir; değişen tek şey işlevin döndürdüğü değerdir.
  • MP34 — Yeniden yüklemeden önce modüle dışarıdan bir ad eklenir ve o adın akıbeti ayrıca okunur.
  • MP35 — Eski işlev nesnesi yeniden yüklemeden önce ayrı bir ada bağlanır; karşılaştırmalar is iledir ve kimlik sayısı basılmaz.
  • MP36 — Ölçüm bittiğinde eklenen yol girdisi ve bütün önbellek kayıtları geri alınır.

Ölçüm

"""Ana blok ve yeniden yukleme: ayni dosya kac modul nesnesi var eder."""

import importlib
import runpy
import sys
import tempfile
from pathlib import Path

ARAC = """import kayit

kayit.OLAY.append(('govde', __name__))


def selam():
    return 'birinci'


if __name__ == '__main__':
    kayit.OLAY.append(('ana blok', __name__))
"""
KAYIT = "OLAY = []\n"


def kur(kok):
    (kok / "kayit.py").write_text(KAYIT, encoding="utf-8")
    (kok / "arac.py").write_text(ARAC, encoding="utf-8")
    sys.path.insert(0, str(kok))
    importlib.invalidate_caches()


def sok(kok):
    sys.path.remove(str(kok))
    for ad in ("kayit", "arac"):
        sys.modules.pop(ad, None)


def olc(kok):
    kur(kok)
    kayit = importlib.import_module("kayit")
    arac = importlib.import_module("arac")
    ice_aktarma = list(kayit.OLAY)

    kayit.OLAY.clear()
    betik = runpy.run_module("arac", run_name="__main__")
    betik_olay = list(kayit.OLAY)
    ayri_nesne = betik["selam"] is not arac.selam
    onbellek_bozuldu = sys.modules["arac"] is arac

    kayit.OLAY.clear()
    arac.EKLENEN = "yeniden yuklemeden once"
    eski_selam = arac.selam
    (kok / "arac.py").write_text(ARAC.replace("'birinci'", "'ikinci'"),
                                 encoding="utf-8")
    importlib.invalidate_caches()
    yeni = importlib.reload(arac)
    sonuc = {
        "ice_aktarma": ice_aktarma,
        "betik": betik_olay,
        "ayri_nesne": ayri_nesne,
        "onbellek_bozuldu": onbellek_bozuldu,
        "yeniden_olay": list(kayit.OLAY),
        "ayni_modul": yeni is arac,
        "eski_islev": eski_selam is arac.selam,
        "eski_deger": eski_selam(),
        "yeni_deger": arac.selam(),
        "eklenen_kaldi": getattr(arac, "EKLENEN", "silindi"),
    }
    sok(kok)
    return sonuc


with tempfile.TemporaryDirectory() as d:
    s = olc(Path(d))

print(f"içe aktarmada koşan: {s['ice_aktarma']}")
print(f"betik olarak koşumda koşan: {s['betik']}")
print(f"betik ad alanındaki işlev modüldekinden ayrı nesne -> {s['ayri_nesne']}")
print(f"önbellekteki kayıt bozulmadı -> {s['onbellek_bozuldu']}")
print()
print(f"yeniden yüklemede koşan: {s['yeniden_olay']}")
print(f"modül nesnesi aynı -> {s['ayni_modul']}, "
      f"işlev nesnesi aynı -> {s['eski_islev']}")
print(f"eski ada bağlı işlev {s['eski_deger']}, "
      f"modüldeki işlev {s['yeni_deger']} veriyor")
print(f"yeniden yüklemeden önce eklenen ad -> {s['eklenen_kaldi']}")
içe aktarmada koşan: [('govde', 'arac')]
betik olarak koşumda koşan: [('govde', '__main__'), ('ana blok', '__main__')]
betik ad alanındaki işlev modüldekinden ayrı nesne -> True
önbellekteki kayıt bozulmadı -> True

yeniden yüklemede koşan: [('govde', 'arac')]
modül nesnesi aynı -> True, işlev nesnesi aynı -> False
eski ada bağlı işlev birinci, modüldeki işlev ikinci veriyor
yeniden yüklemeden önce eklenen ad -> yeniden yuklemeden once

İki Koşum, İki Nesne

İlk iki satır ana bloğun kuralını doğrudan veriyor. İçe aktarmada koşan tek şey gövdedir ve modülün kendi adı arac’tır; ana blok kaydı yok. Betik olarak koşumda aynı gövde yeniden koşuyor, ama bu kez modülün kendi adı __main__ ve ana blok da çalışıyor. Aynı dosya, aynı satırlar, iki farklı sonuç — ayrımı yapan tek şey ada yazılan değer.

Üçüncü satır bedeli gösteriyor: betik koşumunun ad alanındaki işlev, modüldeki işlevden ayrı bir nesne. Gövde ikinci kez koştuğu için def deyimi ikinci bir işlev nesnesi var etti. Aynı dosyadan var edilen modül nesnesi 2, aralarında paylaşılan tanım 0. Dördüncü satır bunu tamamlıyor: önbellekteki arac kaydı bozulmadı, hâlâ ilk nesneye bağlı. İki koşum yan yana duruyor ve birbirini görmüyor.

Bu, ana bloğa iş yazmanın neden sınırlı olduğunu açıklar. Bir dosya hem içe aktarılıp hem betik olarak koşturulursa, iki koşum aynı adları taşıyan iki ayrı ad alanı üretir. Modül düzeyinde tutulan bir sayaç ya da önbellek iki kez var edilir; birine yazılan öbüründe görünmez. Ölçümde bunun görünmemesinin tek nedeni, sayılan listenin arac’ta değil, ikisinin de paylaştığı kayit modülünde durmasıdır. Kural şudur: giriş noktası bir kabuktur — durum ve tanım gövdede kalır, ana blok yalnız bir işlevi çağırır.

Yeniden Yükleme

Alt bölüm ayrı bir düzeneği ölçüyor. Yeniden yüklemede koşan yine gövdedir ve modülün kendi adı arac olarak kalıyor — betik koşumundan farkı bu. Sonraki satır ayrımın kalbini veriyor: modül nesnesi aynı, işlev nesnesi değil. Gövde yeniden koştuğu için def yeni bir işlev nesnesi var etti ve modülün sözlüğündeki ad ona bağlandı; modül nesnesinin kendisi hiç değişmedi.

Üçüncü satır bunun kimi kırdığını gösteriyor. Yeniden yüklemeden önce işlevi kendi adına almış olan taraf eski nesneyi tutuyor ve o nesne birinci veriyor; modül üzerinden çağrılan işlev ikinci veriyor. Değişikliği yalnız modülün sözlüğünden okuyanlar gördü. Var edilen işlev nesnesi 2, tutulan 2, paylaşılan 0. İlk dersin ölçtüğü ayrım burada yeniden ödeniyor: içe aktarma nesneyi paylaşır, adı kopyalar — kopyalanmış ad tazelenmez.

Son satır sözlüğün boşaltılmadığını doğruluyor: yeniden yüklemeden önce modüle dışarıdan eklenen ad yerinde duruyor. Yeniden yükleme bir temizlik değil, bir üzerine yazmadır. Yeni gövdede karşılığı olmayan her ad — silinmiş bir tanım, dışarıdan eklenmiş bir öznitelik — eski değeriyle kalır.

İki ölçümün birlikte söylediği şudur: bir kaynağı yeniden koşturmanın üç ayrı sonucu vardır. Önbellek kaydı silinip yeniden istenirse yeni bir modül nesnesi var edilir; yeniden yükleme yapılırsa modül nesnesi korunur, içindekiler yenilenir; betik olarak koşturulursa ikinci bir ad altında ikinci bir nesne var edilir ve ilki olduğu gibi kalır. Üçünde de gövde bir kez daha koşar, ama var edilen ve tutulan nesneler üçünde de başkadır.

Özet

  • Modülün kendi adı içe aktarmada modül adıyla, doğrudan koşumda __main__ ile doldurulur; ana blok yalnız ikincisinde çalışır.
  • Aynı dosya iki biçimde koşturulduğunda 2 modül nesnesi var edilir; iki ad alanının paylaştığı tanım 0’dır ve içe aktarmadan gelen önbellek kaydı bozulmaz.
  • Ana blok bir kabuk olarak yazılır: tanım ve durum gövdede kalır, çünkü gövde iki koşumda da çalışır ve modül düzeyindeki her durum iki kez var edilir.
  • Yeniden yükleme modül nesnesini korur, gövdeyi yeniden koşturur ve içindeki adları yeni nesnelere bağlar; önceden alınmış eski işlev nesnesi eski değeri vermeye devam eder.
  • Yeniden yükleme sözlüğü boşaltmaz; yeni gövdede karşılığı olmayan adlar eski değerleriyle yerinde kalır.

Kurs Kapanışı

Kurs tek bir soruyla yürüdü: yazılan biçim kaç nesne var etti, kaçını tuttu, neyi paylaştı? Sonucun kendisi hiçbir derste ölçü sayılmadı, çünkü aynı sonucu veren iki yazımın sayıları her seferinde ayrıldı.

Ders Ölçülen biçim Var edilen / tutulan / paylaşılan
koleksiyonlar/01 Listeler bin öğelik liste ve sekiz büyütme biçimi 1000 var edilir ve tutulur; ikinci ada bağlamak 0 var eder, [tek] * 5 0 var edip beş yuvayı paylaştırır
koleksiyonlar/02 Demetler değişmezliğin kapattığı altı işlem ve k += (yeni,) 1 var edilir; kap yenidir, öğeler paylaşılır (buyuk[0] is demet[0] → True); çoklu dönüş 0 var eder
koleksiyonlar/03 Sözlükler iki yüz öğede üyelik ve keys() görünümü listede 200, kümede ve sözlükte 1 karşılaştırma; görünüm sözlüğü paylaşır ve 2’den 3’e çıkar, anlık kopya 1000 yuva tutar
koleksiyonlar/04 Kümeler üç yüz öğenin tekilleştirilmesi ve altı küme işlemi elle 15050, kümeyle 200 karşılaştırma; altı işlem 0 öğe var eder ve sonuçtaki her nesne paylaşılır
koleksiyonlar/05 Özelleşmiş Koleksiyonlar aynı gruplamanın üç yazımı ve bin öğelik akışta kırpma setdefault 320, varsayılan sözlük 100 kap var eder; akışta üç yazım da 1000 üretir, tutulan 1000’e karşı 5; döndürme listede 3 ara kap, kuyrukta 0
koleksiyonlar/06 Dilimleme sekiz dilim biçimi ve iç içe listenin kopyası sekizi de 0 öğe var edip yeni kap döndürür; iç içe listede 4 üretilir ve dilim kopyasında iki iç listenin ikisi de paylaşılır, derin kopya 4 verir
yineleme/01 Yineleyici Protokolü iter ve next sözleşmesi, üç geçiş biçimi iter 0 başvuru yazar, list() 3 yazar, kavrama 3 yeni nesne var eder; ilk ikisi öğeleri paylaşır, sonuncusu 0
yineleme/02 Üreteçler yield içeren işlevin çağrısı ve yield from kurulumda kavrama 1000, üreteç 0 var eder; üç öğede 3’te kalır, yield from ilk öğeye dek 1
yineleme/03 Üreteç İfadeleri bin öğelik toplamanın iki yazımı ikisi de 1000 var eder ve 499500 verir; listede tutulan 0’a karşı 1000
yineleme/04 Kavrama Sözdizimi liste, küme, sözlük kavraması ve süzme koşulunun yeri 1000 / 100 / 100 tutulur, paylaşılan 1000 / 0 / 100; süzme üretimden önce 5, sonra 10 var eder
yineleme/05 Lambda ve Yüksek Mertebeden Fonksiyonlar anahtar işlevinin kaç kez çağrıldığı ve map ile filter anahtar öğe başına 1 kez, toplam 200 çağrı; elle yazılan sıralamada 39800; sorted yeni kap kurar ve 200 öğeyi paylaşır, map kurulumda 0 var eder
yineleme/06 Dekoratörler sarmalamanın kurduğu katman ve meta veri koruma sarmasız 1, tek dekoratör 2, iki dekoratör 3 katman; ada bağlı nesne değişir, özgün işlev paylaşılır (__wrapped__ is hesapla → True); not alan sarmalayıcı 20 isteği 5 çağrıya indirip 5 öğe tutar
moduller-ve-paketler/01 Modül Sistemi üç içe aktarma isteği ve arama yolu sırası 2 modül nesnesi var edilir, 1 tutulur; iki ad aynı nesneyi paylaşır ve ortak kayıt modülü 1 kalır
moduller-ve-paketler/02 Paket Yapısı göreli ve mutlak yazımın çözdüğü ad tek istek 5 gövde koşturur ve 5 nesne tutar; göreli ile mutlak 0 paylaşır (is → False)
moduller-ve-paketler/03 Standart Kütüphane Turu aynı üç işin kitaplıkla ve elle yazımı elle 800 var eder ve 800 tutar, kitaplıkla 3 var eder ve 0 tutar; sonuç ikisinde de 3
moduller-ve-paketler/04 Yeniden Yüklenebilirlik ve Ana Blok içe aktarma, betik koşumu ve yeniden yükleme betik koşumu 2. modül nesnesini var eder, ilki tutulur, paylaşılan tanım 0; yeniden yükleme modülü paylaşır, işlevi yeniler

Tabloda dört okuma birbirini kesiyor. Tembellik üretimi azaltmaz, tutmayı azaltır: bin öğelik toplamada iki yazım da 1000 nesne üretir ve ikisi de 499500 verir; ayrıldıkları tek yer listede tutulandır. Kopya bir katman derinliğindedir: yeni kap kuran her işlem dış kabı yeniler, içindekileri paylaşır — demette de, dilimlemede de, küme işlemlerinde de. Maliyeti veri değil erişim biçimi belirler: aynı iki yüz öğe listede 200, kümede 1 karşılaştırma ister. Modül de bir nesnedir ve bir kez var edilir: son konu aynı sayma düzenini dosya sınırının ötesine taşıdı ve içe aktarmanın da bir var etme işi olduğunu ölçtü.

Kurs boyunca kaplar hazır durdu. Liste, demet, sözlük, küme, üreteç ve modül — hepsi dilin verdiği nesnelerdi ve ölçülen şey onların seçilmesinin bedeliydi. Bir sonraki kurs bu sınırın öbür tarafındadır. Kabı seçmekle kabı yazmak ayrı şeylerdir: bir nesnenin uzunluğunun olması, karşılaştırılabilmesi ve bir kapta anahtar olabilmesi seçilen bir özellik değil, yazılan bir sözleşmedir. Nesneye Dayalı Python ve Tipler kursu o sözleşmeyi yazan tarafı kurar: dilin sözdizimine uyan sınıflar, kalıtım yerine bileşimin seçildiği durumlar, ve tip ipuçlarıyla belirginleştirilen sözleşmeler. Burada hangi kabın kaç nesneye mal olduğu sayıldı; orada o kabın yerine geçecek nesnenin kendisi yazılacak.

İ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