7. Girdi ve Çıktı

Bir programın çıktısını sunmanın birkaç yolu vardır; veriler okunabilir bir biçimde yazdırılabilir veya ileride kullanılmak üzere bir dosyaya yazılabilir. Bu bölümde bazı olasılıklar tartışılacaktır.

7.1. Güzel Çıktı Biçimlendirmesi

So far we’ve encountered two ways of writing values: expression statements and the print() function. (A third way is using the write() method of file objects; the standard output file can be referenced as sys.stdout. See the Library Reference for more information on this.)

Genellikle, yalnızca boşlukla ayrılmış değerleri yazdırmaktansa, çıktınızın biçimlendirmesi üzerinde daha fazla denetim istersiniz. Çıktıyı biçimlendirmenin birkaç yolu vardır.

  • formatted string literals kullanmak için, açılış tırnak işaretinden veya üç tırnak işaretinden önce f veya F ile bir dize başlatın. Bu dizenin içinde, değişkenlere veya hazır bilgi değerlerine başvurabilen { ve } karakterleri arasında bir Python ifadesi yazabilirsiniz.

    >>> year = 2016
    >>> event = 'Referendum'
    >>> f'Results of the {year} {event}'
    'Results of the 2016 Referendum'
    
  • str.format() dize yöntemi daha manuel çaba gerektirir. Bir değişkenin değiştirileceği yeri işaretlemek için { ve } kullanmaya devam edersiniz ve ayrıntılı biçimlendirme yönergeleri sağlayabilirsiniz, ancak biçimlendirilecek bilgileri de sağlamanız gerekir.

    >>> yes_votes = 42_572_654
    >>> no_votes = 43_132_495
    >>> percentage = yes_votes / (yes_votes + no_votes)
    >>> '{:-9} YES votes  {:2.2%}'.format(yes_votes, percentage)
    ' 42572654 YES votes  49.67%'
    
  • Son olarak, hayal edebileceğiniz herhangi bir düzen oluşturmak için dize dilimleme ve birleştirme işlemlerini kullanarak tüm dize işlemeyi kendiniz yapabilirsiniz. Dize türü, dizeleri belirli bir sütun genişliğine doldurma için yararlı işlemler gerçekleştiren bazı yöntemlere sahiptir.

Daha güzel görünen bir çıktıya ihtiyacınız olmadığında, ancak hata ayıklama amacıyla bazı değişkenlerin hızlı bir şekilde görüntülenmesini istediğinizde, herhangi bir değeri repr() veya str() işlevleriyle bir dizeye dönüştürebilirsiniz.

str() işlevi açıkça okunabilir değerlerin gösterimlerini döndürmek için, repr() ise yorumlayıcı tarafından okunabilecek gösterimler oluşturmak içindir (veya eş değer bir sözdizimi yoksa SyntaxError ‘ı zorlar). İnsan tüketimi için belirli bir temsili olmayan nesneler için str(), repr() ile aynı değeri döndürür. Sayılar veya listeler ve sözlükler benzeri yapılar gibi birçok değer, her iki işlevi de kullanarak aynı gösterime sahiptir. Özellikle dizelerin iki farklı gösterimi vardır.

Bazı örnekler:

>>> s = 'Hello, world.'
>>> str(s)
'Hello, world.'
>>> repr(s)
"'Hello, world.'"
>>> str(1/7)
'0.14285714285714285'
>>> x = 10 * 3.25
>>> y = 200 * 200
>>> s = 'The value of x is ' + repr(x) + ', and y is ' + repr(y) + '...'
>>> print(s)
The value of x is 32.5, and y is 40000...
>>> # The repr() of a string adds string quotes and backslashes:
... hello = 'hello, world\n'
>>> hellos = repr(hello)
>>> print(hellos)
'hello, world\n'
>>> # The argument to repr() may be any Python object:
... repr((x, y, ('spam', 'eggs')))
"(32.5, 40000, ('spam', 'eggs'))"

string modülü bir Template sınıfını içerir; bu sınıf, $x gibi yer tutucuları kullanarak ve bunları bir sözlükten değerlerle değiştirerek, değerleri dizelerle değiştirmenin başka bir yolunu sunar, ancak biçimlendirme üzerinde çok daha az kontrol sağlar.

