Fonksiyonlara giriş

İlk beş haftada programlarımız giderek büyüdü: değişkenler kullandık, koşullar kurduk ve döngüler yazdık. Kod büyüdükçe aynı işlemi tekrar tekrar yazmak, bir hatayı birden fazla yerde düzeltmek veya programın hangi parçasının hangi işi yaptığını anlamak zorlaşır.

Bu hafta fonksiyonları, bir problemi daha küçük ve adlandırılmış parçalara ayırmanın temel aracı olarak kullanacağız. Amaç yalnızca def sözdizimini öğrenmek değildir. Bir fonksiyonun hangi bilgiyi aldığı, hangi işi yaptığı ve hangi sonucu ürettiği üzerinde duracağız.

Bu hafta neleri yapabilmelisiniz?

Bölümün sonunda:

  • def ile basit bir fonksiyon tanımlayabilmeli ve çağırabilmeli,
  • fonksiyon tanımı ile fonksiyon çağrısını ayırt edebilmeli,
  • parametre ile argüman arasındaki farkı açıklayabilmeli,
  • bir fonksiyonun return ile değer üretmesini sağlayabilmeli,
  • print() ile ekrana yazdırmak ve return ile değer döndürmek arasındaki farkı açıklayabilmeli,
  • kısa bir problemi iki veya daha fazla fonksiyona ayırabilmeli,
  • bir fonksiyonun farklı argümanlarla nasıl davrandığını çalıştırmadan önce tahmin edebilmeli,
  • kısa bir fonksiyondaki eksik veya yanlış return kullanımını düzeltebilmelisiniz.

Fonksiyon neden kullanılır?

Bir dikdörtgenin alanını birkaç yerde hesapladığımızı düşünelim:

genislik1 = 4
yukseklik1 = 6
alan1 = genislik1 * yukseklik1

genislik2 = 8
yukseklik2 = 3
alan2 = genislik2 * yukseklik2

Aynı hesaplamayı tekrar etmek yerine ona bir ad verebiliriz:

def dikdortgen_alani(genislik, yukseklik):
    return genislik * yukseklik

Artık farklı değerlerle aynı işlemi çağırabiliriz:

alan1 = dikdortgen_alani(4, 6)
alan2 = dikdortgen_alani(8, 3)

print(alan1)
print(alan2)

Fonksiyon burada iki avantaj sağlar:

  • Hesabın ne yaptığına bir ad verir.
  • Aynı mantığı farklı verilerle yeniden kullanmamızı sağlar.
Tip

Bir kod parçasını fonksiyona dönüştürmek için yalnızca “bu kod tekrar ediyor mu?” diye sormayın. “Bu parçanın tek ve açık bir işi var mı?” sorusu da önemlidir.

Fonksiyon tanımı ve çağrısı

Bir fonksiyonun tanımı def ile başlar:

def selamla():
    print("Merhaba")

Bu kod fonksiyonu tanımlar, fakat henüz çalıştırmaz. Fonksiyonu çalıştırmak için çağırmamız gerekir:

selamla()

Aşağıdaki programın çıktısını çalıştırmadan önce tahmin edin:

Fonksiyon tanımı programın başında yer alsa da gövdesi yalnızca mesaj_yaz() çağrısı yapıldığında çalışır.

Parametre ve argüman

Fonksiyonun farklı verilerle çalışabilmesi için parametre kullanabiliriz:

def selamla(ad):
    print("Merhaba", ad)

Burada ad, fonksiyon tanımındaki parametredir.

Fonksiyonu şöyle çağırırsak:

selamla("Deniz")

"Deniz" değeri ise çağrı sırasında verilen argümandır.

Bu ayrımı şöyle düşünebilirsiniz:

Tanım:  def selamla(ad):
                     ↑
                 parametre

Çağrı: selamla("Deniz")
               ↑
            argüman

Bir fonksiyon birden fazla parametre alabilir:

def toplam_fiyat(birim_fiyat, adet):
    return birim_fiyat * adet
print(toplam_fiyat(25, 4))
print(toplam_fiyat(12.5, 3))

