# 11. Standart Kütüphanenin Kısa Özeti — Bölüm II

Bu ikinci özet, profesyonel programlama ihtiyaçlarını destekleyen daha gelişmiş modülleri kapsar. Bu modüller nadiren küçük komut dosyalarında bulunur.

## 11.1. Çıktı Biçimlendirmesi

`reprlib` modülü, büyük veya derinlemesine iç içe kapların kısaltılmış gösterimleri için özelleştirilmiş bir `repr()` sürümünü sağlar:

    >>> import reprlib
    >>> reprlib.repr(set('supercalifragilisticexpialidocious'))
    "{'a', 'c', 'd', 'e', 'f', 'g', ...}"

`pprint` modülü, hem yerleşik hem de kullanıcı tanımlı nesnelerin yorumlayıcı tarafından okunabilecek şekilde yazdırılması üzerinde daha karmaşık kontrol sunar. Sonuç bir satırdan uzun olduğunda, “pretty printer” veri yapısını daha net bir şekilde ortaya çıkarmak için satır sonları ve girintiler ekler:

    >>> import pprint
    >>> t = [[[['black', 'cyan'], 'white', ['green', 'red']], [['magenta',
    ...     'yellow'], 'blue']]]
    ...
    >>> pprint.pprint(t, width=30)
    [[[['black', 'cyan'],
       'white',
       ['green', 'red']],
      [['magenta', 'yellow'],
       'blue']]]

`textwrap` modülü, metin paragraflarını belirli bir ekran genişliğine uyacak şekilde biçimlendirir:

    >>> import textwrap
    >>> doc = """The wrap() method is just like fill() except that it returns
    ... a list of strings instead of one big string with newlines to separate
    ... the wrapped lines."""
    ...
    >>> print(textwrap.fill(doc, width=40))
    The wrap() method is just like fill()
    except that it returns a list of strings
    instead of one big string with newlines
    to separate the wrapped lines.

`locale` modülü kültüre özgü veri biçimlerinden oluşan bir veritabanına erişmektedir. Yerel ortamın biçim işlevinin gruplandırma özniteliği, sayıları grup ayırıcılarıyla biçimlendirmek için doğrudan bir yol sağlar:

    >>> import locale
    >>> locale.setlocale(locale.LC_ALL, 'English_United States.1252')
    'English_United States.1252'
    >>> conv = locale.localeconv()          # get a mapping of conventions
    >>> x = 1234567.8
    >>> locale.format("%d", x, grouping=True)
    '1,234,567'
    >>> locale.format_string("%s%.*f", (conv['currency_symbol'],
    ...                      conv['frac_digits'], x), grouping=True)
    '$1,234,567.80'

## 11.2. Şablonlamak

`string` modülü birçok yönlü kullanıcılar tarafından düzenlemeye uygun basitleştirilmiş sözdizimine sahip şablon sınıfı `Template` içerir. Bu, kullanıcıların uygulamayı değiştirmek zorunda kalmadan uygulamalarını özelleştirmelerini sağlar.

Format, geçerli Python tanımlayıcılarıyla (alfasayısal karakterler ve alt çizgiler) `$` tarafından oluşturulan yer tutucu adlarını kullanır. Yer tutucuyu ayraçla çevrelemek, onu araya giren boşluklar olmadan daha alfasayısal harflerle takip etmenizi sağlar. `$$` yazmak tek bir `$` oluşturur:

    >>> from string import Template
    >>> t = Template('${village}folk send $$10 to $cause.')
    >>> t.substitute(village='Nottingham', cause='the ditch fund')
    'Nottinghamfolk send $10 to the ditch fund.'

`substitute()` yöntemi, bir sözlükte veya anahtar sözcük bağımsız değişkeninde yer tutucu sağlandığında `KeyError` öğesini yükseltir. Adres mektup birleştirme stili uygulamalar için, kullanıcı tarafından sağlanan veriler eksik olabilir ve `safe_substitute()` yöntemi daha uygun olabilir — veriler eksikse yer tutucuları değiştirmez:

    >>> t = Template('Return the $item to $owner.')
    >>> d = dict(item='unladen swallow')
    >>> t.substitute(d)
    Traceback (most recent call last):
      ...
    KeyError: 'owner'
    >>> t.safe_substitute(d)
    'Return the unladen swallow to $owner.'

