koddla

Yazılımcıları bilgi ile güçlendirir.

Fonksiyonlar – İşlevler

İşlevler, bir dizi belirli eylemi gerçekleştirmek için organize, yeniden kullanılabilir ve modüler kod parçaları sağlar. İşlevler kodlama işlemini basitleştirir, gereksiz mantığı önler ve kodun izlenmesini kolaylaştırır. Bu yazıda, Python’daki işlevlerin oluşturulması ve kullanımına bakacağız.

Basit fonksiyon tanımlama ve fonksiyon çağırma

Python daha önce gördüğümüz print(), input(), len() gibi birçok yerleşik fonksiyona sahiptir. Yerleşik işlevlerin yanı sıra, daha spesifik işler yapmak için kendi işlevlerinizi de oluşturabilirsiniz (bunlara kullanıcı tanımlı işlevler denir). 

Sözdizimi 

  • def function_name(arg1, … argN, *args, kw1, kw2=default, …, **kwargs)
  • lambda arg1, … argN, *args, kw1, kw2=default, …, **kwargs

Python’da def ifadesi

def ifadesi python’da bir fonksiyonn tanımlamanın en yaygın yoludur. Bu ifade, tek cümleli bileşik bir ifadedir

def fonksiyon_adi(parametere):
    ifade(ler)

fonksiyon_adi işlev tanımlayıcısı olarak bilinir. İşlev tanımı yürütülebilir bir deyim olduğundan, işlev adı daha sonra çağrılabilecek işlev nesnesine bağlanır.

parametre , işlev çağrıldığında bağımsız değişken olarak sağlanan değerleri gösteren isteğe bağlı bir listedir. Bir işlev, virgülle ayrılmış rasgele sayıda bağımsız değişkene sahip olabilir.

ifade(ler) – işlev gövdesi olarak da bilinir – işlev her çağrıldığında yürütülen, boş olmayan, bir deyim dizisidir. Bu, herhangi bir girintili blok‘ta olduğu gibi, bir işlev gövdesinin boş olamayacağı anlamına gelir.

Fonksiyon tanımlama

Aşağıda, amacı her çağrıldığında Hello yazdırmak olan basit bir fonksiyon tanımına bakalım:

def merhaba():
    print("Hello")

Bu kadar basit. Fonksiyon tanımlarken def fonksiyon_adi(): ifadesini kullanıyoruz. Burada : karakterine dikkat edin. Sonrasında alt satıra geçip girinti ekleyerek fonksiyon içerisinde yapmak istediğimiz işlevi yazıyoruz.

Fonksiyon çağırma

Şimdi tanımlanan fonksiyonu çağıralım: merhaba()

merhaba()
# Çıktı: Hello

Aşağıda tek bir bağımsız değişkeni alan ve işlev her çağrıldığında verilen değeri görüntüleyen bir işlev tanımının başka bir örneğine bakalım:

def merhaba2(deger):
    print(deger)

merhaba2() fonksiyonu bir bağımsız değişkenle çağrılmalıdır: 

merhaba2("Howdy")
# Çıktı: Howdy

Ayrıca bu bağımsız değişkene varsayılan bir değer de verebiliriz:

def merhaba2(deger="Howdy"):
    print(deger)

Böylece bir değer vermeden de işlevi çağırabilirsiniz:

merhaba()
# Çıktı: Howdy

İşlevlerden değer döndürme

İşlevler doğrudan kullanabileceğiniz bir değer döndürebilir.

def beslik():
    return 5

print(beslik())  # Döndürülen değeri yazdır
# Çıktı: 5

veya daha sonra kullanmak üzere değeri kaydedebilirsiniz:

num = beslik()
print(num)             # Kaydedilen döndürülen değeri bastır
# Çıktı: 5

veya herhangi bir işlem için döndürülen değer kullanılabilir:

print(beslik() + 10)
# Çıktı: 15

İşlevde return ile karşılaşılırsa, işlevden hemen çıkılır ve sonraki işlemler değerlendirilmez: 

def beslik():
    return 5
    print('Bu satır bastırılmaz. Hiçbir zaman.')

print(beslik())
# Çıktı: 5

