Functions and recursion - Learn Python 3 - Snakify

Lesson 8
İşlevler ve özyineleme


1. Fonksiyonlar

Matematikte bir sayı n faktörünün n olarak tanımlandığını hatırlayın ! = 1 ⋅ 2 ⋅ ... ⋅ n (1'den n'ye kadar olan tamsayı sayılarının ürünü olarak). Örneğin, 5! = 1 ⋅ 2 ⋅ 3 ⋅ 4 ⋅ 5 = 120. Faktörlerin bir for döngüsü kullanarak hesaplanması kolay. Programımızda çeşitli sayıların faktörlerini (veya farklı kod yerlerinde) hesaplamak için ihtiyacımız olduğunu düşünün. Tabii ki, faktöriyel hesaplamayı bir kez yazabilir ve sonra istediğiniz yere eklemek için Copy-Paste’i kullanabilirsiniz:

# 3 hesapla!
res = 1
for i in range(1, 4):
    res *= i
print(res)

# 5 hesapla!
res = 1
for i in range(1, 6):
    res *= i
print(res)

Ancak, ilk kodda bir hata yaparsak, bu hatalı kod, faktöriyel hesaplamayı kopyaladığımız tüm yerlerde görünecektir. Dahası, kod olabileceğinden daha uzun. Programlama dillerinde aynı mantığın tekrar yazılmasını önlemek için fonksiyonlar vardır.

Fonksiyonlar , programın geri kalanından izole edilen ve sadece çağrıldığında çalıştırılan kod bölümleridir. sqrt() , len() ve print() işlevlerini zaten tanışmıştınız. Hepsinin ortak bir yönü vardır: parametreleri (sıfır, bir veya birkaç) alabilirler ve bir değer döndürebilirler (geri dönmeyebilirler). Örneğin, sqrt() işlevi bir parametreyi kabul eder ve bir değer (verilen sayının karekökü) döndürür. print() işlevi çeşitli sayıda argüman alabilir ve hiçbir şey döndüremez.

