Altblümler

 
7. Giriş ve Çıkış

Bir programın çıktısını sunmanın birkaç yolu vardır; veri yazdırılabilir ya da gelecekte kullanılabilecek şekilde bir dosyaya kaydedilebilir. Bu bölümde giriş ve çıkış ile ilgili olanakların bazılarına değineceğiz.

 
7.1 Daha Güzel Çıkış Biçimi

Buraya kadar değerleri yazdırmanı iki yolunu gördük: deyim ifadeleri ve print deyimi. Üçüncü bir yol da dosya nesnelerinin write() metodudur. Standart çıktı dosyasına sys.stdout şeklinde atıfta bulunulabilir.

Çoğu zaman boşluklar ile biribirinden ayrılmış değerlerden daha iyi biçimlendirilimiş bir çıktıya ihtiyaç duyulur. Çıktınızı biçimlendirmenin iki yolu var. İlki bütün karakter dizisi işlemlerini dilimleme ve birleştirme ile yapıp istediğiniz herhangi bir biçimi elde etmek. string standart modülü karakter dizilerinin istenen sütun genişliğine kadar boşluklar ile doldurulmasını sağlayan ,daha sonra değineceğimiz, bazı faydalı fonksiyonlara sahiptir. İkinci yol ise sol argümanı bir karakter dizisi olan % islecini kullanmaktır. % isleci sol argümanını sağdaki argümanına uygulanacak sprintf() tarzı biçim karakter dizisi olarak yorumlar ve biçimleme işleminden sonra bir karakter dizisi geri döndürür.

Sayısal değerleri karakter dizisine çevirmek için ise değer repr() veya str() fonksiyonuna geçirilebilir ya da ters tırnak işareti ( ``) içine alınabilir ( repr() ile aynı etkiyi yapar).

str() fonksiyonu değerlerin insan tarafından okunabilir gösterimini geri döndürürken, repr() fonksiyonu ise yorumlayıcı tarafından okunabilir gösterimini geri döndürür (veya uygun sözdizim yok ise SyntaxError istisnası oluşturur). İnsan için anlam ifade edecek bir gösterimi bulunmayan nesneler için str() fonksiyonu repr() ile aynı değeri döndürür. Rakamlar, listeler ve sözlükler gibi yapılar ile daha pek çok değer için her iki fonksiyon da aynı sonucu verir. Karakter dizileri ve kayar noktalı rakamlar ise iki farklı gösterime sahiptir.

İşte birkaç örnek:

>>> s = 'Hello, world.'
>>> str(s)
'Hello, world.'
>>> `s`
"'Hello, world.'"
>>> str(0.1)
'0.1'
>>> `0.1`
'0.10000000000000001'
>>> x = 10 * 3.25
>>> y = 200 * 200
>>> s = 'The value of x is ' + `x` + ', and y is ' + `y` + '...'
>>> print s
The value of x is 32.5, and y is 40000...
>>> # Ters tırnaklar sayılar dışındaki tipler ile de çalışır:
... p = [x, y]
>>> ps = repr(p)
>>> ps
'[32.5, 40000]'
>>> # Karakter dizisinde ise tırnaklar ve ters bölü işareti eklenir:
... hello = 'hello, world\n'
>>> hellos = `hello`
>>> print hellos
'hello, world\n'
>>> # Ters tırnakların argümanı bir demet de olabilir:
... `x, y, ('spam', 'eggs')`
"(32.5, 40000, ('spam', 'eggs'))"

Sayıların kare ve küplerinden oluşan bir tablo yazdırmanın iki yolu vardır:

>>> import string
>>> for x in range(1, 11):
...     print string.rjust(`x`, 2), string.rjust(`x*x`, 3),
...     # Üst satırın sonundaki virgüle dikkat edin.
...     print string.rjust(`x*x*x`, 4)
...
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000
>>> for x in range(1,11):
...     print '%2d %3d %4d' % (x, x*x, x*x*x)
...
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

Sütunların arasındaki bir karakterlik boşluk print tarafından eklenir; argümanların arasına daima bir boşluk karakteri eklenir.

Bu örnek karakter dizilerinin başını boşluklar ile doldurup bunları sağ tarafa dayayan string.rjust() fonksiyonunu kullanmaktadır. Buna benzer string.ljust() ve string.center() fonksiyonları da vardır. Bunlar bir şey yazdırmaz; sadece yeni bir karakter dizisi geri döndürürler. Verilen karakter dizisi uzun ise kırpılmaz ve aynen geri döndrürlür; bu sütunlarınızın bozulmasına sebep olmasına rağmen hatalı bir değer göstermekten iyidir. Büyük bir değeri kırpmayı gerçekten istiyorsanız dilimleme ile bunu yapabilirsiniz ("string.ljust(x, n)[0:n]" gibi ).

