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_string("%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:/python312/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, kütüphane 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
>>> 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 == 1.0
False

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

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