Ayrıca birden fazla return değeri de verebilirsiniz (bir demet şeklinde): 

def iki_beslik():
    return 5, 5  # iki tane 5 döndürür

birinci, ikinci= iki_beslik()
print(birinci)
# Çıktı: 5
print(ikinci)
# Çıktı: 5

return ifadesi olmayan bir işlev örtülü olarak None döndürür. Benzer şekilde, return deyimi olan, ancak dönüş değeri veya değişken dönüşü olmayan bir işlev de None döndürür.

Argüman ile fonksiyon tanımı

Argümanlar fonksiyon isminden sonra gelen parantez içerisinde tanımlanır.

def divide(dividend, divisor):  # Fonksiyon ismi ve argümanları
    # Argümanlara fonksiyon içerisinde isimleri ile ulaşılabilir. 
    print(dividend / divisor)

Fonksiyon adı ve argüman listesi işlevin imzası olarak adlandırılır. İsimlendirilmiş her argüman, işlevin yerel bir değişkenidir.

İşlev çağrılırken argümanlar sırayla işlev çağrısında verilir.

divide(10, 2)
# Çıktı: 5

Ya da, herhangi bir sırayla çağrılırken argüman isimleri kullanılır:

divide(divisor=2, dividend=10)
# Çıktı: 5

Birden fazla argümanla işlev tanımlamak

Bir fonksiyon birçok argüman ile de tanımlanabilir. Buradaki tek kural; her argüman adının farklı olması ve isteğe bağlı argümanların isteğe bağlı olmayanlardan sonra olmasıdır:

def func(degisken1, degisken2, istege_bagli_degisken=10):
    return '{0} {1} {2}'.format(degisken1, degisken2, istege_bagli_degisken)

İşlev çağrılırken anahtar kelimeler isimsiz olarak verilebilir. Ancak bu durumda sıralama önemli olur:

print(func(1, 'a', 100))
# Çıktı: 1 a 100

print(func('abc', 14))
# abc 14 10

Argümanlar isimli ve isimsiz olarak da verilebilir. Bu durumda ismi olanlar olmayanlardan sonra gelmelidir, ancak isimli olanların sırası önemli değildir:

print(func('Koddla ', optionalvalue='hoşgeldiniz', value2='Pythona '))
# Out: Koddla Pythona hoşgeldiniz

Yinelemeler ve sözlük açma

Fonksiyonlar pozisyona bağlı (positional), isme bağlı (named), değişken pozisyonuna bağlı (variable positional), anahtar kelime argümanı (Keyword args (kwargs)) türlerinde argüman tanımlanmasına izin verir. Aşağıda bu türlerin nasıl kullanılacağına dair örnekelere bakalım:

def unpacking(a, b, c=45, d=60, *args, **kwargs):
    print(a, b, c, d, args, kwargs)

