← Ana Sayfaya Dön
📊 Profil 3 - Veri Analizi

EduBot 2.0 - Profil 3: Python ile Veri Bilimi (Gün 11–15)

Gün 11: Dosya İşlemleri (Okuma ve Yazma)

Python'da dosya işlemleri, programınızın kalıcı verilerle çalışmasını sağlar. Bilgisayarınızdaki metin dosyaları, CSV'ler veya JSON'lar gibi çeşitli dosyaları okuyabilir, içeriklerini değiştirebilir veya sıfırdan yeni dosyalar oluşturabilirsiniz. Bu, verileri saklamak, konfigürasyon ayarlarını yönetmek veya log tutmak gibi birçok senaryo için temel bir gereksinimdir. Python'un sunduğu basit ve etkili fonksiyonlar sayesinde bu işlemler oldukça kolaydır.

Dosya açmak için temel fonksiyon `open()`'dır. Bu fonksiyon iki ana parametre alır: dosyanın yolu (adı) ve açılış modu. En sık kullanılan modlar 'r' (read - okuma, varsayılan), 'w' (write - yazma, dosya varsa içeriğini siler), 'a' (append - ekleme, dosyanın sonuna ekler) ve 'x' (create - dosya yoksa oluşturur, varsa hata verir). Okuma modunda açılan bir dosyayı `read()` metoduyla tamamen, `readline()` ile satır satır veya `readlines()` ile tüm satırları bir liste olarak okuyabilirsiniz.

Yazma işlemleri de benzer şekilde basittir. 'w' veya 'a' modunda açılan bir dosyaya `write()` metodu ile string veriler yazabilirsiniz. Unutulmaması gereken önemli bir nokta, dosya ile işiniz bittiğinde onu `close()` metodu ile kapatmaktır. Bu, sistem kaynaklarının serbest bırakılması ve yazdığınız verilerin dosyaya tam olarak kaydedilmesi için kritiktir. Ancak, dosyayı kapatmayı unutma riskine karşı `with` ifadesi kullanmak en iyi pratiktir. `with open(...) as f:` bloğu bittiğinde dosya otomatik olarak kapatılır.

Örneğin, bir kullanıcıdan alınan metni bir dosyaya kaydetmek ve ardından o dosyayı okuyup ekrana yazdırmak yaygın bir kullanım senaryosudur. `with` bloğu, bu süreci hem daha güvenli hem de daha okunaklı hale getirir. `try...finally` bloklarıyla yapılabilecek bu işlemi basitleştirir ve kodun daha temiz kalmasını sağlar. Dosya modlarına ek olarak '+' karakteri ekleyerek (örneğin 'r+' veya 'w+') hem okuma hem de yazma işlemini aynı anda yapabilirsiniz.

# Kullanıcıdan bir metin alıp dosyaya yazma ve sonra okuma
metin = input("Lütfen dosyaya kaydetmek için bir metin girin: ")

# 'with' ifadesiyle dosyayı güvenli bir şekilde açıp yazıyoruz
with open('gun11_notlar.txt', 'w', encoding='utf-8') as f:
    f.write(metin)
print("\nMetin 'gun11_notlar.txt' dosyasına başarıyla yazıldı.")

print("\nŞimdi dosya içeriğini okuyoruz:")
# Dosyayı okuma modunda açıp içeriğini ekrana yazdırıyoruz
with open('gun11_notlar.txt', 'r', encoding='utf-8') as f:
    icerik = f.read()
    print("--- Dosya İçeriği ---")
    print(icerik)
    print("---------------------")
Lütfen dosyaya kaydetmek için bir metin girin: Python öğrenmek harika!

Metin 'gun11_notlar.txt' dosyasına başarıyla yazıldı.

Şimdi dosya içeriğini okuyoruz:
--- Dosya İçeriği ---
Python öğrenmek harika!
---------------------

1. Bir dosyayı, içeriğini silmeden sonuna veri eklemek için hangi modda açmalısınız?

Gün 12: Hata Yönetimi (Try, Except, Finally)

Programlama yaparken hatalarla karşılaşmak kaçınılmazdır. Python'da bu hatalar "istisna" (exception) olarak adlandırılır. Örneğin, var olmayan bir dosyayı okumaya çalışmak `FileNotFoundError`, bir sayıyı sıfıra bölmek `ZeroDivisionError` gibi istisnalara yol açar. Bu tür hatalar programın çökmesine neden olabilir. Hata yönetimi, bu istisnaları "yakalayarak" programın çökmesini engellemek ve bunun yerine kontrollü bir şekilde ne yapılacağını belirlemektir.