return: fonksiyonun ürettiği değer

Fonksiyon yalnızca ekrana bir şey yazdırmak zorunda değildir. Çoğu zaman asıl istediğimiz, hesaplanan değeri programın başka bir yerinde kullanmaktır.

def kare(sayi):
    return sayi * sayi

sonuc = kare(5)
print(sonuc)

return, fonksiyonun çağrıldığı yere bir değer gönderir.

Bir fonksiyonun tanımlanması, argümanlarla çağrılması ve hesaplanan değeri return ile döndürmesi arasındaki ilişki.

Aşağıdaki iki fonksiyon görünüşte benzer olsa da aynı işi yapmaz:

def yazdirarak_topla(a, b):
    print(a + b)

def dondurerek_topla(a, b):
    return a + b

Birincisi sonucu yalnızca ekrana yazar. İkincisinin sonucunu başka bir hesapta kullanabiliriz:

ara_toplam = dondurerek_topla(10, 20)
genel_toplam = ara_toplam + 5
print(genel_toplam)
Important

print() kullanıcıya çıktı gösterir. return ise fonksiyondan çağıran koda bir değer verir. Bunlar aynı şey değildir.

print() ile ekrana yazdırma ve return ile çağıran koda değer döndürme arasındaki fark.

Tahmin et — return sonrasında ne olur?

Aşağıdaki fonksiyonun çıktısını ve dönüş değerini düşünün:

return çalıştığında fonksiyon sona erer. Bu nedenle return satırından sonraki print() çağrısına ulaşılmaz.

Alıştırma — eksik dönüş değerini tamamlayın

Aşağıdaki fonksiyon iki sınavın basit ortalamasını hesaplamalıdır; ancak şu anda sonuç döndürmüyor.

Fonksiyonun 80.0 değerini döndürmesini sağlayın.

sonuc değişkeni zaten hesaplandı. Fonksiyonun sonuna return sonuc ekleyebilirsiniz.

def ortalama(not1, not2):
    sonuc = (not1 + not2) / 2
    return sonuc

print(ortalama(70, 90))

Fonksiyonun sonucunu başka bir ifadede kullanmak

Dönüş değeri normal bir değer gibi kullanılabilir:

def kdv_hesapla(tutar, oran):
    return tutar * oran

urun_tutari = 500
kdv = kdv_hesapla(urun_tutari, 0.20)
odenecek = urun_tutari + kdv

print(odenecek)

Fonksiyon çağrısı doğrudan bir ifadenin içinde de yer alabilir:

odenecek = urun_tutari + kdv_hesapla(urun_tutari, 0.20)

Başlangıç düzeyinde, ara değer anlamlıysa ayrı bir değişkende tutmak çoğu zaman kodu daha okunur yapar.

Alıştırma — alan fonksiyonunu yazın

Bir dikdörtgenin alanını hesaplayan dikdortgen_alani fonksiyonunu tamamlayın.

Beklenen sonuç 40tır.

Fonksiyonun dönüş değeri genislik * yukseklik olmalıdır.

def dikdortgen_alani(genislik, yukseklik):
    return genislik * yukseklik

print(dikdortgen_alani(8, 5))

Bir problemi küçük fonksiyonlara ayırmak

Fonksiyon kullanmanın asıl gücü yalnızca tekrar azaltmak değildir. Büyük bir problemi anlamlı alt problemlere ayırabiliriz.

Örneğin bir alışveriş tutarında indirim ve KDV hesabı yapalım:

def indirim_hesapla(tutar, oran):
    return tutar * oran

def kdv_hesapla(tutar, oran):
    return tutar * oran

urunler_toplami = 1000
indirim = indirim_hesapla(urunler_toplami, 0.10)
indirimli_tutar = urunler_toplami - indirim
kdv = kdv_hesapla(indirimli_tutar, 0.20)
odenecek = indirimli_tutar + kdv

print(odenecek)