Şimdi size tek bir parametre alan (sayıyı döndüren ve bir değer döndüren factorial() diye adlandırılan bir fonksiyonun nasıl yazılacağını göstermek istiyoruz.

def factorial(n):
    res = 1
    for i in range(1, n + 1):
        res *= i
    return res

print(factorial(3))
print(factorial(5))

Birkaç açıklama yapmak istiyoruz. Öncelikle, fonksiyon kodu programın başlangıcına yerleştirilmelidir (fonksiyon factorial() kullanmak istediğimiz yerden önce factorial() , tam olarak). Bu örnekteki ilk satır def factorial(n): fonksiyonumuzun bir açıklamasıdır; factorial kelimesi bir tanımlayıcıdır (fonksiyonumuzun adı). Tanımlayıcıdan hemen sonra, fonksiyonumuzun aldığı parantezler listesi (parantez içinde). Liste, parametrelerin virgülle ayrılmış tanımlayıcılarından oluşur; bizim durumumuzda, liste, bir parametre oluşur n . Satırın sonunda, bir kolon yerleştirin.

Daha sonra işlev gövdesine gider. Python'da, gövde (her zaman olduğu gibi, Tab veya dört boşlukla) girintili olması gerekir. Bu fonksiyon n değerini hesaplar! ve değişken res saklar. Fonksiyonunun son hattıdır return res fonksiyonu çıkar ve değişken değerini verir ki, res .

return ifadesi, bir işlevin herhangi bir yerinde görünebilir. Yürütme işlevi çıkar ve işlevin çağrıldığı yere belirtilen değeri döndürür. İşlev bir değer döndürmezse, döndürme ifadesi aslında bir değer döndürmez (yine de kullanılabilir). Bazı işlevlerin değer döndürmesi gerekmez ve dönüş ifadesi onlar için ihmal edilebilir.

Başka bir örnek vermek istiyoruz. Burada, iki sayıyı kabul eden ve bunların maksimum değerini döndüren işlev max() (aslında, bu işlev zaten Python sözdiziminin parçası haline gelmiştir) işlevidir.

def max(a, b):
    if a > b:
        return a
    else:
        return b

print(max(3, 5))
print(max(5, 3))
print(max(int(input()), int(input())))

Şimdi, üç sayı alan ve bunların maksimumlarını döndüren bir max3() işlevi max3() .

def max(a, b):
    if a > b:
        return a
    else:
        return b

def max3(a, b, c):
    return max(max(a, b), c)

print(max3(3, 5, 4))

Python'daki yerleşik fonksiyon max() çeşitli sayıda argümanı kabul edebilir ve bunların maksimumlarını iade edebilir. İşte böyle bir fonksiyonun nasıl yazılabileceği bir örnektir.

def max(*a):
    res = a[0]
    for val in a[1:]:
        if val > res:
            res = val
    return res

print(max(3, 5, 4))
Bu işleve geçirilen herşey adlı tek başlığın içine parametreleri toplayacak a yıldız işareti ile belirtilir.
Advertising by Google, may be based on your interests

2. Yerel ve küresel değişkenler

İşlev içinde, dışında bir yerde bildirilen değişkenleri kullanabilirsiniz:

def f():
    print(a)

a = 1
f()

Burada değişken a 1 olarak ayarlanır ve fonksiyon olan f() diye ilan zaman fonksiyonu olmasına rağmen, bu değeri yazdırır f bu değişken başlatılmamış. Nedeni işlevi çağırarak sırasında olduğu f() (son dize) değişken a zaten bir değeri vardır. Bu yüzden f() fonksiyonu görüntüleyebilir.

Bu değişkenler (işlevin dışında bildirilen, ancak işlevin içinde mevcut olan) global olarak adlandırılır.

Ancak, işlevin içindeki bir değişkeni başlatırsanız, bu değişkeni bunun dışında kullanamazsınız. Örneğin:

def f():
    a = 1

f()
print(a)

NameError: name 'a' is not defined hatası alıyoruz NameError: name 'a' is not defined . Bir işlev içinde bildirilen bu değişkenler yerel olarak adlandırılır. İşlevden çıktıktan sonra kullanılamaz hale gelirler.

Burada gerçekten büyüleyici olan şey, bir fonksiyonun içinde global bir değişkenin değerini değiştirirseniz ne olur?

def f():
    a = 1
    print(a)

a = 0
f()
print(a)

Bu program değişkeninin değeri olmasına rağmen size numaralar 1 ve 0'a yazdırır a aynı kalır fonksiyonu dışında, işlevi içinde değişti! Bu, global değişkenlerin yanlışlıkla işlev değişikliklerinden korunması için yapılır. Yani, eğer bazı değişkenler fonksiyonun içinde değiştirilirse, değişken yerel bir değişken olur ve onun modifikasyonu aynı isimle bir global değişkeni değiştirmez.

Daha resmi olarak: Python yorumcusu, bu işlevin kodunda, değişkenin değerini değiştiren en az bir yönerge varsa, işlevin bir değişken yerel olduğunu düşünür. Daha sonra bu değişken başlangıçtan önce kullanılamaz. Bir değişkenin değerini değiştiren yönergeler - işleçler = , += ve değişkenin parametre for bir döngü olarak for . Bununla birlikte, değişken değişken deyimi hiçbir zaman yürütülmezse bile, yorumlayıcı bunu denetleyemez ve değişken hala yereldir. Bir örnek:

def f():
    print(a)
    if False:
        a = 0

a = 1
f()

Bir hata oluşur: UnboundLocalError: local variable 'a' referenced before assignment . Yani, fonksiyon f() tanımlayıcı a fonksiyonu değişken değiştirir komut içerdiğinden yerel değişken olur a . Değiştirme talimatı asla uygulanmayacaktır, ancak yorumlayıcı bunu kontrol etmeyecektir. Bu nedenle, a değişkenini yazdırmaya çalıştığınızda, başlatılmamış bir yerel değişkene başvurursunuz.

Bir değişkenin bir değişkeni değiştirebilmesini istiyorsanız, bu değişkeni global anahtar sözcüğünü kullanarak işlevin içinde bildirmelisiniz:

def f():
    global a
    a = 1
    print(a)

a = 0
f()
print(a)

Bu örnek 1 1 çıkışını basacaktır, çünkü a değişkeni global olarak beyan edilmiştir ve onu fonksiyonun içinde değiştirmek, global olarak değişmesine neden olur.

Bununla birlikte, bir fonksiyon içindeki global değişkenlerin değerlerini değiştirmemek daha iyidir. Eğer işlevin bir değişkeni değiştirmesi gerekiyorsa, bu değeri geri vermesine izin verin ve işlevi çağırırken bu değeri bir değişkene açıkça atamayı seçersiniz. Bu kuralları izlerseniz, fonksiyon mantığı kod mantığından bağımsız çalışır ve bu sayede bu tür fonksiyonlar bir programdan diğerine kolayca kopyalanabilir ve zamandan tasarruf edilebilir.

Örneğin, programınızın f değişkenine kaydetmek istediğiniz belirli sayıdaki faktörleri hesaplaması gerektiğini varsayalım. Bunu yapmamanız gerekenler :

def factorial(n):
    global f
    res = 1
    for i in range(2, n + 1):
        res *= i
    f = res

n = int(input())
factorial(n)
print(f)
# değişken f ile diğer şeyler yapmak

Bu, kötü kod örneğidir, çünkü başka bir zaman kullanmak zordur. Yarın "faktoriyel" fonksiyonunu kullanmak için başka bir programa ihtiyacınız varsa, bu işlevi buradan kopyalayıp yeni programınıza yapıştıramayacaksınız. Bu programın f değişkenini içermediğinden emin olmanız gerekir.

Bu örneği aşağıdaki gibi yeniden yazmak çok daha iyidir:

# programdan programa kopyalanabilen kodun başlangıcı
def factorial(n):
    res = 1
    for i in range(2, n + 1):
        res *= i
    return res
# kod parçasının sonu

n = int(input())
f = factorial(n)
print(f)
# değişken f ile diğer şeyler yapmak

İşlevlerin birden fazla değer döndürdüğünü söylemek yararlıdır. İşte iki veya daha fazla değerin bir listesini döndürme örneği:

return [a, b]

Bu listenin işlevini çağırabilir ve çoklu atamada kullanabilirsiniz:

n, m = f(a, b)
Advertising by Google, may be based on your interests

3. özyineleme

Yukarıda gördüğümüz gibi, bir işlev başka bir işlevi çağırabilir. Ancak işlevler de kendini çağırabilir! Bunu açıklamak için, faktörel hesaplama işlevinin örneğini düşünün. İyi bilinir ki 0! = 1, 1! = 1. N değeri nasıl hesaplanır? büyük n için? Eğer (n-1)! Değerini hesaplayabildiysek, o zaman n! 'Yi n! = N⋅ (n-1)! Ama nasıl hesaplanır (n-1) !? Eğer hesapladık (n-2)!, O zaman (n-1)! = (N-1) ⋅ (n-2) !. Nasıl hesaplanır (n-2) !? Eğer ... Eğer sonunda, 1'e eşit olan 0'a ulaşırız. Böylece, faktoriyeliği hesaplamak için daha küçük bir tam sayı için faktörel değerini kullanabiliriz. Bu hesaplama Python kullanılarak yapılabilir:

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

print(factorial(5))        

Fonksiyonun kendisini çağırdığı durum, özyineleme olarak adlandırılır ve bu işlev, özyineledir.

Yinelemeli fonksiyonlar programlamada güçlü bir mekanizmadır. Ne yazık ki, bunlar her zaman etkili değildir ve sıklıkla hatalara yol açar. En sık karşılaşılan hata sonsuz işlevdir, işlev çağrıları zinciri asla bitmez (aslında, bilgisayarınızda boş bellek bittiğinde sona erer). Sonsuz özyineleme örneği:

def f():
    return f()
Sonsuz yineleme neden en yaygın iki neden:
  1. Yanlış durma koşulu. Örneğin, faktör-hesaplama programına eğer onay koymak unutmayın if n == 0 , o zaman factorial(0) arayacak factorial(-1) arayacak, factorial(-2) , vs.
  2. Yanlış parametrelerle yinelenen çağrı. Fonksiyonu, örneğin, factorial(n) fonksiyonu çağıran factorial(n) , aynı zamanda aramaların sonsuz zincir elde edecektir.

Bu nedenle, özyinelemeli bir işlevi kodlarken, durma koşullarına nasıl ulaşacağından emin olmak gerekir - özyönlemenizin neden biteceğini düşünmek.

Advertising by Google, may be based on your interests