Python ile Programlama ‘Günlük Uygulaması’ #4

Murat Kurtuluş
Three Arrows Security
6 min readAug 21, 2018

Merhaba sayın okurlarımız Python ile programlama yazı dizisinin dördüncü yazısına hoş geldiniz. Bu yazımızda basit bir günlük geliştireceğiz.
Günlük uygulamasını geliştirirken aşağıdaki konulara değineceğiz:

  • Çoklu dosyalar ile işlemler
  • Karmaşık koşullar
  • İşletim sistemi bağımsız yol(path) yönetimi
  • Dosya okuma/yazma işlemleri
  • __name__ niteliği
  • for-in döngüleri
  • docstring ile dökümantasyon

Geliştireceğimiz günlük uygulaması 3 ana işlevden oluşmaktadır. Günlüğe yeni girdiler ekleme, girdileri listeleme ve çıkış işlemi. Günlüğe girilen her bir girdi bir txt dosyasına kaydedilecek.

Programımızın kaynak kodlarını iki farklı dosyaya yazacağız. Bunun sebebi ise kodlarımızın taşınabilir, yeniden kullanılabilir olmasıdır. İlk dosyada 4 ana
fonksiyonu tanımlayacağız ve bu fonksiyonları main() fonksiyonu ile çağıracağız. Bu 4 ana fonksiyonun içine yazacağımız yardımcı fonksiyonları ise günlük.py adlı dosyaya kaydedeceğiz ve kendi modülümüzü oluşturacağız.

Gelin kodlarımızı incelemeye başlayalım. İlk olarak yardımcı fonksiyonları tanımladığımız günlük modülümüzü içeri aktarıyoruz. Bir modülün içinde fonksiyonlar, değişkenler, sınıflar tanımlanmış olabilir. Bu değerleri kullanmanın birden fazla yolu vardır.

import os
from os import name

>>> os.name # ilk yöntem ile kullanım
‘nt’
>>> name # ikinci yöntem ile kullanım
‘posix’

İlk içeri aktarma işleminde os modülünü içeri aktarırız. Bu standart içe aktarma yöntemidir. Bu şekilde bir modülü içeri aktardığımız zaman, modül adını kullanarak, o modülün içeriğine erişebiliriz. İkinci yöntemde ise bu modül içindeki bir nitelik olan name’i içeri aktarmış oluyoruz. Bu şekilde birkaç farklı nitelik ve fonksiyonu da içeri aktarabiliriz.

>>> from os import name, listdir, getcwd

Üçüncü yöntem ile modül içindeki bütün fonksiyon ve nitelikleri içe aktarmış oluruz.

>>> from os import *

Kodumuza main() fonksiyonunu tanımlayarak devam ediyoruz. main() fonksiyonunun içinde iki fonksiyonu çağırıyoruz. İlk olarak başlık_yazdır() fonksiyonu ve daha sonrasında olay_döngüsü() fonksiyonunu çağırıyoruz. başlık_yazdır() fonksiyonu şimdiye kadar geliştirdiğimiz bütün kodlarda vardı. Programımızın konsolda güzel bir çıktı vermesi için böyle bir fonksiyon tanımlıyoruz. Devamında ise olay_döngüsü() fonksiyonunu tanımlıyoruz.

Geliştirdiğimiz günlük uygulamasında gerçekleşen çoğu işlem olay_döngüsü() fonksiyonu altında tanımlıyoruz. İlk olarak kullanıcıya program ile hangi işlemi yapmak istiyor bunu soruyoruz. Daha sonrasında “komut” adında bir değişken tanımlıyoruz ve “BOŞ” değerini atıyoruz bunun sebebine birazdan değineceğim. günlük_adı isimli bir değişken daha tanımlıyoruz ve “varsayılan” değerini atıyoruz. günlük_verisi adında bir değişken daha tanımlıyoruz. Bu değişkene, içeri aktardığımız günlük modülünde tanımladığımız yükle(günlük_adı) fonksiyonundan gelen değeri atıyoruz. yükle() fonksiyonu ile önceden yazdığımız günlük verisini
döndürüyoruz.

Kullanıcının yapacağı işlem için konsoldan veri almamız gerekiyor ve bunu kullanıcı çıkış yapmak isteyene kadar sürekli yapmamız lazım. Bu işlem için while döngü yapısı uygundur. While döngü yapısının nasıl çalıştığını bir önceki yazımızda anlatmıştık. While deyiminin yanında yazdığımız koşul doğru(True) değerini verirse while kod bloğu çalışacaktır. While döngülerinin şöyle bir tehlikesi vardır. Döngüden çıkış şartı koymaz isek kodumuz sonsuz döngüye girebilir ve program hata verebilir. Bizim örneğimizde ilk olarak while döngüsünün çalışması için daha önceden tanımladığımız “komut” değişkeninin ‘ç’ olmaması ve değişkenin boş olmaması gerekmektedir. Bu iki koşul birden sağlanırsa while bloğu çalışır.

