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

Şimdiye kadar iki değer yazma yolu ile karşılaştık: expression statements ve print() fonksiyonu. (Üçüncü bir yol, dosya nesnelerinin write() yöntemini kullanmaktır; standart çıktı dosyasına sys.stdout olarak başvurulabilir. Bu konuda daha fazla bilgi için Kütüphane Referansı’na bakın.)

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'.

For a reference on these format specifications, see the reference guide for the Format Specification Mini-Language.

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

This could also be done by passing the table as keyword arguments with the ‘**’ notation.

>>> 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.

As an example, the following lines produce a tidily-aligned set of columns giving integers and their squares and cubes:

>>> 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 kesmiyorlar, ancak değiştirmeden döndürün; 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() returns a file object, and is most commonly used with two positional arguments and one keyword argument: 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.

Normally, files are opened in text mode, that means, you read and write strings from and to the file, which are encoded in a specific encoding. If encoding is not specified, the default is platform dependent (see open()). Because UTF-8 is the modern de-facto standard, encoding="utf-8" is recommended unless you know that you need to use a different encoding. Appending a 'b' to the mode opens the file in binary mode. Binary mode data is read and written as bytes objects. You can not specify encoding when opening file in binary mode.

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.

Dosya nesnelerinin daha az kullanılan isatty() ve truncate() gibi bazı ek metotları vardır; dosya nesneleri için eksiksiz bir kılavuz için Kütüphane Referansı’na bakın.

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

Dizeler bir dosyaya kolayca yazılabilir ve dosyadan okunabilir. Sayılar biraz daha fazla çaba gerektirir, çünkü read() yöntemi yalnızca '123' gibi bir dize alan ve sayısal değeri 123’ü döndüren int() gibi bir işleve geçirilmesi gereken dizeleri döndürür. İç içe geçmiş listeler ve sözlükler gibi daha karmaşık veri türlerini kaydetmek istediğinizde, elle ayrıştırma ve seri hale getirmek karmaşık hale gelir.

Rather than having users constantly writing and debugging code to save complicated data types to files, Python allows you to use the popular data interchange format called JSON (JavaScript Object Notation). The standard module called json can take Python data hierarchies, and convert them to string representations; this process is called serializing. Reconstructing the data from the string representation is called deserializing. Between serializing and deserializing, the string representing the object may have been stored in a file or data, or sent over a network connection to some distant machine.

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)

To decode the object again, if f is a binary file or text file object which has been opened for reading:

x = json.load(f)

Not

JSON files must be encoded in UTF-8. Use encoding="utf-8" when opening JSON file as a text file for both of reading and writing.

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 bkz.

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.