Şablon alt sınıfları özel bir sınırlayıcı belirtebilir. Örneğin, bir fotoğraf tarayıcısı için toplu yeniden adlandırma yardımcı programı, geçerli tarih, görüntü sıra numarası veya dosya biçimi gibi yer tutucular için yüzde işaretlerini kullanmayı seçebilir:

    >>> import time, os.path
    >>> photofiles = ['img_1074.jpg', 'img_1076.jpg', 'img_1077.jpg']
    >>> class BatchRename(Template):
    ...     delimiter = '%'
    >>> fmt = input('Enter rename style (%d-date %n-seqnum %f-format):  ')
    Enter rename style (%d-date %n-seqnum %f-format):  Ashley_%n%f

    >>> t = BatchRename(fmt)
    >>> date = time.strftime('%d%b%y')
    >>> for i, filename in enumerate(photofiles):
    ...     base, ext = os.path.splitext(filename)
    ...     newname = t.substitute(d=date, n=i, f=ext)
    ...     print('{0} --> {1}'.format(filename, newname))

    img_1074.jpg --> Ashley_0.jpg
    img_1076.jpg --> Ashley_1.jpg
    img_1077.jpg --> Ashley_2.jpg

Templating için başka bir uygulama, program mantığını birden çok çıktı biçiminin ayrıntılarından ayırmaktır. Bu, XML dosyaları, düz metin raporları ve HTML web raporları için özel şablonların değiştirilmesini mümkün kılar.

## 11.3. İkili Veri Kaydı Düzenleriyle Çalışma

`struct` modülü, değişken uzunluklu ikili kayıt formatlarıyla çalışmak için `pack()` ve `unpack()` işlevlerini sağlar. Aşağıdaki örnek, `zipfile` modülünü kullanmadan bir ZIP dosyasındaki başlık bilgilerinin nasıl döngüye alınacağını gösterir. Paket kodları `"H"` ve `"I"` sırasıyla iki ve dört baytlık işaretsiz sayıları temsil eder. `"<"`, standart boyutta ve küçük endian bayt düzeninde olduklarını gösterir:

    import struct

    with open('myfile.zip', 'rb') as f:
        data = f.read()

    start = 0
    for i in range(3):                      # show the first 3 file headers
        start += 14
        fields = struct.unpack('<IIIHH', data[start:start+16])
        crc32, comp_size, uncomp_size, filenamesize, extra_size = fields

        start += 16
        filename = data[start:start+filenamesize]
        start += filenamesize
        extra = data[start:start+extra_size]
        print(filename, hex(crc32), comp_size, uncomp_size)

        start += extra_size + comp_size     # skip to the next header

## 11.4. Çoklu iş parçacığı

Diş açma, sıralı olarak bağımlı olmayan görevlerin ayrıştırılması için bir tekniktir. Diğer görevler arka planda çalışırken kullanıcı girdisini kabul eden uygulamaların yanıt verme hızını artırmak için iş parçacıkları kullanılabilir. İlgili bir kullanım durumu, başka bir iş parçacığındaki hesaplamalara paralel olarak I/O çalıştırmaktadır.

Aşağıdaki kod, ana program çalışmaya devam ederken üst düzey `threading` modülünün görevleri arka planda nasıl çalıştırabileceğini gösterir:

    import threading, zipfile

    class AsyncZip(threading.Thread):
        def __init__(self, infile, outfile):
            threading.Thread.__init__(self)
            self.infile = infile
            self.outfile = outfile

        def run(self):
            f = zipfile.ZipFile(self.outfile, 'w', zipfile.ZIP_DEFLATED)
            f.write(self.infile)
            f.close()
            print('Finished background zip of:', self.infile)

    background = AsyncZip('mydata.txt', 'myarchive.zip')
    background.start()
    print('The main program continues to run in foreground.')

    background.join()    # Wait for the background task to finish
    print('Main program waited until background was done.')

Çok iş parçacıklı uygulamaların temel zorluğu, verileri veya diğer kaynakları paylaşan iş parçacıklarını koordine etmektir. Bu amaçla, iş parçacığı modülü, kilitler, olaylar, koşul değişkenleri ve semaforlar dahil olmak üzere bir dizi senkronizasyon ilkesi sağlar.

