# 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 arguments: `open(filename, mode)`.

    >>> f = open('workfile', 'w')

İ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()`). `'b'` appended to the mode opens the file in binary mode: now the data is read and written in the form of bytes objects. This mode should be used for all files that don’t contain text.

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') 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
    >>> json.dumps([1, 'simple', 'list'])
    '[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 text file object which has been opened for reading:

    x = json.load(f)

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.