>>> unpacking(1, 2)
1 2 45 60 () {}
>>> unpacking(1, 2, 3, 4)
1 2 3 4 () {}
>>> unpacking(1, 2, c=3, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, c=3)
1 2 3 4 () {}
>>> pair = (3,)
>>> unpacking(1, 2, *pair, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, *pair)
1 2 3 4 () {}
>>> unpacking(1, 2, *pair, c=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c' 
#c için birden fazla değer verildi

>>> unpacking(1, 2, c=3, *pair)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
#c için birden fazla değer verildi

>>> args_list = [3]
>>> unpacking(1, 2, *args_list, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, *args_list)
1 2 3 4 () {}
>>> unpacking(1, 2, c=3, *args_list)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
#c için birden fazla değer verildi

>>> unpacking(1, 2, *args_list, c=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
#c için birden fazla değer verildi
>>> pair = (3, 4)
>>> unpacking(1, 2, *pair)
1 2 3 4 () {}
>>> unpacking(1, 2, 3, 4, *pair)
1 2 3 4 (3, 4) {}
>>> unpacking(1, 2, d=4, *pair)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
#d için birden fazla değer verildi

>>> unpacking(1, 2, *pair, d=4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
#d için birden fazla değer verildi
>>> args_list = [3, 4]
>>> unpacking(1, 2, *args_list)
1 2 3 4 () {}
>>> unpacking(1, 2, 3, 4, *args_list)
1 2 3 4 (3, 4) {}
>>> unpacking(1, 2, d=4, *args_list)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
#d için birden fazla değer verildi

>>> unpacking(1, 2, *args_list, d=4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
#d için birden fazla değer verildi
>>> arg_dict = {'c':3, 'd':4}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {}
>>> arg_dict = {'d':4, 'c':3}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {}
>>> arg_dict = {'c':3, 'd':4, 'yeni_parametre': 75}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {'yeni_parametre': 75}
>>> unpacking(1, 2, *pair, **arg_dict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
#d için birden fazla değer verildi

>>> unpacking(1, 2, 3, 4, **arg_dict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
#d için birden fazla değer verildi

# Pozisyona bağlı argümanlar diğer türlere göre daha önceliklidir. 
>>> unpacking(1, 2, **arg_dict, c=3)
1 2 3 4 () {'not_a_parameter': 75}
>>> unpacking(1, 2, 3, **arg_dict, c=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
#c için birden fazla değer verildi

Açıklamalar 

İşlevlerle yapabileceğiniz 5 temel şey:

Değişkenlere işlevler atayın:

def f():
  print(20)
y = f
y()
# Çıktı: 20

Fonksiyonlar içinde fonksiyonlar tanımlayın:

def f(a, b, y):
    def inner_add(a, b):      # inner_add f dışındaki diğer kod parçalarından gizlidir
        return a + b
    return inner_add(a, b)**y

İşlevler diğer işlevleri döndürebilir

def f(y):
    def nth_power(x):
        return x ** y
    return nth_power    # işlev döndürür

sayinin_karesi = f(2)         # sayının karesini döndüren fonksiyon
sayinin_kupu = f(3)           # sayının küpünü döndüren fonksiyon
sayinin_karesi(3)             # Çıktı: 9
sayinin_kubu(2)               # Çıktı: 8

İşlevler diğer işlevlere parametre olarak geçirilebilir:

def a(x, y):
    print(x, y)
def b(fun, str):        # b iki argümana sahip: bir fonksiyon ve bir dize
    fun('Hello', str)
b(a, 'Sophia')           # Çıktı: Hello Sophia

İç işlevlerin kendisini çevreleyen koda erişimi vardır

def dis_fonksiyon(name):
    def ic_fonksiyon():     # name değişkeni iç fonksiyonda da görülür
        return "Hello "+ name + "!"
    return ic_fonksiyon
greet = dis_fonksiyon("Sophia")
print(greet())            # Çıktı: Hello Sophia!

Fonksiyonda return ifadesi

Diğer birçok dilden farklı olarak, işlevin dönüş türünü açıkça bildirmeniz gerekmediğini fark etmişsinizdir. Python işlevleri, return anahtar kelimesi aracılığıyla herhangi bir türdeki değerleri döndürebilir. Bir fonksiyon herhangi bir türde sonuç döndürebilir: 

def farkli_turler(x):
    if x < 0:
        return "Hello!"
    else:
        return 0

print(farkli_turler(1))
print(farkli_turler(-1))

# Çıktı:
0
Hello!

Bu kod çağırıldığında doğru bir şekilde işlendiği sürece tamamen geçerli bir Python kodudur.

return deyimi olmadan yürütmenin sonuna ulaşan bir işlev her zaman şunu döndürür: None

Python’da pass ifadesi

def hicbir_sey_yapma():
    pass

print(hicbir_sey_yapma())
# Çıktı: None

Daha önce de belirtildiği gibi, bir işlev tanımı, bir işlev gövdesine, boş olmayan bir deyimler dizisine sahip olmalıdır. Bu nedenle pass ifadesi, null bir işlem olan işlev gövdesi olarak kullanılır – yürütüldüğü zaman hiçbir şey olmaz. Bu ifade, adı üzerinde, sadece atlar. Bir deyim sözdizimsel olarak gerekli olduğunda, ancak hiçbir kodun yürütülmesi gerekmediğinde yer tutucu olarak kullanışlıdır. 

Bir işlevi rasgele sayıda bağımsız değişkenle tanımlama

Konumsal argümanlar:

Rasgele sayıda bağımsız değişken alabilen bir fonksiyonun tanımlanması için bağımsız değişkenlerden birinin önüne * getirilir

def func(*args):
    # args verilen tüm parametreleri içeren bir tuple olacaktır
    for i in args:
        print(i)

func(1, 2, 3)  # 3 argüman ile çağrı
# Çıktı: 1
#      2
#      3

arg_list = [1, 2, 3]
func(*arg_list)  # Liste değerleri ile çağrı, * listeyi açar
# Çıktı: 1
#      2
#      3 

func()  # argümansız çağrı
# Çıktı yok

args için varsayılan bir değer sağlayamazsınız. Örneğin, func(*args=[1, 2, 3]) ifadesi bir sözdizimi hatası oluşturacaktır (hatta derlemez bile).

İşlevi çağırırken args için isim sağlayamazsınız, örneğin func(*args=[1, 2, 3]) bir TypeError oluşturur.

Ancak, bağımsız değişkenleriniz zaten bir dizide (veya başka bir döndürülebilir veri türünde) ise, işlevinizi şu şekilde çağırabilirsiniz:  func(*degerlerim)

Bu bağımsız değişkenlere (*args) index ile erişilebilir. Örneğin ilk bağımsız değişkeni args[0] ile çağırırız.

Anahtar bağımsız değişkenler 

Fonksiyon tanımında iki tane * içeren argüman oluşturarak istediğiniz sayıda bağımsız değişken alabilirsiniz:

def func(**kwargs):
    # kwargs anahtar ve değer çiftlerini içeren bir sözlük olacaktır
    for name, value in kwargs.items():
        print(name, value)

func(value1=1, value2=2, value3=3)   # 3 argüman
# Çıktı: value1 1
#        value2 2
#        value3 3

func()                               # argümansız
# Çıktı yok

my_dict = {'foo': 1, 'bar': 2}
func(**my_dict)                      # bir sözlük ile çağrı
# Çıktı: foo 1
#        bar 2

Bu argümanları isimleri olmadan sağlayamazsınız, örneğin func(1, 2, 3) bir TypeError oluşturur.

kwargs basit bir yerel python sözlüğüdür. Örneğin args['value1'], value1 bağımsız değişkeninin değerini verecektir. Tabiki böyle bir argüman olup olmadığını kontrol etmeniz gerekir. Aksi takdirde bir KeyError hatası oluşacaktır.

Uyarı – Konumasal/anahtar kelimelerin pozisyonu 

*args ve **kwargs’ı diğer isteğe bağlı ve gerekli argümanlarla da kullanabilirsiniz, ancak tanımın içindeki sıra önemlidir.

Konumsal/anahtar kelime bağımsız değişkenleri önce gelir (Gerekli bağımsız değişkenler).

Sonra keyfi argümanlar gelir: *arg (İsteğe bağlı)

Ardından, anahtar kelime argümanları gelir. (Gerekli).

Sonra keyfi anahtar kelime argümanları gelir. **kwargs (İsteğe bağlı)

#       |-konumsal-|-isteğe bağlı-|---anahtar-kelime--|-isteğe bağlı-|
def func(arg1, arg2=10 , *args, kwarg1, kwarg2=2, **kwargs):
     pass
  • arg1 verilmelidir, aksi takdirde bir TypeError oluşturulur. arg1 konumsal (func(10)) veya anahtar kelime argümanı (func(arg1=10)) olarak verilebilir. 
  • kwarg1 ayrıca verilmelidir, ancak yalnızca anahtar kelime-değer olarak sağlanabilir: func(kwarg1=10)
  • arg2 ve kwarg2 isteğe bağlıdır. Verilen değer değiştirilecekse, arg1 (konumsal veya anahtar kelime) ve kwarg1 (yalnızca anahtar kelime) için aynı kurallar uygulanır. 
  • *args ek konumsal parametreleri yakalar. Ancak, arg1 ve arg2 argümanlarının daha önce sağlanması gerektiğini unutmayın: func(1, 1, 1, 1)
  • **kwargs tüm ek anahtar kelime parametrelerini yakalar.
  • Python 3’te, sonraki tüm bağımsız değişkenlerin anahtar sözcük olarak belirtilmesi gerektiğini belirtmek için tek başına * kullanabilirsiniz. Örneğin, math.isclose işlevi Python 3.5 ve sonraki sürümlerinde def math.isclose (a, b, *, rel_tol=1e-09, abs_tol=0.0) ile tanımlanır; bu, ilk iki bağımsız değişkenin konumsal olarak sağlanabileceği, ancak isteğe bağlı üçüncü ve dördüncü parametrelerin yalnızca anahtar kelime bağımsız değişkenleri olarak sağlanabileceği anlamına gelir. 

Python 2.x anahtar sözcük parametrelerini desteklemez. Bu davranışa kwargs ile öykünülebilir: 

def func(arg1, arg2=10, **kwargs):
    try:
        kwarg1 = kwargs.pop("kwarg1")
    except KeyError:
        raise TypeError("missing required keyword-only argument: 'kwarg1'")

    kwarg2 = kwargs.pop("kwarg2", 2)
    # function body ...

Adlandırma hakkında not 

İsteğe bağlı konumsal argümanların args ve isteğe bağlı anahtar kelime argümanlarının kwargs olarak isimlendirilmesi bir kural olmamakla birlikte geleneksel olarak kullanılan isimlerdir. İstediğiniz herhangi bir adı kullanabilirsiniz. Ancak başkalarının ne yaptığınızı bilmesi için bu geleneği sizin de takip etmeniz yararlı olacaktır – hatta daha sonra kendiniz için bile yararlı olur.

Benzersizlik Hakkında Not 

Herhangi bir fonksiyon sıfır veya bir *args ve sıfır veya bir **kwargs ile tanımlanabilir ancak her birinden birden fazla verilerek tanımlanamaz. Ayrıca, *args son konumsal bağımsız değişken olmalı ve **kwargs son parametre olmalıdır. Her ikisinden birden fazlasını kullanmaya çalışmak bir Sözdizimi Hatası özel durumuna neden olur

İsteğe bağlı değişkenlerle işlev tanımlama

İsteğe bağlı bağımsız değişkenler, bağımsız değişken adına varsayılan bir değer atayarak (kullanılarak) tanımlanabilir:

def make(action='nothing'):
    return action

Bu işlev 3 farklı şekilde çağrılabilir:

make("fun")
# Çıktı: fun

make(action="sleep")
# Çıktı: sleep

# Parametre isteğe bağlı olduğu için verilmediğinde varsayılan değeri ile işlev çağırılır

make()   
# Çıktı: nothing

Not: Değiştirilebilir türler (list, dict, set, vb.) varsayılan özellik olarak verildiğinde dikkat edilmelidir. Varsayılan argümanın herhangi bir şekilde değiştirilmesi onu kalıcı olarak değiştirecektir.

İsteğe bağlı değiştirilebilir değişkenlerle işlev tanımlama

İsteğe bağlı bağımsız değişkenleri değiştirilebilir bir varsayılan türle kullanırken beklenmeyen davranışlar oluşabilir.

Sorun

Bu sorun, işlev değişkenlerinin, işlev çağrıldığında (diğer birçok dil gibi) oluşturulması yerine işlevin tanımlandığı noktada oluşturulması sebebiyle ortaya çıkar. Varsayılan değerler, işlev nesnesinin __defaults__ değişkeninin içinde depolanır.

def f(a, b=42, c=[]):
    pass

print(f.__defaults__)
# Çıktı: (42, [])

Değişmez türler için bu bir sorun değildir, çünkü değişkeni mutasyona uğratmanın bir yolu yoktur; ancak, orijinal değerler değiştirilmeden yeniden atanabilir. Bu nedenle, sonraki sürümlerin aynı varsayılan değere sahip olması garanti edilir. Ancak, değiştirilebilir bir tür için, özgün değer, çeşitli üye işlevlerine çağrılar yaparak mutasyona uğrayabilir. Bu nedenle, işleve yapılan ardışık çağrıların ilk varsayılan değere sahip olacağı garanti edilmez.

def append(elem, to=[]):
    to.append(elem)      # varsayılan to değişkenine append() uygulanması varsayılan değeri değiştirir
    return to

append(1)
# Çıktı: [1]

append(2)  # Listeye yeni bir öğe atar
# Çıktı: [1, 2]

append(3, [])  # Yeni bir liste oluşturmak beklenmedik bir sonuç doğurur
# Çıktı: [3]

# İşlevin tekrar çağırılması ilk listeye ekleme yapar
append(4)   
# Out: [1, 2, 4]

Not: PyCharm gibi bazı IDE’ler, değiştirilebilir bir tür varsayılan öznitelik olarak belirtildiğinde bir uyarı verir.

Çözüm 

Varsayılan değişkenin her zaman işlev tanımında belirttiğiniz değişken olduğundan emin olmak istiyorsanız, çözüm varsayılan değişkeninizi her zaman değişmez bir tür ile kullanmaktır.

Varsayılan olarak değiştirilebilir bir türe ihtiyaç duyulduğunda bunu başarmak için yaygın bir deyim, varsayılan değişken olarak None (değişmez) kullanmak ve ardından varsayılan değişken istenilen değere eşit olduğunda varsayılan değere bunu atamaktır. 

def append(elem, to=None):
    if to is None:
        to = []

    to.append(elem)
    return to

Argüman geçişi ve değişkenlik

İlk olarak biraz terminoloji:

  • bağımsız değişken – argüman (gerçek parametre): bir işleve geçirilen gerçek değişken;
  • parametre (formal parametre): bir işlevde kullanılan alıcı değişken.

Python’da, bağımsız değişkenler atama ile geçirilir (bağımsız değişkenlerin değer/referans/işaretçi ile geçirilebildiği diğer dillerin aksine).

Bir parametrenin değiştirilmesi bağımsız değişkeni değiştirir (bağımsız değişkenin türü değiştirilebilirse):

def foo(x):        # x parametre
    x[0] = 9       # Bu satır x ve y ile isimlendirilmiş listeleri değiştirir
    print(x)

y = [4, 5, 6]
foo(y)             # foo işlevini y argümanı ile çağıralım
# Çıktı: [9, 5, 6]   # x ile isimlendirilen liste değişti
print(y)           
# Çıktı: [9, 5, 6]   # x ile isimlendirilen liste de değişti

Parametrenin yeniden atanması, bağımsız değişkeni yeniden atamaz:

def foo(x):        # x parametre, foo(y) çağırıldığında y'yi x'e atarız
    x[0] = 9       # Bu x ve y ile isimlendirilmiş listeleri değiştirir
    x = [1, 2, 3]  # x şimdi başka bir listeyi tanımlıyor (y etkilenmiyor)
    x[2] = 8       # Bu satır x'i değiştirirken y'yi değiştirmez
  
y = [4, 5, 6]      # y arguman, x parameter
foo(y)             # "x = y" yazmışız gibi düşünün ve 1. satıra gidin
y
# Çıktı: [9, 5, 6]

Python’da, değişkenlere gerçekten değer atamıyoruz, bunun yerine değişkenleri (ad olarak kabul edilen) nesnelere bağlarız (yani atarız, ekleriz).

  • Değiştirilemeyenler: Tamsayılar, dizeler, demetler vb. Tüm işlemler birer kopya oluşturur.
  • Değiştirilebilirler: Listeler, sözlükler, setler vb. İşlemler mutasyona uğrayabilir veya uğramayabilir.
x = [3, 1, 9]
y = x
x.append(5)    # x ve y listelerinin ikisini de değiştirir, x ve y'nin ikisi de[3, 1, 9]'e bağlı
x.sort()       # x ve y listelerinin ikisini de değiştirir (yerinde sıralama)
x = x + [4]    # Listeleri değiştirmez (sadece x'in kopyasını oluşturur, y'yi değil)
z = x          # z, x'e eşit ([1, 3, 9, 4])
x += [6]       # x ve z listelerinin ikisini de değiştirir 
x = sorted(x)  # Listeyi değiştirmez (sadece x'in kopyasını oluşturur).
x
# Çıktı: [1, 3, 4, 5, 6, 9]
y
# Çıktı: [1, 3, 5, 9]
z
# Çıktı: [1, 3, 5, 9, 4, 6]

İsimlendirilmiş parametre kullanmaya zorlama

Fonksiyon tanımındaki ilk yıldız * sonrasında verilen tüm parametreler anahtar gerektirir.

def f(*a, b):
    pass

f(1, 2, 3)
# TypeError: f() missing 1 required keyword-only argument: 'b'
# anahtar gerektiren parametre verilmedi

Python3’te fonksiyon tanımına sadece yıldız ekleyerek sonraki parametrelerin hepsinin anahtar gerektirdiği belirtilebilir

def f(a, b, *, c):
    pass

f(1, 2, 3)
# TypeError: f() takes 2 positional arguments but 3 were given
f(1, 2, c=3)
# Hata yok

Özyinelemeli Fonksiyonlar

Özyinelemeli işlelvler kendi tanımında yine kendisini çağıran işlevlerdir. Örneğin, matematiksel fonksiyon olan faktöriyel için tanımlanan fonksiyon aşağıdaki gibi olabilir: (n) = n * (n-1) * (n-2) *… * 3 * 2 * 1

def factorial(n):
    #n integer olmalı
    if n == 0:
        return 1
    else:
        return n*factorial(n-1)

Beklendiği gibi çıktı:

factorial(0)
#Çıktı 1
factorial(1)
#Çıktı 1
factorial(2)
#Çıktı 2
factorial(3)
#Çıktı 6

Bu fonksiyonun tanımında kendini çağıran bir fonksiyon olduğunu unutmayın. Fonksiyon sona ulaştığında return n*factorial(n-1) nedeniyle kendini tekrar çağırır.

Bazı özyinelemeli işlevler lambda kullanılarak da uygulanabilir:

factorial = lambda n: 1 if n == 0 else n*factorial(n-1)

Bu programın çıktısı da yukarıdaki ile aynı olacaktır.

Özyineleme Limiti

Python uygulamasına bağlı olarak özyinelenme derinliğinde sınır bulunur. Sınıra ulaşıldığında, RuntimeError istisnası yükseltilir:

def yinele(derinlik):
  try:
    cursing(derinlik+ 1) # aslında, tekrar-yinele
  except RuntimeError as RE:
    print('{} kere yinelendi!'.format(derinlik))

yinele(0)
# Çıktı: 1083 kere yinelendi!

Özyineleme derinliğini sys.setrecursionlimit(limit) ile değiştirmek mümkündür. Şuanki limitin kaç olduğu ise sys.getrecursionlimit() ile görülebilir.

sys.setrecursionlimit(2000)
yinele(0)
# Out: 1997 kere yinelendi!

Python 3.5’ten itibaren, yükseltilen istisna RecursionError olmuştur. Bu istisna da RuntimeError‘ın bir türevidir.

İç içe fonksiyonlar

Pythondaki fonksiyonlar birinci dereceden nesnelerdir. Dolayısıyla herhangi bir kapsamda tanımlanabilirler:

def fibonacci(n):
    def step(a,b):
        return b, a+b
    a, b = 0, 1
    for i in range(n):
        a, b = step(a, b)
    return a

Fonksiyonlar herhangi bir nesne türü gibi atanabilirler veya parametre olarak verilebilirler:

def make_adder(n):
    def adder(x):
        return n + x
    return adder
add5 = make_adder(5)
add6 = make_adder(6)
add5(10)
#Çıktı: 15
add6(10)
#Çıktı: 16

def repeatedly_apply(func, n, x):
    for i in range(n):
        x = func(x)
    return x

repeatedly_apply(add5, 5, 1)
#Çıktı: 26

Python’da fonksiyon örnekleri

Verilen sayıları toplama fonksiyonu

Aşağıdaki sum fonksiyonu liste ile verilen sayıları toplar ve toplamı yazdırır:

def sum(values):  # values 'list' türünde
    result = 0
    for value in values:
        result += value
    print(result)

Kelime içerisindeki harfleri sayma

count_letters fonksiyonu argüman olarak verilen kelimedeki harfleri sayar ve döndürür:

def count_letters(word):
    return count_vowels(word) + count_consonants(word)

Bir yanıt yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Back to top