Şimdi kullanıcıdan girdi almak için komut değişkenine input() fonksiyonu ile kullanıcının girdiği değeri atıyoruz. Kullanıcı günlükteki girdileri listelemek için ‘L’, girdi eklemek için ‘E’ ve çıkış yapmak için ‘Ç’ harfi girmesi gerekmektedir. Kullanıcımız dikkatsiz olabilir ve büyük harf girmesi gerekirken küçük harf girebilir. Bu hataların önüne geçmek için bir takım işlemler yapmamız gerekiyor. İlk olarak girilen her karakteri lower() ile küçük harfe dönüştürüyoruz. Daha sonra strip() ile varsa boşluk karakterlerini siliyoruz. Bu işlemler sayesinde programımızda çıkabilecek bir takım hataların önüne geçebiliriz.

Kullanıcının girdisini işleme sokmak için if/elif bloğu yazıyoruz. Kullanıcı ‘l’ karakterini girerse girdileri_listele(günlük_verisi) fonksiyonu ile günlük
girdilerini listeliyoruz ve ekrana bastırıyoruz. Eğer kullanıcı ‘e’ karakterini girmiş ise girdi_ekle(günlük_verisi) fonksiyonu ile günlüğümüze yeni bir girdi
ekliyoruz. Son olarak kullanıcı ‘ç’ girmiş ise döngüden çıkıyoruz. Kullanıcı bu karakterlerin dışında bir şey girmiş ise ekrana girdiği karakteri bastırıyoruz.
While döngüsünden çıktığımızda ise günlük modülünde tanımladığımız kaydet(günlük_adı, günlük_verisi) fonksiyonu ile girdilerimizi günlüğe kaydediyoruz.

Kullanıcının daha önceden yazdığı günlük girdilerini ekrana bastırmak için girdileri_listele(veri) adında bir fonksiyon tanımlıyoruz. Programımızda son girilen girdi ilk gösterilmesi için reversed() fonksiyonunu kullanıyoruz ve ters döndürülmüş değeri girdiler değişkenine atıyoruz. Daha sonrasında ters sıralanmış girdileri tek tek ekrana bastırmak için for-in döngü yapısını kullanıyoruz.

eşyalar = [‘anahtar’, ‘şapka’, ‘klavye’]

for eşya in eşyalar:
print(‘Eşya: {}’.format(eşya))

for (indeks, eşya) in enumerate(eşyalar):
print(‘Eşya {}: {}’.format(indeks, eşya))

Python’da iki tip döngü yapısı vardır. Bunlardan birisi bu yazıda da bahsetmiş olduğum while döngü yapısıdır. Diğeri ise for-in döngü yapısıdır. For döngüsü
Python’da belki de en çok kullanılan döngü tipidir. Bunun sebebi çok kullanışlı olmasıdır. For döngüsü, listelerin, sözlüklerin, demetlerin, karakter dizilerinin üzerinde dolaşmamızı sağlayan bir döngü türüdür. enumerate() fonksiyonu ile öğeleri numaralandırabiliriz. Bizim örneğimizde her bir eşyayı sıfırdan başlayarak numaralandırırız. enumerate() fonksiyonu numaralandırmaya sıfırdan başlar. İstersek bunu değiştirebiliriz.

Bu dosyada son olarak tanımlayacağımız fonksiyon girdi_ekle(veri) fonksiyonudur. Bu fonksiyon ile kullanıcıya günlüğe yeni girdiler girme imkanını tanırız. Fonksiyon veri adında tek parametre alır. Bu parametre bizim günlüğümüzde bulunan girdilerin bulunduğu listeyi temsil eder. Günlük modülünde tanımladığımız girdi_ekle(metin, veri) fonksiyonu ile kullanıcının girdiği metini girdilerin tamamının bulunduğu listeye ekler.

Yardımcı fonksiyonları tanımladığımız günlük modülünü inceleyelim. Günlük modülüne belge dizisi(docstring) tanımlayarak başlıyoruz. Belge dizileri sayesinde bizim tanımladığımız fonksiyon, sınıf, modül gibi yapıların açıklamasını kodlarımızın içine yazabiliriz. Belge dizileri aracılığıyla kodu daha sonra kullanacak kişi için belgelendirme yapmış oluruz ve kodlarımızın okunurluğunu, yeniden kullanılabilirliğini artırabiliriz. Belge dizilerini üç çift tırnak arasına yazıyoruz.

Günlük modülünde dosya işlemleri yapacağımız için dosyanın yolunu(path) belirtmemiz gerekiyor. Dosya işlemleri işletim sistemleri arasında farklılık gösterir. Biz bu farklılıkların üstesinden kolayca gelmek için os modülünü kullanacağız. Günlük modülünde tanımlayacağımız ilk fonksiyon yükle(isim) fonksiyonudur. Bu fonksiyonda ilk olarak veri adında boş bir liste tanımlarız. Daha sonrasında girdilerimizi yazacağımız dosyanın yolunu dosya_adı değişkenine atarız. Bunun için tam_yol_adını_al(isim) adında bir fonksiyon tanımlıyoruz. İlk olarak yazacağımız dosyanın var olup olmadığını os.path.exists(dosya_adı) fonksiyonu ile kontrol ediyoruz. Eğer dosya var ise bu fonksiyon bize True değer döndürecektir ve if bloğu çalışacaktır.