string.zfill() fonksiyonu ise rakamlar içeren karakter dizilerinin başını sıfırlar ile doldurur. Bu fonksiyon artı ve eksi işaretlerini de dikkate alır:

>>> import string
>>> string.zfill('12', 5)
'00012'
>>> string.zfill('-3.14', 7)
'-003.14'
>>> string.zfill('3.14159265359', 5)
'3.14159265359'

% isleci şu şekilde kullanılır:

>>> import math
>>> print 'PI sayısının yaklaşık değeri: %5.3f' % math.pi
PI sayısının yaklaşık değeri: 3.142

Karakter dizisinin içinde birden fazla biçim varsa sağ operand olarak bir demet kullanmak gerekir:

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
>>> for name, phone in table.items():
...     print '%-10s ==> %10d' % (name, phone)
...
Jack       ==>       4098
Dcab       ==>       7678
Sjoerd     ==>       4127

Çoğu biçim aynı C dilindeki gibi çalışır ve doğru veri tipinin geçirilmesi gerekir; bu yapılamaz ise bir istisna oluşur. %s biçiminin kullanımı daha rahattır; verilen argüman karakter dizisi değilse yerleşik fonksiyon str() ile karakter dizisine dönüştürülür. Genişlik ya da hassasiyeti belirtmek için * ile bir tamsayı argüman kullanılabilir. C dilindeki %n ve %p biçimler ise desteklenmemektedir.

Eğer bölmek istemediğiniz gerçekten uzun bir biçim karakter diziniz varsa biçimlendirmek istediğiniz argümanlara konumu yerine ismiyle atıfta bulunabilmeniz güzel olur. Bu aşağıda gösterildiği gibi %(isim)biçim şeklinde yapılabilir:

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print 'Jack: %(Jack)d; Sjoerd: %(Sjoerd)d; Dcab: %(Dcab)d' % table
Jack: 4098; Sjoerd: 4127; Dcab: 8637678

Bu özellik bütün yerel değişkenlerin bulunduğu bir sözlük geri döndüren yerleşik fonksiyon vars() ile beraber kullanıldığında faydalı olur.

 
7.2 Dosya Okuma ve Yazma

open() fonksiyonu bir dosya nesnesi geri döndürür ve genellikle iki argüman ile kullanılır: "open(dosya_adı, mod)"

>>> f=open('/tmp/workfile', 'w')
>>> print f
<open file '/tmp/workfile', mode 'w' at 80a0960>

İlk argüman dosya adını içeren bir karakter dizisidir. İkincisi ise dosyanın nasıl kullanılacağını belirten karakterlerden oluşur. Erişim modu dosyadan sadece okuma yapılacak ise 'r', sadece yazma için 'w' (anı isimli bir dosya zaten var ise bu silinir) ve dosyanın sonuna eklemeler yapmak için 'a' olur. 'r+' modu dosyayı hem okuma hem de yazma yapmak için açar. mod argümanı seçimliktir; kullanılamaması halinde 'r' olduğu varsayılır.

Windows ve Macintosh üzrinde moda eklenen 'b' harfi dosyayı binary modunda açar; yani 'rb', 'wb', ve 'r+b' gibi modlar da vardır. Windows metin ve binary dosyaları arasında ayrım yapmaktadır; metin dosyalarında okuma veya yazma işlemlerinde satır sonu karakterleri otomatik olarak biraz değişir. Bu görünmez değişiklik ASCII metin dosyaları için iyidir; anacak JPEG resimler veya .EXE dosyalar gibi binary verileri bozar.

 
7.2.1 Dosya Nesnelerinin Metodları

Bundan sonraki örneklerde f adlı bir dosya nesnesinin önceden yaratılmış olduğunu varsayacağız.

Dosyanın içeriğini okumak için belirli miktarda veriyi okuyup bunu karakter dizisi olarak geri döndüren f.read(boy) metodu kullanılabilir. boy okunacak bayt sayısını belirleyen seçimlik bir argümandır; kullanılmaması halinde dosyanın tamamı okunur. Dosyanın sonuna gelindiğinde f.read() boş bir karakter dizisi ( "") geri döndürür.

>>> f.read()
'Dosyanın tamamı bu satırdan oluşuyor.\n'
>>> f.read()
''

f.readline() dosyadan tek bir satır okur. Satırın sonundaki yeni satır karakteri (\n) korunur; ancak dosya yeni bir satır ile bitmiyor ise son satırda bu karakter silinir. Bu özellik geri döndürülen değerin birden fazla anlama gelmesini engeller; f.readline() boş bir karakter dizisi geri döndürdüğünde dosyanın sonuna ulaşılırken boş bir satır tek bir '\n' karakteri ile ifade edilir.