7.1.1. Biçimlendirilmiş Dize Değişmezleri

Formatted string literals (kısaltmak için f-string olarak da adlandırılır), dizenin önüne f veya F yazarak ve ifadeleri {expression} olarak yazarak Python ifadelerinin değerini bir dizenin içine eklemenize olanak tanır.

Opsiyonel biçim belirleyicisi ifadeyi izleyebilir. Bu, değerin nasıl biçimlendirileceğini daha fazla denetlemenizi sağlar. Aşağıdaki örnek pi sayısını ondalık sayıdan sonra üç basamağa yuvarlar:

>>> import math
>>> print(f'The value of pi is approximately {math.pi:.3f}.')
The value of pi is approximately 3.142.

':' öğesinin ardından bir tamsayı geçmek, bu alanın en az sayıda karakter genişliğinde olmasına neden olur. Bu, sütunların hizaya getirilmesi için yararlıdır.

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

Diğer değiştiriciler, değeri biçimlendirilmeden önce dönüştürmek için kullanılabilir. '!a' ascii(), '!s' str(), ve '!r' repr() uygular:

>>> animals = 'eels'
>>> print(f'My hovercraft is full of {animals}.')
My hovercraft is full of eels.
>>> print(f'My hovercraft is full of {animals!r}.')
My hovercraft is full of 'eels'.

= belirleyicisi, bir ifadeyi ifadenin metnine, eşittir işaretine ve ardından değerlendirilen ifadenin temsiline genişletmek için kullanılabilir:

>>> bugs = 'roaches'
>>> count = 13
>>> area = 'living room'
>>> print(f'Debugging {bugs=} {count=} {area=}')
Debugging bugs='roaches' count=13 area='living room'

= belirtici hakkında daha fazla bilgi için kendi kendini belgeleyen ifadeler konusuna bakın. Bu biçim belirtimleriyle ilgili bir referans için, Format Specification Mini-Language için başvuru kılavuzuna bakın.

7.1.2. String format() Metodu

str.format() metodunun temel kullanımı şöyle görünür:

>>> print('We are the {} who say "{}!"'.format('knights', 'Ni'))
We are the knights who say "Ni!"

İçlerindeki köşeli ayraçlar ve karakterler (format fields olarak adlandırılır) str.format() yöntemine geçirilen nesnelerle değiştirilir. Köşeli ayraçlardaki bir sayı, str.format() yöntemine geçirilen nesnenin konumuna başvurmak için kullanılabilir.

>>> print('{0} and {1}'.format('spam', 'eggs'))
spam and eggs
>>> print('{1} and {0}'.format('spam', 'eggs'))
eggs and spam

Anahtar sözcük argümanları str.format() yönteminde kullanılıyorsa, değerlerine argümanın adı kullanılarak başvurulmaktadır.

>>> print('This {food} is {adjective}.'.format(
...       food='spam', adjective='absolutely horrible'))
This spam is absolutely horrible.

Konumsal ve anahtar sözcük argümanları isteğe bağlı olarak birleştirilebilir:

>>> print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',
...                                                    other='Georg'))
The story of Bill, Manfred, and Georg.

Bölmek istemediğiniz gerçekten uzun biçimli bir dizeniz varsa, konuma göre değil de ada göre biçimlendirilecek değişkenlere başvurursanız iyi olur. Bu, sadece dict’i geçirerek ve tuşlara erişmek için '[]' köşeli ayraçları kullanarak yapılabilir.

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; '
...       'Dcab: {0[Dcab]:d}'.format(table))
Jack: 4098; Sjoerd: 4127; Dcab: 8637678

Bu, table sözlüğünü ** gösterimiyle anahtar kelime bağımsız değişkenleri olarak ileterek de yapılabilir.

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

Bu, özellikle tüm yerel değişkenleri içeren bir sözlük döndüren yerleşik işlev vars() ile birlikte yararlıdır.

Örnek olarak, aşağıdaki satırlar, tamsayıları ve bunların karelerini ve küplerini veren düzenli bir şekilde hizalanmış bir sütun kümesi oluşturur:

>>> for x in range(1, 11):
...     print('{0:2d} {1:3d} {2:4d}'.format(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

str.format() ile dize biçimlendirmeye tam bir genel bakış için bkz. Format String Syntax.

7.1.3. Manuel Dize Biçimlendirmesi

Manuel olarak biçimlendirilmiş aynı kare ve küp tablosu aşağıdadır:

>>> for x in range(1, 11):
...     print(repr(x).rjust(2), repr(x*x).rjust(3), end=' ')
...     # Note use of 'end' on previous line
...     print(repr(x*x*x).rjust(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

(Her sütun arasındaki tek boşluğun print() çalışma şekliyle ekli olduğunu unutmayın: her zaman argümanları arasına boşluk ekler.)

Dize nesnelerinin str.rjust() yöntemi, belirli bir genişlikteki bir alandaki dizeyi soldaki boşluklarla doldurmayı haklı hale getirir. Benzer yöntemler vardır str.ljust() ve str.center(). Bu yöntemler hiçbir şey yazmaz, yalnızca yeni bir dize döndürür. Giriş dizesi çok uzunsa, onu kesmezler, değiştirmeden döndürürler; bu, sütununuzu mahvedecektir, ancak bu genellikle bir değer hakkında yalan söylemek olan alternatiften daha iyidir. (Gerçekten kesilme istiyorsanız, x.ljust(n)[:n] gibi her zaman bir dilim işlemi ekleyebilirsiniz.)

Soldaki sayısal bir dizeyi sıfırlarla dolduran başka bir metot vardır: str.zfill(). Bu metot artı ve eksi işaretlerini anlar:

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

7.1.4. Eski dize biçimlendirmesi

% operatör (modulo) dize biçimlendirmesi için de kullanılabilir. 'string' % values göz önüne alındığında, string öğesindeki % örnekleri sıfır veya daha fazla values öğesiyle değiştirilir. Bu işlem genellikle dize enterpolasyonu olarak bilinir. Mesela:

>>> import math
>>> print('The value of pi is approximately %5.3f.' % math.pi)
The value of pi is approximately 3.142.

Daha fazla bilgiyi printf-style String Formatting bölümünde bulabilirsiniz.

7.2. Dosyaları Okuma ve Yazma

open() bir file object döndürür ve en yaygın olarak iki konum argümanı ve bir anahtar sözcük argümanı ile kullanılır: open(filename, mode, encoding=None)

>>> f = open('workfile', 'w', encoding="utf-8")

İlk parametre dosya adını içeren bir dizedir. İkinci parametre dosyanın nasıl kullanılacağını açıklayan birkaç karakter içeren başka bir dizedir. mode, dosya yalnızca okunacağı zaman 'r', yalnızca yazmak için 'w' olabilir (aynı ada sahip varolan bir dosya temizlenir) ve 'a' dosyayı ekleme için açar; dosyaya yazılan tüm veriler otomatik olarak sonuna eklenir. 'r+' dosyayı hem okumak hem de yazmak için açar. mode parametresi isteğe bağlıdır; verilmezse 'r' varsayılacaktır.

Normalde dosyalar text mode ‘unda açılır, yani belirli bir kodlamada (encoding) kodlanmış dizeleri dosyadan okur ve dosyaya yazarsınız. kodlama belirtilmezse, varsayılan değer platforma bağlıdır (bakınız open()). UTF-8 modern de-fakto standart olduğundan, farklı bir kodlama kullanmanız gerekmiyorsa encoding="utf-8" kullanmanız önerilir. Moda 'b' eklemek, dosyayı binary modunda açar. İkili mod verileri, bytes nesneleri olarak okunur ve yazılır. Dosyayı ikili modda açarken kodlama belirtemezsiniz.

Metin modunda, okurken varsayılan değer platforma özgü satır sonlarını (\n on Unix, \r\n on Windows) yalnızca \n olarak dönüştürmektir. Metin modunda yazarken, varsayılan değer \n oluşumlarını platforma özgü satır sonlarına geri dönüştürmektir. Dosya verilerinde yapılan bu sahne arkası değişikliği metin dosyaları için iyidir, ancak JPEG veya EXE dosyalarında bunun gibi ikili verileri bozacaktır. Bu tür dosyaları okurken ve yazarken ikili modu kullanmaya çok dikkat edin.

Dosya nesneleriyle uğraşırken with anahtar sözcüğünü kullanmak iyi bir uygulamadır. Avantajı, herhangi bir noktada bir hata oluşsa bile, paketi bittikten sonra dosyanın düzgün bir şekilde kapatılmasıdır. with kullanmak da eş değer try -finally blokları yazmaktançok daha kısadır:

>>> with open('workfile', encoding="utf-8") as f:
...     read_data = f.read()

>>> # We can check that the file has been automatically closed.
>>> f.closed
True

with anahtar sözcüğünü kullanmıyorsanız, dosyayı kapatmak ve kullandığı sistem kaynaklarını hemen boşaltmak için f.close() metodunu çağırmalısınız.

Uyarı

with anahtar sözcüğünü kullanmadan f.write() çağırmak veya f.close() çağırmak, program başarıyla çıksa bile f.write() parametrelerinin diske tamamen yazılmamasıyla sonuçlanabilir.

Bir dosya nesnesi kapatıldıktan sonra, bir with deyimiyle veya f.close() çağırarak dosya nesnesini kullanma girişimleri otomatik olarak başarısız olur.

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

7.2.1. Dosya Nesnelerinin Metotları

Bu bölümdeki örneklerin geri kalanı, f adlı bir dosya nesnesinin zaten oluşturulduğunu varsayar.

Bir dosyanın içeriğini okumak için, bir miktar veriyi okuyan ve dize (metin modunda) veya bayt nesnesi (ikili modda) olarak döndüren f.read(size) öğesini çağırın. size isteğe bağlı bir sayısal parametredir. size boş bırakıldığında veya negatif olduğunda, dosyanın tüm içeriği okunur ve döndürülür; dosya makinenizin belleğinden iki kat daha büyükse bu sizin sorununuzdur. Aksi takdirde, en fazla size karakterleri (metin modunda) veya size bayt (ikili modda) okunur ve döndürülür. Dosyanın sonuna ulaşıldıysa, f.read() boş bir dize ('') döndürür.

>>> f.read()
'This is the entire file.\n'
>>> f.read()
''

f.readline() dosyadan tek bir satır okur; dizenin sonunda bir newline karakteri (\n) bırakılır ve dosya yalnızca dosya yeni satırda bitmezse dosyanın son satırında atlanır. Bu, dönüş değerini netleştirir; f.readline() boş bir dize döndürürse, dosyanın sonuna ulaşılmış demektir, boş bir satır ise yalnızca tek bir yeni satır içeren bir dize olan '\n' ile temsil edilir.

>>> f.readline()
'This is the first line of the file.\n'
>>> f.readline()
'Second line of the file\n'
>>> f.readline()
''

Bir dosyadan satırları okumak için, dosya nesnesinin üzerinde döngü oluşturabilirsiniz. Bu bellek verimliliğine, hızlılığına ve basit koda yol açar:

>>> for line in f:
...     print(line, end='')
...
This is the first line of the file.
Second line of the file

Listedeki bir dosyanın tüm satırlarını okumak istiyorsanız, list(f) veya f.readlines() öğelerini de kullanabilirsiniz.

f.write(string) string içeriğini dosyaya yazar ve yazılan karakter sayısını döndürür.

>>> f.write('This is a test\n')
15

Diğer nesne türlerinin yazmadan önce bir dizeye (metin modunda) veya bayt nesnesine (ikili modda) dönüştürülmesi gerekir:

>>> value = ('the answer', 42)
>>> s = str(value)  # convert the tuple to string
>>> f.write(s)
18

f.tell() dosya nesnesinin dosyadaki geçerli konumunu ikili moddayken dosyanın başından itibaren bayt sayısı ve metin modundayken opak bir sayı olarak veren bir tamsayı döndürür.

Dosya nesnesinin konumunu değiştirmek için f.seek(offset, whence) kullanın. Konum, bir referans noktasına offset eklenerek hesaplanır; referans noktası whence parametresi tarafından seçilir. whence değeri dosyanın başından itibaren 0 ölçerken, 1 geçerli dosya konumunu, 2 ise başvuru noktası olarak dosyanın sonunu kullanır. whence atlanabilir ve başvuru noktası için dosyanın başlangıcını kullanarak 0 olarak varsayılabilir.

>>> f = open('workfile', 'rb+')
>>> f.write(b'0123456789abcdef')
16
>>> f.seek(5)      # Go to the 6th byte in the file
5
>>> f.read(1)
b'5'
>>> f.seek(-3, 2)  # Go to the 3rd byte before the end
13
>>> f.read(1)
b'd'

Metin dosyalarında (mod dizesinde b olmadan açılanlar), yalnızca dosyanın başına göre aramalara izin verilir (dosyanın sonuna seek(0, 2) ile arayan özel durum) ve tek geçerli offset değerleri f.tell() veya sıfırdan döndürülen değerlerdir. Başka herhangi bir offset değeri tanımsız davranış üretir.

File objects have some additional methods, such as isatty() and truncate() which are less frequently used; consult the Library Reference for a complete guide to file objects.

7.2.2. Yapılandırılmış verileri json ile kaydetme

Strings can easily be written to and read from a file. Numbers take a bit more effort, since the read() method only returns strings, which will have to be passed to a function like int(), which takes a string like '123' and returns its numeric value 123. When you want to save more complex data types like nested lists and dictionaries, parsing and serializing by hand becomes complicated.

Python, kullanıcıların karmaşık veri türlerini dosyalara kaydetmek için sürekli olarak kod yazmasını ve hata ayıklamasını sağlamak yerine, JSON (JavaScript Object Notation) adlı popüler veri değişim biçimini kullanmanıza olanak tanır. json adlı standart modül, Python veri hiyerarşilerini alabilir ve bunları dize temsillerine dönüştürebilir; bu işleme serializing adı verilir. Dize gösteriminden verilerin yeniden yapılandırılmasına deserializing denir. Serileştirme ve seri durumdan çıkarma arasında, nesneyi temsil eden dizi bir dosyada veya veride saklanmış olabilir veya bir ağ bağlantısı üzerinden uzaktaki bir makineye gönderilmiş olabilir.

Not

JSON biçimi, veri alışverişine izin vermek için modern uygulamalar tarafından yaygın olarak kullanılır. Birçok programcı zaten buna aşinadır, bu da onu birlikte çalışabilirlik için iyi bir seçim haline getirir.

x nesnesiniz varsa, JSON dize gösterimini basit bir kod satırıyla görüntüleyebilirsiniz:

>>> import json
>>> x = [1, 'simple', 'list']
>>> json.dumps(x)
'[1, "simple", "list"]'

dumps() işlevinin başka bir çeşidi, dump() adı verilen nesneyi bir text file (metin dosyası) olarak seri hale getirmektedir. Yani f bir text file nesnesi yazmak için açılmışsa, bunu yapabiliriz:

json.dump(x, f)

Nesnenin kodunu tekrar çözmek için, f okuma için açılmış bir binary file veya text file nesnesiyse:

x = json.load(f)

Not

JSON dosyaları UTF-8’de kodlanmalıdır. Hem okuma hem de yazma için JSON dosyasını text file olarak açarken encoding="utf-8" kullanın.

Bu basit seri hale getirme tekniği listeleri ve sözlükleri işleyebilir, ancak JSON’da rasgele sınıf örneklerini seri hale getirmek biraz daha fazla çaba gerektirir. json modülü için olan örnek bunun bir açıklamasını içerir.

Ayrıca bakınız

pickle - pickle modülü

JSON ifadesinin aksine, pickle, gelişigüzel olarak karmaşık Python nesnelerinin seri hale getirilmesine izin veren bir protokoldür. Bu nedenle, Python’a özgüdür ve diğer dillerde yazılmış uygulamalarla iletişim kurmak için kullanılamaz. Varsayılan olarak da güvensizdir: güvenilmeyen bir kaynaktan gelen pickle verilerinin dizilerinin seri halden çıkarılması, veriler yetenekli bir saldırgan tarafından hazırlanmışsa rasgele kod yürütebilir.