Bu araçlar güçlü olsa da, küçük tasarım hataları, yeniden üretilmesi zor sorunlara neden olabilir. Bu nedenle, görev koordinasyonuna yönelik tercih edilen yaklaşım, bir kaynağa tüm erişimi tek bir iş parçacığında yoğunlaştırmak ve ardından bu iş parçacığını diğer iş parçacıklarından gelen isteklerle beslemek için `queue` modülünü kullanmaktır. İş parçacıkları arası iletişim ve koordinasyon için `Queue` nesnelerini kullanan uygulamaların tasarımı daha kolay, daha okunaklı ve daha güvenilirdir.

## 11.5. Günlükleme

`logging` modülü, tam özellikli ve esnek bir kayıt sistemi sunar. En basit haliyle, günlük mesajları bir dosyaya veya `sys.stderr` adresine gönderilir:

    import logging
    logging.debug('Debugging information')
    logging.info('Informational message')
    logging.warning('Warning:config file %s not found', 'server.conf')
    logging.error('Error occurred')
    logging.critical('Critical error -- shutting down')

Bu, aşağıdaki çıktıyı üretir:

    WARNING:root:Warning:config file server.conf not found
    ERROR:root:Error occurred
    CRITICAL:root:Critical error -- shutting down

Varsayılan olarak, bilgi ve hata ayıklama mesajları bastırılır ve çıktı standart hataya gönderilir. Diğer çıktı seçenekleri, mesajları e-posta, datagramlar, yuvalar veya bir HTTP Sunucusuna yönlendirmeyi içerir. Yeni filtreler mesaj önceliğine göre farklı yönlendirme seçebilir: `DEBUG`, `INFO`, `WARNING`, `ERROR` , ve `CRITICAL`.

Günlük kaydı sistemi, doğrudan Python’dan yapılandırılabilir veya uygulamayı değiştirmeden özelleştirilmiş günlük kaydı için kullanıcı tarafından düzenlenebilir bir yapılandırma dosyasından yüklenebilir.

## 11.6. Zayıf Başvurular

Python otomatik bellek yönetimi yapar (çoğu nesne için referans sayımı ve döngüleri ortadan kaldırmak için garbage collection). Hafıza, ona yapılan son başvurunun ortadan kaldırılmasından kısa bir süre sonra serbest bırakılır.

Bu yaklaşım çoğu uygulama için iyi sonuç verir ancak bazen nesneleri yalnızca başka bir şey tarafından kullanıldıkları sürece izlemeye ihtiyaç duyulur. Ne yazık ki, sadece onları izlemek onları kalıcı kılan bir referans oluşturur. `weakref` modülü, referans oluşturmadan nesneleri izlemek için araçlar sağlar. Nesneye artık ihtiyaç duyulmadığında, zayıf referans tablosundan otomatik olarak kaldırılır ve zayıf referans nesneleri için bir geri arama tetiklenir. Tipik uygulamalar, oluşturması pahalı olan nesneleri önbelleğe almayı içerir:

    >>> import weakref, gc
    >>> class A:
    ...     def __init__(self, value):
    ...         self.value = value
    ...     def __repr__(self):
    ...         return str(self.value)
    ...
    >>> a = A(10)                   # create a reference
    >>> d = weakref.WeakValueDictionary()
    >>> d['primary'] = a            # does not create a reference
    >>> d['primary']                # fetch the object if it is still alive
    10
    >>> del a                       # remove the one reference
    >>> gc.collect()                # run garbage collection right away
    0
    >>> d['primary']                # entry was automatically removed
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
        d['primary']                # entry was automatically removed
      File "C:/python38/lib/weakref.py", line 46, in __getitem__
        o = self.data[key]()
    KeyError: 'primary'

## 11.7. Listelerle Çalışma Araçları

Birçok veri yapısı ihtiyacı yerleşik liste türüyle karşılanabilir. Ancak bazen farklı performans ödünleşimleri ile alternatif uygulamalara ihtiyaç duyulmaktadır.

`array` modülü, yalnızca homojen verileri depolayan ve daha kompakt bir şekilde depolayan bir liste gibi bir `array()` nesnesi sağlar. Aşağıdaki örnek, normal Python int nesneleri listeleri için giriş başına olağan 16 bayt yerine iki baytlık işaretsiz ikili sayılar (tür kodu `"H"`) olarak saklanan bir sayı dizisini gösterir:

    >>> from array import array
    >>> a = array('H', [4000, 10, 700, 22222])
    >>> sum(a)
    26932
    >>> a[1:3]
    array('H', [10, 700])