>>> f.readline()
'Bu dosyanın ilk satırı.\n'
>>> f.readline()
'Dosyanın ikinci satırı\n'
>>> f.readline()
''

f.readlines() dosya içindeki bütün satırların bulunduğu bir liste geri döndürür. Seçimlik parametre boy_ipucu kullanılması durumunda ise dosyadan boy_ipucu kadar ve bundan bir satır tamamlamaya yetecek kadar fazla bayt okunur ve bunlar yine satırlar listesi şeklinde geri döndürülür.

>>> f.readlines()
['Bu dosyanın ilk satırı.\n', 'Dosyanın ikinci satırı\n']

f.write(karakter_dizisi) metodu karakter_dizisi içeriğini dosyaya yazar ve None geri döndürür.

>>> f.write('Bu bir deneme satırıdır.\n')

f.tell() dosya nesnesinin dosya içindeki konumunu belirten bir tamsayı geri döndürür (dosyanın başından bayt cinsinden ölçülür). "f.seek(uzaklık, nereden)" ile de dosyanın içinde istenen konuma gidilebilir. Konum uzaklık ile referans noktası nereden değerlerinin toplanması ile bulunur. nereden 0 olursa dosyanın başını, 1 o andaki konumu, 2 ise dosyanın sonunu belirtir. nereden kullanılmaz ise 0 olduğu varsayılır ve referans noktası olarak dosyanın başı alınır.

>>> f=open('/tmp/workfile', 'r+')
>>> f.write('0123456789abcdef')
>>> f.seek(5)     # Dosyadaki 5'inci bayta git
>>> f.read(1)
'5'
>>> f.seek(-3, 2) # Sondan 3'üncü bayta git
>>> f.read(1)
'd'

Dosya ile işiniz bittiğinde metodunu f.close() çağırarak dosyayı kapatabilir ve dosyanın işgal ettiği sistem kaynaklarını serbest bırakabilirsiziz. f.close() çağırıldıktan sonra dosya üzerinde başka işlem yapmaya devam etmek mümkün değildir:

>>> f.close()
>>> f.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ValueError: I/O operation on closed file

Dosya nesnelerinin isatty() ve truncate() gibi pek sık kullanılmayan başka metodları da vardır.

 
7.2.2 pickle Modülü

 

Karakter dizileri kolayca dosyalara yazılıp dosyalardan okunabilirler. Sayılar biraz zahmetlidir; çünkü read() metodu sadece karakter dizileri geri döndürür ve bunların '123' gibi bir değeri alıp sayısal değeri 123'ü geri döndüren string.atoi() fonksiyonundan geçirilmeleri gerekir. Listeler, sözlükler ve sınıf fertleri (class instances) gibi daha karmaşık veri türlerini dosyalara kaydetmek isterseniz işler oldukça zorlaşır.

Programcıları karmaşık veri türlerini saklamak için kodlamak ve hata ayıklamak ile uğraştırmak yerine Python bu iş için pickle adlı standart modülü sağlar. Bu hayret verici modül neredeyse herhangi bir Python nesnesini (bazı Python kodu biçimlerini bile !) karakter dizisi ile ifade edilebilecek hale getirebilir ve bu halinden geri alabilir. Bu dönüşüm ve geri kazanım işlemleri arasında nesne bir dosyaya kaydedilebilir ya da ağ bağlantısı ile uzaktaki başka bir makineye gönderilebilir.

x gibi bir nesneniz ve yazma işlemi için açılmış f gibi bir dosya nesneniz varsa bu nesneyi dosyaya aktarmanız için tek satırlık kod yeterli olur:

pickle.dump(x, f)

Nesneyi geri almak için ise f okumak için açılmış bir dosya nesnesi olsun:

x = pickle.load(f)

Birden fazla nesnenin dönüştürülmesi gerekiyor ya da dönüştürülmüş olan nesnelerin dosyaya yazılması istenmiyor ise pickle farklı şekilde kullanılır. Bunları pickle modülünün dokümanlarından öğrenmek mümkündür.

pickle modülü saklanabilen ve başka programlar tarafından ya da aynı programın farklı çalışma zamanlarında kullanılabilecek Python nesneleri yapmanın standart yoludur. pickle modülü çok yaygın kullanıldığından Python genişletme modülleri yazan çoğu programcı matrisler gibi yeni veri tiplerinin doğru olarak dönüştürülebilir ve geri alınabilir olmasına özen gösterirler.