Burada her fonksiyonun işi tek cümleyle açıklanabilir:

  • indirim_hesapla: verilen tutarın indirim miktarını bulur.
  • kdv_hesapla: verilen tutarın KDV miktarını bulur.

Bu yapı, hesaplamanın hangi adımında sorun olduğunu bulmayı da kolaylaştırır.

Yerel değişken fikri

Fonksiyon içinde oluşturulan bir değişken çoğunlukla o fonksiyonun kendi çalışma alanına aittir:

def cevre_hesapla(kenar):
    sonuc = kenar * 4
    return sonuc

Buradaki sonuc değişkenini fonksiyon dışındaki kodun doğrudan kullanmasına ihtiyaç yoktur. Fonksiyon dışına taşınması gereken bilgi return ile açıkça verilir.

Kapsam (scope) konusunun ayrıntılarını ileride ele alacağız. Şimdilik şu ilke yeterlidir:

Bir fonksiyonun iç hesabı, mümkün olduğunca fonksiyonun içinde kalmalı; dışarıya yalnızca ihtiyaç duyulan sonuç verilmelidir.

Değiştir — kargo hesabını fonksiyona dönüştürün

Aşağıdaki programda kargo ücreti doğrudan hesaplanıyor:

Bunu şu tasarıma dönüştürün:

def kargo_ucreti(sepet_tutari):
    ...

Fonksiyon:

  • 500 TL ve üzeri için 0,
  • daha düşük tutarlar için 39.90

döndürmelidir.

Üret — indirimli fiyat fonksiyonu

Bir ürünün fiyatını ve indirim oranını alan, indirim sonrası fiyatı döndüren bir fonksiyon yazın.

Başlangıç:

Beklenen sonuç 600.0dır.

Kabul kriterleri:

  • Fonksiyonun adı indirimli_fiyat olmalı.
  • İki parametre kullanılmalı.
  • İndirim miktarı fiyat * indirim_orani ilişkisiyle hesaplanmalı.
  • Sonuç return ile döndürülmeli.
  • Fonksiyon farklı fiyat ve oranlarla da çalışabilmeli.

Önce indirim = fiyat * indirim_orani hesaplanabilir. Sonra fiyat - indirim döndürülebilir.

def indirimli_fiyat(fiyat, indirim_orani):
    indirim = fiyat * indirim_orani
    return fiyat - indirim

print(indirimli_fiyat(800, 0.25))

Bölüm özeti

Bu hafta programı adlandırılmış ve yeniden kullanılabilir parçalara ayırmaya başladık.

  • Fonksiyon def ile tanımlanır, adı ve parantezleriyle çağrılır.
  • Parametre fonksiyon tanımındaki addır; argüman çağrıda verilen değerdir.
  • print() ekrana çıktı verir; return fonksiyonun sonucunu çağıran koda gönderir.
  • return çalıştığında fonksiyon sona erer.
  • Fonksiyonun dönüş değeri başka değişkenlerde ve ifadelerde kullanılabilir.
  • İyi bir başlangıç fonksiyonunun işi çoğu zaman tek cümleyle açıklanabilir.
  • Problemi küçük fonksiyonlara ayırmak kodu okumayı, test etmeyi ve hata ayıklamayı kolaylaştırır.

Kendinizi kontrol edin

  1. Fonksiyon tanımı ile fonksiyon çağrısı arasındaki fark nedir?
  2. def toplam(a, b): satırındaki a ve b nedir?
  3. toplam(4, 7) çağrısındaki 4 ve 7 nedir?
  4. print() ile return arasındaki temel fark nedir?
  5. Aşağıdaki kod ne yazdırır?
def iki_kat(x):
    return x * 2

a = iki_kat(3)
b = iki_kat(a)
print(b)
  1. Bir fonksiyon neden yalnızca tekrar eden kodu azaltmak için değil, problem parçalamak için de yararlıdır?

Bir sonraki bölümde fonksiyonları yalnızca “çalışıyor mu?” diye değil, hangi girdileri kabul etmeli, hangi sonucu üretmeli ve bunu nasıl doğrulamalıyız? sorularıyla tasarlayacağız.

Back to top