Python'da hata yönetimi için `try...except` bloğu kullanılır. Hata oluşma potansiyeli olan kodlar `try` bloğunun içine yazılır. Eğer `try` bloğu içinde bir istisna meydana gelirse, Python o bloğun geri kalanını atlar ve ilgili `except` bloğunu çalıştırmaya başlar. Hangi tür hatayı yakalamak istediğinizi `except` ifadesinden sonra belirtebilirsiniz. Örneğin, `except FileNotFoundError:` sadece dosya bulunamadı hatasını yakalar. Tüm hataları yakalamak için genel bir `except Exception:` kullanılabilir.

Bazen bir kod bloğunun, hata oluşsa da oluşmasa da çalışmasını istediğimiz durumlar olabilir. Örneğin, açılan bir dosyanın veya ağ bağlantısının her durumda kapatılması gerekir. Bu gibi durumlar için `finally` bloğu kullanılır. `try...except` yapısına eklenen `finally` bloğundaki kodlar, `try` bloğu başarıyla tamamlansa da, bir `except` bloğu çalışsa da her zaman en sonda çalıştırılır. Bu, kaynakların düzgün bir şekilde serbest bırakılmasını garanti altına alır.

İyi bir hata yönetimi, programları daha sağlam ve kullanıcı dostu yapar. Kullanıcıya "Program çöktü" demek yerine, "Girdiğiniz dosya bulunamadı, lütfen kontrol edin." gibi anlamlı bir mesaj göstermek çok daha profesyoneldir. Farklı hata türleri için birden fazla `except` bloğu tanımlayabilir ve her bir hata türü için farklı bir eylem gerçekleştirebilirsiniz. Bu, programınızın beklenmedik durumlara karşı daha dirençli olmasını sağlar.

# Sayısal bir değer girmesini beklediğimiz kod
try:
    yas_str = input("Lütfen yaşınızı girin: ")
    yas = int(yas_str)
    
    if yas < 0:
        raise ValueError("Yaş negatif olamaz!") # Kendi hatamızı fırlatabiliriz

    print(f"Harika! Yaşınız: {yas}")

except ValueError as e:
    # Hem int'e çevirme hatasını hem de kendi fırlattığımız hatayı yakalar
    print(f"❌ Hata: Geçersiz bir değer girdiniz. Lütfen sadece pozitif bir sayı girin. (Detay: {e})")

except Exception as e:
    # Beklenmedik diğer tüm hatalar için
    print(f"Beklenmedik bir hata oluştu: {e}")

finally:
    print("\nBu mesaj, hata olsa da olmasa da her zaman gösterilir.")

Lütfen yaşınızı girin: otuz
❌ Hata: Geçersiz bir değer girdiniz. Lütfen sadece pozitif bir sayı girin. (Detay: invalid literal for int() with base 10: 'otuz')

Bu mesaj, hata olsa da olmasa da her zaman gösterilir.

2. Hata olsa da olmasa da mutlaka çalışması gereken kod bloğu hangisidir?

Gün 13: Nesne Yönelimli Programlama (OOP) - Sınıflar ve Nesneler

Nesne Yönelimli Programlama (Object-Oriented Programming - OOP), programları "nesneler" etrafında organize eden bir programlama paradigmalarıdır. Bu nesneler, hem veri (nitelikler/attributes) hem de bu veriler üzerinde işlem yapan fonksiyonları (metotlar/methods) bir arada tutar. Gerçek dünyadaki varlıkları modellemek için harika bir yoldur. Örneğin, bir "Araba" nesnesi; renk, marka, hız gibi niteliklere ve hızlan(), yavaşla(), dur() gibi metotlara sahip olabilir.

Python'da bir nesnenin şablonunu veya kalıbını oluşturmak için `class` anahtar kelimesini kullanırız. Bu kalıba "sınıf" denir. Sınıf, o türdeki tüm nesnelerin sahip olacağı ortak nitelikleri ve metotları tanımlar. Örneğin, bir `Kopek` sınıfı tanımlayabilir ve bu sınıfın tüm köpekler için ortak olan `isim`, `cins` gibi niteliklere ve `havla()` gibi metotlara sahip olmasını sağlayabiliriz. Sınıf tanımı, bu şablonun nasıl görüneceğini belirler.

Bir sınıftan somut bir örnek oluşturduğumuzda buna "nesne" (object) veya "örnek" (instance) denir. `kangal = Kopek()` gibi bir kod, `Kopek` sınıfından `kangal` adında yeni bir nesne yaratır. Her nesne, sınıf tanımındaki niteliklerin kendi kopyasına sahiptir. Sınıflar içinde `__init__()` adında özel bir metot bulunur. Bu metot, bir nesne oluşturulduğunda otomatik olarak çağrılır ve genellikle nesnenin başlangıç niteliklerini ayarlamak için kullanılır. `self` parametresi, metotlar içinde o anki nesnenin kendisine referans verir.

