Python da Rastgele Sayıda İsimli Parametre Belirleme

Bir önceki başlık altında, fonksiyon tanımlarken rastgele sayıda isimsiz parametrelerin nasıl belirleneceğini tartıştık. Aynı bu şekilde, rastgele sayıda isimli parametre belirlemek de mümkündür.

Örneğin:

def fonksiyon(**parametreler):
    print(parametreler)

fonksiyon(isim="Ahmet", soyisim="Öz", meslek="Mühendis", şehir="Ankara")

Bu kodları çalıştırdığımızda şöyle bir çıktı alıyoruz:

{'şehir': 'Ankara', 'isim': 'Ahmet', 'soyisim': 'Öz', 'meslek': 'Mühendis'}

Gördüğünüz gibi, fonksiyonu tanımlarken parametremizin sol tarafına yerleştirdiğimiz ** işareti, bu fonksiyonu çağırırken yazdığımız isimli parametrelerin bize bir sözlük olarak verilmesini sağlıyor. Bu yapının bize bir sözlük verdiğini bildikten sonra, bunu sözlük veri tipinin kuralları çerçevesinde istediğimiz şekilde evirip çevirebiliriz.

Peki bu araç ne işimize yarar?

Hatırlarsanız bu bölümün en başında kayıt_oluştur() adlı şöyle bir fonksiyon tanımlamıştık:

def kayıt_oluştur(isim, soyisim, işsis, şehir):
    print("-"*30)

    print("isim           : ", isim)
    print("soyisim        : ", soyisim)
    print("işletim sistemi: ", işsis)
    print("şehir          : ", şehir)

    print("-"*30)

Bu fonksiyon bize toplam dört adet parametre kullanarak, isim, soyisim, işletim sistemi ve şehir bilgilerinden meydana gelen bir kayıt oluşturma imkanı sağlıyor. Bu fonksiyonda kullanıcının girebileceği bilgiler sınırlı. Ama bir de şöyle bir fonksiyon yazdığımızı düşünün:

def kayıt_oluştur(**bilgiler):
    print("-"*30)

    for anahtar, değer in bilgiler.items():
        print("{:<10}: {}".format(anahtar, değer))

    print("-"*30)

kayıt_oluştur(ad="Emre", soyad="AYdın", şehir="İstanbul", tel="05333213232")

Bu fonksiyonu çalıştırdığımızda şu çıktıyı alacağız:

tel       : 05333213232
ad        : Emre
şehir     : İstanbul
soyad     : AYDIN

Gördüğünüz gibi, ** işaretlerini kullanmamız sayesinde hem adlarını hem de değerlerini kendimiz belirlediğimiz bir kişi veritabanı oluşturma imkanı elde ediyoruz. Üstelik bu veritabanının, kişiye ait kaç farklı bilgi içereceğini de tamamen kendimiz belirleyebiliyoruz.

Tıpkı * işaretlerinin betimlediği parametrenin geleneksel olarak ‘args’ şeklinde adlandırılması gibi, ** işaretlerinin betimlediği parametre de geleneksel olarak ‘kwargs’ şeklinde adlandırılır. Dolayısıyla yukarıdaki gibi bir fonksiyonu Python programcıları şöyle tanımlar:

def kayıt_oluştur(**kwargs):
    ...

** işaretli parametreler pek çok farklı durumda işinize yarayabilir veya işinizi kolaylaştırabilir. Mesela * ve ** işaretlerini kullanarak şöyle bir program yazabilirsiniz:

def karşılık_bul(*args, **kwargs):
    for sözcük in args:
        if sözcük in kwargs:
            print("{} = {}".format(sözcük, kwargs[sözcük]))
        else:
            print("{} kelimesi sözlükte yok!".format(sözcük))

sözlük = {"kitap"      : "book",
          "bilgisayar" : "computer",
          "programlama": "programming"}

karşılık_bul("kitap", "bilgisayar", "programlama", "fonksiyon", **sözlük)

Burada tanımladığımız karşılık_bul() adlı fonksiyon, kendisine verilen parametreleri (*args), bir sözlük içinde arayarak (**sözlük) karşılıklarını bize çıktı olarak veriyor. Eğer verilen parametre sözlükte yoksa, ilgili kelimenin sözlükte bulunmadığı konusunda da bizi bilgilendiriyor.