Python’da dosya işlemleri için şöyle bir ifade kullanırız:

eşyalar = [‘anahtar’, ‘şapka’, ‘klavye’]

with open(‘deneme.txt’, ‘w’) as çıktı_dosyası:
for eşya in eşyalar:
çıktı_dosyası.write(eşya + ‘\n’)

Yukarıdaki ifade ilk olarak eşyalar adında bir liste tanımlar. Sonraki satırda bulunan ifade ile ‘deneme.txt’ adında bir dosyanın varlığını kontrol eder. ‘deneme.txt’ adında bir dosya var ise yazıyı bu dosyanın üzerine yazar. Dosya yok ise bu adda bir dosya oluşturur ve ‘w’ ifadesi ile dosyayı yazma kipinde açar. ‘as’ ifadesi ile bu deyimi çıktı_dosyası değişkenine atar. Sonrasında for döngüsü ile eşyalar listesindeki bulunan her bir elemanın write() fonksiyonu ile dosyaya yazar.

Bizim programımızda dosyayı girdi_dosyası adında açarız ve for döngüsü ile dosyanın her bir satırını readlines() fonksiyonu ile okuruz. Okuduğumuz bu girdileri biraz önce tanımladığımız veri adındaki listeye append() metotu ile ekleriz. Fonksiyonumuz son olarak bu listeyi return ifadesi ile döndürür.

Bir sonraki fonksiyonumuz kaydet(isim, günlük_verisi) adındaki fonksiyondur. Bu fonksiyon ilk parametre olarak günlük ismini alır. İkinci parametre olarak günlük_verisi alır. Girdilerimizin kayıt edileceği dosya ismini dosya_adı değişkenine tam_yol_adını_al() fonksiyonu ile atıyoruz. Sonrasında with open(dosya_adı, ‘w’) ifadesi ile dosyamızı yazma kipinde açarız. Sonrasında kullanıcının girdilerini her biri bir satıra yazılacak şekilde yazdırırız.

Günlüğümüzün kayıt edileceği dosyanın tam yolunu(path) belirleyebilmek için tam_yol_adını_al() fonksiyonunu tanımlıyoruz. Bu fonksiyonu tanımlarken os modülünden faydalanıyoruz. os.path.join(‘.’, ‘günlükler’, isim + ‘.txt’) ifadesi parametre olarak verdiğimiz değerlerden, ilgili işletim sistemine uygun yol adresi oluşturur. os.path.abspath(‘deneme.txt’) ifadesi ise parametre olarak verdiğimiz dosyanın tam yolunun ne olduğunu söyler. Bu değerleri dosya_adı değişkenine atamasını yapıyoruz ve return ifadesi ile döndürüyoruz.

Günlük modülünde tanımlayacağımız son fonksiyon girdi_ekle(metin, günlük_verisi) fonksiyonudur. Kullanıcının girdiği metini günlük_verisi adındaki listeye append() metotu ile ekler.

Yazdığımız bu kodları çalıştırabilmek için program.py dosyasında bulunan main() fonksiyonunu çağırmamız lazım. Bir önceki yazımızda yaptığımız gibi main() fonksiyonunu dosyanın en sonunda çağırarak uygulamamızı çalıştırabiliriz. Ama bu yöntem pek işlevsel değildir. Bu yöntem ile yazıdığımız kodları daha sonra kullanmamız zor olur. program.py dosyası da aslında bir modüldür. Biz burada tanımladığımız fonksiyonları daha sonra başka bir fonksiyonda kullanmak istediğimizde doğru bir şekilde çalışmayabilir. Bunun sebebi örneğin program.py modülünü aktardığımız dosyada kodları çalıştırırken aslında biz bütün program.py dosyasını çalıştırırız. Ama biz sadece bir fonksiyonu kullanmak istiyorduk. Bu hatanın önüne geçmek için aşağıdaki gibi bir ifade kullanabiliriz:

if __name__ == ‘__main__’:
main()

Buradaki __name__ niteliği iki farklı değer alabilir: İçinde bulunduğu modülün adı veya ‘__main__’ adı özel bir değer. Eğer bir Python programı başka bir program içinde modül olarak içeri aktarılıyorsa, __name__ niteliğinin değeri o modülün adı olacaktır. Eğer bir Python programı doğrudan bağımsız bir program olarak çalıştırılıyorsa, __name__ niteliğinin değeri bu defa ‘__main__’ olacaktır.

Bir yazının daha sonuna geldik. Umarım anlatabilmişimdir ve faydalı olmuştur. Okuduğunuz için teşekkürlerimi sunuyorum. İyi günler iyi çalışmalar dilerim.

--

--

Murat Kurtuluş
Three Arrows Security

İzmir Katip Çelebi Üniversitesi Elektrik elektronik mühendisliği 1.sınıf