OOP'nin en büyük avantajlarından biri kodun yeniden kullanılabilirliğini ve modülerliğini artırmasıdır. Bir kere iyi tasarlanmış bir sınıf, projenin farklı yerlerinde veya tamamen farklı projelerde tekrar tekrar kullanılabilir. Bu, karmaşık sistemleri daha küçük, yönetilebilir ve anlaşılır parçalara ayırmayı sağlar. Verileri ve o verilerle ilgili işlemleri tek bir pakette (nesnede) toplamak, kodun düzenini ve bakımını kolaylaştırır.

class Araba:
    # __init__ metodu, nesne oluşturulurken çağrılır.
    def __init__(self, marka, model, yil, renk):
        self.marka = marka
        self.model = model
        self.yil = yil
        self.renk = renk
        self.hiz = 0
        print(f"{self.yil} model {self.marka} {self.model} oluşturuldu.")

    # Nesnenin bir metodu
    def hizlan(self, deger):
        self.hiz += deger
        print(f"Hız {self.hiz} km/s'e yükseldi.")

    # Nesnenin başka bir metodu
    def bilgi_goster(self):
        return f"Marka: {self.marka}, Model: {self.model}, Renk: {self.renk}, Hız: {self.hiz} km/s"

# Araba sınıfından bir nesne (instance) oluşturalım
araba1 = Araba("Tesla", "Model Y", 2024, "Kırmızı")

# Nesnenin metotlarını çağıralım
araba1.hizlan(50)
araba1.hizlan(30)

# Nesnenin bilgilerini gösterelim
print(araba1.bilgi_goster())
2024 model Tesla Model Y oluşturuldu.
Hız 50 km/s'e yükseldi.
Hız 80 km/s'e yükseldi.
Marka: Tesla, Model: Model Y, Renk: Kırmızı, Hız: 80 km/s

3. Bir sınıftan nesne oluşturulduğunda otomatik olarak çalışan özel metodun adı nedir?

Gün 14: OOP - Kalıtım ve Çok Biçimlilik

Kalıtım (Inheritance), OOP'nin en güçlü konseptlerinden biridir. Bir sınıfın, başka bir sınıfın tüm niteliklerini ve metotlarını miras almasını sağlar. Miras veren sınıfa "temel sınıf" (base class) veya "üst sınıf" (parent class), miras alan sınıfa ise "türetilmiş sınıf" (derived class) veya "alt sınıf" (child class) denir. Bu sayede "bir ... bir ...'dır" ilişkisi kurulabilir. Örneğin, bir `Kedi` bir `Hayvan`dır. `Hayvan` sınıfındaki `beslen()` metodu, `Kedi` sınıfı tarafından doğrudan kullanılabilir.

Kalıtımın temel amacı kod tekrarını önlemek ve mantıksal bir hiyerarşi oluşturmaktır. Ortak özellikler temel sınıfta toplanır, alt sınıflar ise bu ortak özelliklere ek olarak kendilerine özgü nitelikler ve metotlar ekleyebilir veya üst sınıftan gelen metotları geçersiz kılabilir (override). Örneğin, `Hayvan` sınıfında genel bir `ses_cikar()` metodu olabilir, ancak `Kedi` sınıfı bu metodu "miyav" sesi çıkaracak şekilde, `Kopek` sınıfı ise "hav" sesi çıkaracak şekilde yeniden tanımlayabilir.

Çok biçimlilik (Polymorphism), kelime anlamı olarak "birçok şekle sahip olma" demektir. Programlamada ise, farklı nesnelerin aynı isimdeki bir metoda farklı şekillerde yanıt vermesi anlamına gelir. Yukarıdaki `ses_cikar()` örneği, çok biçimliliğin mükemmel bir örneğidir. Elimizde farklı hayvan nesnelerinden oluşan bir liste olsa bile, her bir nesne için `hayvan.ses_cikar()` metodunu çağırdığımızda, her hayvan kendi türüne özgü sesi çıkaracaktır. Bu, kodun esnekliğini ve genişletilebilirliğini artırır.

Python'da bir sınıfın başka bir sınıftan kalıtım alması için, sınıf tanımında parantez içinde üst sınıfın adı belirtilir: `class Kedi(Hayvan):`. Eğer alt sınıfın `__init__` metodunda üst sınıfın `__init__` metodunu da çağırmak istersek `super().__init__(...)` ifadesini kullanırız. Bu, üst sınıfın niteliklerinin de doğru bir şekilde başlatılmasını sağlar. Kalıtım ve çok biçimlilik, karmaşık ve hiyerarşik sistemleri zarif bir şekilde modellememize olanak tanır.

# Temel Sınıf (Parent Class)
class Hayvan:
    def __init__(self, isim):
        self.isim = isim
    
    def ses_cikar(self):
        print("Bilinmeyen bir hayvan sesi...")