karşılık_bul() adlı fonksiyonu nasıl tanımladığımıza çok dikkat edin. Parametre listesi içinde belirttiğimiz *args ifadesi sayesinde, fonksiyonu kullanacak kişiye, istediği sayıda isimsiz parametre girme imkanı tanıyoruz. **kwargs parametresi ise kullanıcıya istediği sayıda isimli parametre girme olanağı veriyor.

Esasında yukarıdaki kod *args ve **kwargs yapıları açısından ucuz bir örnektir. Bu yapılar için daha nitelikli bir örnek verelim…

Bildiğiniz gibi print() fonksiyonu sınırsız sayıda isimsiz parametre ve buna ek olarak birkaç tane de isimli parametre alıyor. Bu fonksiyonun alabildiği isimli parametrelerin sependfile ve flush adlı parametreler olduğunu biliyorsunuz. Yine bildiğiniz gibi, sep parametresi print() fonksiyonuna verilen isimsiz parametrelerin her birinin arasına hangi karakterin geleceğini; end parametresi ise bu parametrelerin en sonuna hangi karakterin geleceğini belirliyor. Bizim amacımız bu fonksiyona bir destart adında isimli bir parametre ekleyerek print() fonksiyonunun işlevini genişleten başka bir fonksiyon yazmak. Bu yeni parametre, karakter dizilerinin en başına hangi karakterin geleceğini belirleyecek.

Şimdi bu amacımızı gerçekleştirecek kodlarımızı yazalım:

def bas(*args, start='', **kwargs):
    for öğe in args:
        print(start+öğe, **kwargs)

bas('öğe1', 'öğe2', 'öğe3', start="#.")

print() fonksiyonunun işlevini genişleten yeni fonksiyonumuzun adı bas(). Bu fonksiyon her bakımdan print() fonksiyonu ile aynı işlevi görecek. Ancak bas() fonksiyonu, print() fonksiyonuna ek olarak, sahip olduğu start adlı bir isimli parametre sayesinde, kendisine verilen parametrelerin en başına istediğimiz herhangi bir karakteri eklemek olanağı da verecek bize.

bas() fonksiyonunun ilk parametresi olan *args sayesinde kullanıcıya istediği kadar parametre verme imkanı tanıyoruz. Daha sonra da ilave start parametresini tanımlıyoruz. Bu parametrenin öntanımlı değeri boş bir karakter dizisi. Yani eğer kullanıcı bu parametrenin değerine herhangi bir şey yazmazsa, *args kapsamında verilen parametreler üzerinde hiçbir değişiklik yapmıyoruz. Bunun ardından gelen **kwargs parametresi ise print() fonksiyonunun halihazırda sahip olduğu sepend,file ve flush parametrelerinin bas() fonksiyonunda da aynı şekilde kullanılmasını sağlıyor. **kwargs şeklinde bir tanımlama sayesinde, print() fonksiyonunun isimli parametrelerini tek tek belirtip tanımlamak zorunda kalmıyoruz:

def bas(*args, start='', **kwargs):
    for öğe in args:
        print(start+öğe, **kwargs)

f = open("te.txt", "w")

bas('öğe1', 'öğe2', 'öğe3', start="#.", end="", file=f)

Eğer elimizde **kwargs gibi bir imkan olmasaydı yukarıdaki fonksiyonu şu şekilde tanımlamamız gerekirdi:

import sys

def bas(*args, start='', sep=' ', end='n', file=sys.stdout, flush=False):
    for öğe in args:
        print(start+öğe, sep=sep, end=end, file=file, flush=flush)

Gördüğünüz gibi, print() fonksiyonunun bütün isimli parametrelerini ve bunların öntanımlı değerlerini tanımlamak zorunda kaldık. Eğer günün birinde Python geliştiricileri print() fonksiyonuna bir başka isimli parametre daha eklerse, yukarıdaki fonksiyonu ilgili yeniliğe göre elden geçirmemiz gerekir. Ama **kwargs yapısını kullandığımızda, print() fonksiyonuna Python geliştiricilerince eklenecek bütün parametreler bizim fonksiyonumuza da otomatik olarak yansıyacaktır..

Alıntıdır.