`collections` modülü, eklemelerin daha hızlı olduğu ve sol taraftan açılan ancak ortada daha yavaş aramaların olduğu bir liste gibi bir `deque()` nesnesi sağlar. Bu nesneler, kuyruklar uygulamak ve ilk ağaç aramalarını genişletmek için çok uygundur:

    >>> from collections import deque
    >>> d = deque(["task1", "task2", "task3"])
    >>> d.append("task4")
    >>> print("Handling", d.popleft())
    Handling task1

    unsearched = deque([starting_node])
    def breadth_first_search(unsearched):
        node = unsearched.popleft()
        for m in gen_moves(node):
            if is_goal(m):
                return m
            unsearched.append(m)

Alternatif liste uygulamalarına ek olarak, kitaplık ayrıca sıralanmış listeleri işlemek için işlevlere sahip `bisect` modülü gibi başka araçlar da sunar:

    >>> import bisect
    >>> scores = [(100, 'perl'), (200, 'tcl'), (400, 'lua'), (500, 'python')]
    >>> bisect.insort(scores, (300, 'ruby'))
    >>> scores
    [(100, 'perl'), (200, 'tcl'), (300, 'ruby'), (400, 'lua'), (500, 'python')]

`heapq` modülü, düzenli listelere dayalı yığınları uygulamak için işlevler sağlar. En düşük değerli giriş her zaman sıfır konumunda tutulur. Bu, en küçük öğeye tekrar tekrar erişen ancak tam liste sıralamasını çalıştırmak istemeyen uygulamalar için kullanışlıdır:

    >>> from heapq import heapify, heappop, heappush
    >>> data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
    >>> heapify(data)                      # rearrange the list into heap order
    >>> heappush(data, -5)                 # add a new entry
    >>> [heappop(data) for i in range(3)]  # fetch the three smallest entries
    [-5, 0, 1]

## 11.8. Ondalık Kayan Nokta Aritmetiği

`decimal` modülü, ondalık kayan nokta aritmetiği için bir `Decimal` veri tipi sunar. İkili kayan noktanın yerleşik `float` uygulamasıyla karşılaştırıldığında, sınıf özellikle için yararlıdır

- tam ondalık gösterim gerektiren finansal uygulamalar ve diğer kullanımlar,

- hassasiyet üzerinde kontrol,

- yasal veya düzenleyici gereklilikleri karşılamak için yuvarlama üzerinde kontrol,

- önemli ondalık basamakların izlenmesi veya

- kullanıcının sonuçların elle yapılan hesaplamalarla eşleşmesini beklediği uygulamalar.

Örneğin, 70 sentlik bir telefon ücretinde 5% vergi hesaplamak ondalık kayan nokta ve ikili kayan nokta için farklı sonuçlar verir. Sonuçlar en yakın küsurata yuvarlanırsa fark önemli hale gelir:

    >>> from decimal import *
    >>> round(Decimal('0.70') * Decimal('1.05'), 2)
    Decimal('0.74')
    >>> round(.70 * 1.05, 2)
    0.73

`Decimal` sonucu, iki basamaklı anlamlı çarpanlardan otomatik olarak dört basamaklı anlamlılık çıkaran, sonunda bir sıfır tutar. Ondalık, matematiği elle yapıldığı gibi yeniden üretir ve ikili kayan nokta ondalık miktarları tam olarak temsil edemediğinde ortaya çıkabilecek sorunları önler.

Tam gösterim, `Decimal` sınıfının, ikili kayan nokta için uygun olmayan modlo hesaplamaları ve eşitlik testleri gerçekleştirmesini sağlar:

    >>> Decimal('1.00') % Decimal('.10')
    Decimal('0.00')
    >>> 1.00 % 0.10
    0.09999999999999995

    >>> sum([Decimal('0.1')]*10) == Decimal('1.0')
    True
    >>> sum([0.1]*10) == 1.0
    False

`decimal` modülü, aritmetikle birlikte gerektiği kadar hassasiyet sağlar:

    >>> getcontext().prec = 36
    >>> Decimal(1) / Decimal(7)
    Decimal('0.142857142857142857142857142857142857')