# Türetilmiş Sınıf (Child Class)
class Kedi(Hayvan):
    def __init__(self, isim, tuy_rengi):
        super().__init__(isim) # Üst sınıfın init'ini çağır
        self.tuy_rengi = tuy_rengi

    # Üst sınıftaki metodu override etme (ezme)
    def ses_cikar(self):
        print(f"{self.isim}: Miyav!")

# Başka bir Türetilmiş Sınıf
class Kopek(Hayvan):
    # Bu sınıf kendi __init__'ine sahip değil, doğrudan Hayvan'ınkini kullanır.
    
    # Metodu override etme
    def ses_cikar(self):
        print(f"{self.isim}: Hav hav!")

# Nesneleri oluşturalım
hayvan_listesi = [Kedi("Tekir", "Sarı"), Kopek("Karabaş")]

# Çok biçimlilik (Polymorphism) örneği
print("Hayvanlar ses çıkarıyor:")
for hayvan in hayvan_listesi:
    hayvan.ses_cikar() # Aynı metot adı, farklı davranışlar
Hayvanlar ses çıkarıyor:
Tekir: Miyav!
Karabaş: Hav hav!

4. Bir alt sınıfın, üst sınıftan aldığı bir metodu yeniden tanımlaması işlemine ne ad verilir?

Gün 15: Modüller ve Python Standart Kütüphanesi

Python'un en güçlü yanlarından biri, zengin ve kapsamlı standart kütüphanesidir. Standart kütüphane, Python kurulumuyla birlikte gelen ve ek bir kurulum gerektirmeyen hazır modüller topluluğudur. "Modül", içinde Python tanımları ve ifadeleri bulunan bir dosyadır. Bu modülleri programlarımıza `import` anahtar kelimesiyle dahil ederek, içlerindeki fonksiyonları, sınıfları ve değişkenleri kullanabiliriz. Bu, tekerleği yeniden icat etmek yerine, başkaları tarafından yazılmış ve test edilmiş kodları kullanmamızı sağlar.

Örneğin, matematiksel işlemler için `math` modülü, rastgele sayılar üretmek için `random` modülü, tarih ve saat işlemleri için `datetime` modülü ve işletim sistemiyle etkileşim için `os` modülü gibi yüzlerce kullanışlı modül bulunur. `import math` yazdıktan sonra `math.sqrt(16)` gibi fonksiyonları çağırabiliriz. Veya `from datetime import datetime` diyerek sadece `datetime` sınıfını alıp `datetime.now()` ile şu anki zamanı öğrenebiliriz.

Kendi modüllerimizi oluşturmak da oldukça basittir. İçinde fonksiyonlar ve sınıflar olan herhangi bir `.py` uzantılı dosya, başka bir Python betiği tarafından modül olarak `import` edilebilir. Bu, büyük projeleri daha küçük, yönetilebilir ve mantıksal dosyalara bölmek için harika bir yoldur. Örneğin, tüm veritabanı işlemlerini `database.py` dosyasına koyup, ana programımızdan `import database` diyerek bu fonksiyonlara erişebiliriz. Bu, kod organizasyonunu ve yeniden kullanılabilirliği artırır.

Python'un standart kütüphanesi o kadar geniştir ki, genellikle ihtiyacınız olan birçok temel araç zaten mevcuttur. Web istekleri yapmak için `urllib` veya `http`, JSON verileriyle çalışmak için `json`, dosyaları sıkıştırmak için `zipfile` ve `gzip` gibi modüller hayat kurtarıcı olabilir. Programlamaya devam ederken, herhangi bir probleme çözüm aramadan önce "Acaba bunun için standart kütüphanede bir modül var mı?" diye sormak, zaman kazandıran iyi bir alışkanlıktır.

import random # Rastgele seçimler için modül
import datetime # Tarih ve saat işlemleri için modül
import math # Matematiksel fonksiyonlar için modül

# random modülü kullanımı
ogrenciler = ["Ali", "Veli", "Ayşe", "Fatma"]
gunun_sanslisi = random.choice(ogrenciler)
print(f"Günün şanslı öğrencisi: {gunun_sanslisi}")

# datetime modülü kullanımı
simdi = datetime.datetime.now()
print(f"Şu anki tarih ve saat: {simdi.strftime('%Y-%m-%d %H:%M:%S')}")

# math modülü kullanımı
sayi = 64
karekok = math.sqrt(sayi)
print(f"{sayi} sayısının karekökü: {karekok}")
Günün şanslı öğrencisi: Ayşe
Şu anki tarih ve saat: 2025-07-15 14:30:00
64 sayısının karekökü: 8.0

5. Rastgele bir sayı üretmek veya bir listeden rastgele bir eleman seçmek için hangi standart modül kullanılır?