.. meta:: :description: Bu bölümde gömülü fonksiyonlar konusunu inceleyeceğiz. :keywords: python, fonksiyon, gömülü fonksiyon .. highlight:: py3 ************************ Gömülü Fonksiyonlar ************************ Bu bölümde, daha önce de birkaç kez bahsettiğimiz ve çokça örneğini gördüğümüz bir kavramdan söz edeceğiz. Bu kavramın adı 'gömülü fonksiyonlar'. Esasında biz buraya gelene kadar Python'da pek çok gömülü fonksiyon gördük. Dolayısıyla aslında görünüş olarak bunların neye benzediğini biliyoruz. Örneğin daha önceki derslerimizde gördüğümüz ``print()`` gömülü bir fonksiyondur. Aynı şekilde ``open()``, ``type()``, ``len()``, ``pow()``, ``bin()`` ve şimdiye kadar tanıştığımız öteki bütün fonksiyonlar birer gömülü fonksiyondur. Gömülü fonksiyonlar İngilizcede *builtin functions* olarak adlandırılır. Bu fonksiyonlar gerçekten de dile gömülü vaziyettedirler. Bildiğiniz gibi, bir fonksiyonu kullanabilmemiz için o fonksiyonu tanımlamamız gerekir. İşte gömülü fonksiyonlar, bizim tanımlamamıza gerek kalmadan, Python geliştiricileri tarafından önceden tanımlanıp dile gömülmüş ve hizmetimize sunulmuş faydalı birtakım araçlardır. İşte bu bölümde biz de bu gömülü fonksiyonları tek tek ve ayrıntılı olarak inceleyeceğiz. Dediğimiz gibi, bunlardan bir kısmını halihazırda görmüştünüz. Ama biz bütünlük açısından, önceden ele almış olduğumuz bu fonksiyonlara da kısaca değinmeden geçmeyeceğiz. Böylelikle hem yeni fonksiyonlar öğrenmiş olacağız hem de önceden öğrendiğimiz fonksiyonlarla birlikte yeni fonksiyonları da derli toplu bir şekilde görme imkanımız olacak. Bu bölümde elbette birtakım fonksiyonları salt art arda sıralamakla yetinmeyeceğiz. Python'daki gömülü fonksiyonları incelerken bir yandan da Python programlama dilindeki çok önemli bazı kavramları ele alacağız. İlk olarak ``abs()`` adlı bir fonksiyonla başlıyoruz gömülü fonksiyonları incelemeye... abs() ********** İngilizcede 'mutlak' anlamına gelen *absolute* adlı bir kelime bulunur. İşte bu fonksiyonun adı da bu kelimeden gelir. Fonksiyonumuzun görevi de isminin anlamına yakındır. ``abs()`` fonksiyonunu bir sayının mutlak değerini elde etmek için kullanıyoruz. Peki 'mutlak değer' ne anlama geliyor. Esasında siz bu kavrama matematik derslerinden aşinasınız. Ama bilmeyenler veya unutmuş olanlar için tekrar edelim. 'Mutlak değer' bir sayının `0`'a olan uzaklığıdır. Örneğin `20` sayısının `0` sayısına olan uzaklığı 20'dir. Dolayısıyla `20` sayısının mutlak değeri 20'dir. Aynı şekilde `-20` sayısının da `0` sayısına uzaklığı 20'dir. Yani, `-20` sayısının da mutlak değeri 20'dir. İşte ``abs()`` fonksiyonu bize bir sayının mutlak değerinin ne olduğunu söyler:: >>> abs(-20) 20 >>> abs(20) 20 >>> abs(20.0) 20.0 Mutlak değer kavramı yalnızca tamsayılar ve kayan noktalı sayılar için değil, aynı zamanda karmaşık sayılar için de geçerlidir. Dolayısıyla ``abs()`` fonksiyonunu kullanarak karmaşık sayıların da mutlak değerini hesaplayabiliriz:: >>> abs(20+3j) 20.223748416156685 Gördüğünüz gibi bu fonksiyon yalnızca tek bir parametre alıyor ve bu parametrenin mutlak değerini döndürüyor. round() ******** ``round()`` fonksiyonu bir sayıyı belli ölçütlere göre yukarı veya aşağı doğru yuvarlamamızı sağlar. Basit birkaç örnek verelim:: >>> round(12.4) 12 >>> round(12.7) 13 Gördüğünüz gibi bu fonksiyon, kayan noktalı sayıları en yakın tam sayıya doğru yuvarlıyor. Ancak burada dikkat etmemiz gereken bir nokta var. Şu örnekleri bir inceleyelim:: >>> round(1.5) 2 >>> round(12.5) 12 Gördüğünüz gibi, fonksiyonumuz `1.5` sayısını yukarı doğru, `12.5` sayısını ise aşağı doğru yuvarladı. Bunun sebebi, kayan noktalı bir sayının üst ve alt tam sayılara olan uzaklığının birbirine eşit olduğu durumlarda Python'ın çift sayıya doğru yuvarlama yapmayı tercih etmesidir. Mesela yukarıdaki örneklerde `1.5` sayısı hem `1` sayısına, hem de `2` sayısına eşit uzaklıkta bulunuyor. İşte Python bu durumda, bir çift sayı olan `2` sayısına doğru yuvarlamayı tercih edecektir. ``round()`` fonksiyonu toplam iki parametre alır. İlk parametre, yuvarlanacak sayının kendisidir. Yuvarlama hassasiyetini belirlemek için ise ikinci bir parametreden yararlanabiliriz. Örneğin `22` sayısını `7`'ye böldüğümüzde normalde şöyle bir çıktı elde ederiz:: >>> 22/7 3.142857142857143 ``round()`` fonksiyonunu tek parametre ile kullandığımızda bu fonksiyon yukarıdaki sayıyı şu şekilde yuvarlayacaktır:: >>> round(22/7) 3 İşte biz ``round()`` fonksiyonuna ikinci bir parametre daha vererek, yuvarlama hassasiyetini kontrol edebiliriz. Aşağıdaki örnekleri dikkatlice inceleyin:: >>> round(22/7) 3 >>> round(22/7, 0) 3.0 >>> round(22/7, 1) 3.1 >>> round(22/7, 2) 3.14 >>> round(22/7, 3) 3.143 >>> round(22/7, 4) 3.1429 Gördüğünüz gibi, ``round()`` fonksiyonuna verdiğimiz ikinci parametre, yuvarlama işleminin ne kadar hassas olacağını belirliyor. all() ********** *All* kelimesi Türkçede 'hepsi' anlamına gelir. Bu fonksiyonun görevi de bu anlamı çağrıştırır. ``all()`` fonksiyonunun görevi, bir dizi içinde bulunan bütün değerler `True` ise `True` değeri, eğer bu değerlerden herhangi biri `False` ise de `False` değeri döndürmektir. Örneğin elimizde şöyle bir liste olduğunu varsayalım:: >>> liste = [1, 2, 3, 4] Şimdi ``all()`` fonksiyonunu bu liste üzerine uygulayalım:: >>> all(liste) True Bildiğiniz gibi, `0` hariç bütün sayıların bool değeri `True`'dur. Yukarıdaki listede `False` değeri verebilecek herhangi bir değer bulunmadığından, ``all()`` fonksiyonu bu liste için `True` değerini veriyor. Bir de şuna bakalım:: >>> liste = [0, 1, 2, 3, 4] >>> all(liste) False Dediğimiz gibi, ``all()`` fonksiyonu ancak dizi içindeki bütün değerlerin bool değeri `True` ise `True` çıktısı verecektir. Son bir örnek daha verelim:: >>> liste = ['ahmet', 'mehmet', ''] >>> all(liste) False Listede `False` değerine sahip bir boş karakter dizisi bulunduğu için ``all()`` fonksiyonu `False` çıktısı veriyor. Bu fonksiyonu her türlü kodun bool değerlerini test etmek için kullanabilirsiniz. Mesela bu fonksiyonu kullanarak, bir nesnenin listelenen özelliklerin hepsine sahip olup olmadığını denetleyebilirsiniz:: >>> a = 3 >>> t1 = a == 3 #sayı 3 mü? >>> t2 = a < 4 #sayı 4'ten küçük mü? >>> t3 = a % 2 == 1 #sayı bir tek sayı mı? >>> all([t1, t2, t3]) #sayı bu özelliklerin hepsine sahip mi? True Eğer sayımız bu özelliklerin birine bile sahip değilse, ``all()`` fonksiyonu `False` çıktısı verecektir. any() ********** *Any* kelimesi İngilizcede 'herhangi bir' anlamına gelir. İşte ``any()`` fonksiyonunun görevi de, bir dizi içindeki bütün değerlerden en az biri `True` ise `True` çıktısı vermektir. Örneğin:: >>> liste = ['ahmet', 'mehmet', ''] >>> any(liste) True ``any()`` fonksiyonunun `True` çıktısı verebilmesi için listede yalnızca bir adet `True` değerli öğe olması yeterlidir. Bu fonksiyonun `False` çıktısı verebilmesi için dizi içindeki bütün öğelerin bool değerinin `False` olması gerekir:: >>> l = ['', 0, [], (), set(), dict()] >>> any(l) False İçi boş veri tiplerinin bool değerinin `False` olduğunu biliyorsunuz. Tıpkı ``all()`` fonksiyonunda olduğu gibi, ``any()`` fonksiyonunu da, bir grup nesnenin bool değerlerini denetlemek amacıyla kullanabilirsiniz. ascii() ********** Bu fonksiyon, bir nesnenin ekrana basılabilir halini verir bize. Dilerseniz bu fonksiyonun yaptığı işi tanımlamak yerine bunu bir örnek üzerinden anlatmaya çalışalım:: >>> a = 'istihza' >>> print(ascii(a)) 'istihza' Bu fonksiyonun, ``print()`` fonksiyonundan farklı olarak, çıktıya tırnak işaretlerini de eklediğine dikkat edin. ``ascii()`` fonksiyonunun tam olarak ne yaptığını daha iyi anlamak için herhalde şu örnek daha faydalı olacaktır. Dikkatlice bakın:: >>> print('\n') Bu komutu verdiğimizde, `\n` kaçış dizisinin etkisiyle yeni satıra geçileceğini biliyorsunuz. Bir de şuna bakın:: >>> print(ascii('\n!')) '\n' Gördüğünüz gibi, ``ascii()`` fonksiyonu, satır başı kaçış dizisinin görevini yapmasını sağlamak yerine bu kaçış dizisinin ekrana basılabilir halini veriyor bize. Ayrıca bu fonksiyon, karakter dizileri içindeki Türkçe karakterlerin de UNICODE temsillerini döndürür. Örneğin:: >>> a = 'ışık' >>> print(ascii(a)) '\u0131\u015f\u0131k' Bunu daha net şu şekilde görebiliriz:: >>> for i in a: ... print(ascii(i)) ... '\u0131' '\u015f' '\u0131' 'k' Gördüğünüz gibi, ``ascii()`` fonksiyonu ASCII olmayan karakterlerle karşılaştığında bunların karakter temsilleri yerine UNICODE temsillerini (veya onaltılık sayma düzenindeki karşılıklarını) veriyor. Son olarak şu örneğe bakalım:: >>> liste = ['elma', 'armut', 'erik'] >>> temsil = ascii(liste) >>> print(temsil) ['elma', 'armut', 'erik'] Burada listemiz ``ascii()`` fonksiyonuna parametre olarak verildikten sonra artık liste olma özelliğini yitirip bir karakter dizisi haline gelir. Bunu denetleyelim:: >>> print(type(temsil)) >>> temsil[0] '[' Gördüğünüz gibi, ``ascii()`` fonksiyonu listeyi alıp, bunu ekrana basılabilir bir bütün haline getiriyor. Elbette bunun için de, kendisine verilen parametreyi bir karakter dizisine dönüştürüyor. repr() ********** ``repr()`` fonksiyonunun yaptığı iş, biraz önce gördüğümüz ``ascii()`` fonksiyonunun yaptığı işe çok benzer. Bu iki fonksiyon, ASCII olmayan karakterlere muameleleri açısından birbirinden ayrılır. Hatırlarsanız ``ascii()`` fonksiyonu ASCII olmayan karakterlerle karşılaştığında bunların UNICODE (veya onaltılık) temsillerini gösteriyordu:: >>> ascii('şeker') "'\\u015feker'" ``repr()`` fonksiyonu ise ASCII olmayan karakterlerle karşılaşsa bile, bize çıktı olarak bunların da karakter karşılıklarını gösterir:: >>> repr('şeker') "'şeker'" Geri kalan özellikleri bakımından ``repr()`` ve ``ascii()`` fonksiyonları birbiriyle aynıdır. bool() ********** Bu fonksiyon bir nesnenin bool değerini verir:: >>> bool(0) False >>> bool(1) True >>> bool([]) False bin() ********** Bu fonksiyon, bir sayının ikili düzendeki karşılığını verir:: >>> bin(12) '0b1100' Bu fonksiyonun verdiği çıktının bir sayı değil, karakter dizisi olduğuna dikkat etmelisiniz. bytes() ********** Bu fonksiyon `bytes` türünde nesneler oluşturmak için kullanılır. Bu fonksiyonu 'bayt' adlı veri tipini incelerken ayrıntılı olarak ele almıştık. Gelin isterseniz burada da bu fonksiyona şöyle bir değinelim. Dediğimiz gibi, ``bytes()`` adlı fonksiyon, `bytes` türünde veriler oluşturmaya yarar. Bu fonksiyon işlev olarak, daha önce öğrendiğimiz ``list()``, ``str()``, ``int()``, ``set()``, ``dict()`` gibi fonksiyonlara çok benzer. Tıpkı bu fonksiyonlar gibi, ``bytes()`` fonksiyonunun görevi de farklı veri tiplerini 'bayt' adlı veri tipine dönüştürmektir. Bu fonksiyon, kendisine verilen parametrelerin türüne bağlı olarak birbirinden farklı sonuçlar ortaya çıkarır. Örneğin eğer bu fonksiyona parametre olarak bir tam sayı verecek olursanız, bu fonksiyon size o tam sayı miktarınca bir bayt nesnesi verecektir. Gelin isterseniz bu durumu örnekler üzerinde göstermeye çalışalım:: >>> bytes(10) b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' Yukarıdaki komut bize, her bir öğesinin değeri `0` olan 10 baytlık bir veri döndürdü:: >>> a = bytes(10) >>> a b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' >>> a[0] 0 >>> a[1] 0 >>> a[2] 0 Gördüğünüz gibi, ``bytes(10)`` komutuyla oluşturduğumuz `a` değişkeni içinde toplam 10 adet bayt var ve bu baytların her birinin değeri 0. Yukarıda, ``bytes()`` fonksiyonuna bir tam sayı değerli parametre verdiğimizde nasıl bir sonuç alacağımızı öğrendik. Peki biz bu fonksiyona parametre olarak bir karakter dizisi verirsek ne olur? Hemen görelim:: >>> bytes('istihza') Traceback (most recent call last): File "", line 1, in TypeError: string argument without an encoding Bu fonksiyona karakter dizilerini doğrudan parametre olarak veremeyiz. Eğer verirsek yukarıdaki gibi bir hata alırız. Peki acaba bu hatayı almamızın nedeni ne olabilir? Dediğimiz gibi, ``bytes()`` fonksiyonu, çeşitli veri tiplerini bayta dönüştürmeye yarar. Ancak bildiğiniz gibi, bayta dönüştürme işlemi her kod çözücü tarafından farklı biçimde yapılır. Örneğin:: >>> 'ışık'.encode('utf-8') b'\xc4\xb1\xc5\x9f\xc4\xb1k' >>> 'ışık'.encode('cp857') b'\x8d\x9f\x8dk' >>> 'ışık'.encode('cp1254') b'\xfd\xfe\xfdk' Dolayısıyla, ``bytes()`` fonksiyonunun bir karakter dizisini bayta çevirirken nasıl davranması gerektiğini anlayabilmesi için, bayta dönüştürme işlemini hangi kod çözücü ile yapmak istediğimizi açıkça belirtmemiz gerekir:: >>> bytes('ışık', 'utf-8') b'\xc4\xb1\xc5\x9f\xc4\xb1k' >>> bytes('ışık', 'cp1254') b'\xfd\xfe\xfdk' >>> bytes('ışık', 'cp857') b'\x8d\x9f\x8dk' Gördüğünüz gibi, ``bytes()`` fonksiyonuna parametre olarak bir karakter dizisi verebilmek için, bu karakter dizisi ile birlikte bir kod çözücü de belirtmemiz gerekiyor. Böylece ``bytes()`` fonksiyonu kendisine verdiğimiz karakter dizisini, belirttiğimiz kod çözücünün kurallarına göre bayta dönüştürüyor. Bu arada, çıktıda görünen 'b' harflerinin, elimizdeki verinin bir bayt olduğunu gösteren bir işaret olduğunu biliyorsunuz. Ayrıca, ``bytes()`` fonksiyonuna verdiğimiz ikinci parametrenin isminin `encoding` olduğunu ve bu parametreyi isimli bir parametre olarak da kullanabileceğimizi belirtelim:: >>> bytes('istihza', encoding='ascii') Bu noktada size şöyle bir soru sorayım: Acaba ``bytes()`` fonksiyonuna ilk parametre olarak verdiğimiz karakter dizisi, ikinci parametrede belirttiğimiz kod çözücü tarafından tanınmazsa ne olur? Cevabı tahmin edebilirsiniz: Böyle bir durumda elbette Python bize bir hata mesajı gösterir:: >>> bytes('şeker', 'ascii') Traceback (most recent call last): File "", line 1, in UnicodeEncodeError: 'ascii' codec can't encode character '\u015f' in position 0: ordinal not in range(128) ... veya:: >>> bytes('€', 'cp857') Traceback (most recent call last): File "", line 1, in File "C:\Python33\lib\encodings\cp857.py", line 12, in encode return codecs.charmap_encode(input,errors,encoding_map) UnicodeEncodeError: 'charmap' codec can't encode character '\u20ac' in position 0: character maps to 'ş' harfi 'ASCII' karakter kümesinde; '€' işareti ise 'CP857' adlı karakter kümesinde tanımlanmamış birer karakter olduğu için, ilgili kod çözücüler bu karakterleri çözüp bayta dönüştüremiyor. Yazdığımız kodların bu tür durumlarda tamamen çökmesini engellemek için, önceki derslerimizde de çeşitli vesilelerle öğrenmiş olduğumuz `errors` adlı bir parametreden yararlanabiliriz:: >>> bytes('ışık', encoding='ascii', errors='replace') b'???k' >>> bytes('şeker', encoding='ascii', errors='replace') b'?eker' >>> bytes('€', encoding='cp857', errors='replace') b'?' >>> bytes('€', encoding='cp857', errors='ignore') b'' >>> bytes('€', encoding='cp857', errors='xmlcharrefreplace') b'€' >>> bytes('şeker', encoding='cp857', errors='xmlcharrefreplace') b'\x9feker' Gördüğünüz gibi, `errors` parametresine verdiğimiz çeşitli değerler yardımıyla, ``bytes()`` fonksiyonunun, `encoding` parametresinde belirtilen kod çözücü ile çözülemeyen karakterlerle karşılaştığında nasıl davranacağını belirleyebiliyoruz. `errors` parametresine verdiğimiz bütün bu değerleri önceki derslerimizde öğrenmiştik. Dolayısıyla yukarıda gösterdiğimiz kodları rahatlıkla anlayabilecek kadar Python bilgisine sahibiz. Son olarak, ``bytes()`` fonksiyonuna parametre olarak 0-256 arası sayılardan oluşan diziler de verebiliriz:: >>> bytes([65, 10, 12, 11, 15, 66]) b'A\n\x0c\x0b\x0fB' Bu yapı içinde Python, `0` ile `128` arası sayılar için standart ASCII tablosunu, `128` ile `256` arası sayılar için ise Latin-1 karakter kümesini temel alarak sayıları birer bayta dönüştürecektir. bytearray() ************* Bildiğiniz gibi baytlar değiştirilemeyen bir veri tipidir. Dolayısıyla bir bayt veri tipi üzerinde herhangi bir değişiklik yapamayız. Örneğin bir baytın herhangi bir öğesini başka bir değerle değiştiremeyiz:: >>> a = bytes('istihza', 'ascii') >>> a[0] 105 >>> a[0] = 106 Traceback (most recent call last): File "", line 1, in TypeError: 'bytes' object does not support item assignment Ama eğer hem baytlarla çalışmak, hem de bu baytların üzerinde değişiklik yapabilmek isterseniz baytlar yerine bayt dizileri ile çalışabilirsiniz. İşte bunun için ``bytearray()`` adlı bir fonksiyondan yararlanıyoruz. Yaptıkları iş bakımından ``bytearray()`` ve ``bytes()`` fonksiyonları birbirlerine çok benzer. Bu ikisi arasındaki tek fark, ``bytearray()`` ile oluşturulan veri tipinin, ``bytes()`` ile oluşturulan veri tipinin aksine, değiştirilebilir nitelikte olmasıdır:: >>> a = bytearray('adana', 'ascii') >>> a bytearray(b'adana') >>> a[0] = 65 >>> a bytearray(b'Adana') chr() ********** Bu fonksiyon, kendisine parametre olarak verilen bir tam sayının karakter karşılığını döndürür. Örneğin:: >>> chr(10) '\n' Bildiğiniz gibi `10` sayısının karakter karşılığı satır başı karakteridir. Bir de şuna bakalım:: >>> chr(65) 'A' `65` sayısının karakter karşılığı ise 'A' harfidir. Bu fonksiyon sayıları karakterlere dönüştürürken ASCII sistemini değil, UNICODE sistemini temel alır. Dolayısıyla bu fonksiyon ile 128 (veya 255) üstü sayıları da dönüştürebiliriz. Örneğin:: >>> chr(305) 'ı' list() ********* Bu fonksiyon iki farklı amaç için kullanılabilir: #. Liste tipinde bir veri oluşturmak #. Farklı veri tiplerini liste adlı veri tipine dönüştürmek Birinci amaç için bu fonksiyonu şu şekilde kullanıyoruz:: >>> l = list() Böylece liste tipinde bir veri oluşturmuş olduk. Dediğimiz gibi ``list()`` fonksiyonunu, farklı tipteki verileri listeye dönüştürmek için de kullanabiliriz. Örneğin:: >>> list('istihza') ['i', 's', 't', 'i', 'h', 'z', 'a'] Burada `'istihza'` adlı karakter dizisini bir listeye dönüştürdük. Elbette bu fonksiyonu kullanarak başka veri tiplerini de listeye dönüştürebiliriz. Örneğin bir sözlüğü, bu fonksiyon yardımıyla kolayca listeye dönüştürebiliriz:: >>> s = {'elma': 44, 'armut': 10, 'erik': 100} >>> list(s) ['armut', 'erik', 'elma'] Bir sözlük listeye dönüştürülürken, elbette sözlüğün anahtarları dikkate alınacaktır. Eğer siz sözlüğün anahtarlarından değil de değerlerinde bir liste oluşturmak isterseniz şöyle bir kod yazabilirsiniz:: >>> list(s.values()) [10, 100, 44] set() ******* ``set()`` fonksiyonu ``list()`` fonksiyonuna çok benzer. Bu fonksiyon da tıpkı ``list()`` fonksiyonu gibi, veri tipleri arasında dönüştürme işlemleri gerçekleştirmek için kullanılabilir. ``set()`` fonksiyonunun görevi farklı veri tiplerini kümeye dönüştürmektir:: >>> k = set() Burada boş bir küme oluşturduk. Şimdi de mesela bir karakter dizisini kümeye dönüştürelim:: >>> i = 'istihza' >>> set(i) {'t', 's', 'z', 'a', 'i', 'h'} tuple() ********* ``tuple()`` fonksiyonu da, tıpkı ``list()``, ``set()`` ve benzerleri gibi bir dönüştürücü fonksiyondur. Bu fonksiyon farklı veri tiplerini demete dönüştürür:: >>> tuple('a') ('a',) frozenset() ************** Bu fonksiyonu kullanarak farklı veri tiplerini dondurulmuş kümeye dönüştürebilirsiniz:: >>> s = set('istihza') >>> df = frozenset(s) >>> df frozenset({'t', 's', 'a', 'z', 'i', 'h'}) complex() ********** Sayılardan söz ederken, eğer matematikle çok fazla içli dışlı değilseniz pek karşılaşmayacağınız, 'karmaşık sayı' adlı bir sayı türünden de bahsetmiştik. Karmaşık sayılar, bir gerçek, bir de sanal kısımdan oluşan sayılardır. Karmaşık sayılar Python’da 'complex' ifadesiyle gösteriliyor. Mesela şu bir karmaşık sayıdır:: >>> 12+0j İşte eğer herhangi bir sayıyı karmaşık sayıya dönüştürmeniz gerekirse ``complex()`` adlı bir fonksiyondan yararlanabilirsiniz. Örneğin:: >>> complex(15) (15+0j) Böyle bir kod yazdığımızda, verdiğimiz parametre karmaşık sayının gerçek kısmını oluşturacak, sanal kısım ise `0` olarak kabul edilecektir. Elbette isterseniz sanal kısmı kendiniz de belirleyebilirsiniz:: >>> complex(15, 2) (15+2j) float() ********* Bu fonksiyonu, sayıları veya karakter dizilerini kayan noktalı sayıya dönüştürmek için kullanıyoruz:: >>> float('134') 134.0 >>> float(12) 12.0 int() ****** Bu fonksiyon birkaç farklı amaç için kullanılabilir. ``int()`` fonksiyonunun en temel görevi, bir karakter dizisi veya kayan noktalı sayıyı (eğer mümkünse) tam sayıya dönüştürmektir:: >>> int('10') 10 >>> int(12.4) 12 Bunun dışında bu fonksiyonu, herhangi bir sayma sisteminde temsil edilen bir sayıyı onlu sayma sistemine dönüştürmek için de kullanabiliriz. Örneğin:: >>> int('12', 8) 10 Burada, sekizli sayma sistemine ait sayı değerli bir karakter dizisi olan `'12'`yi onlu sayma sistemine dönüştürdük ve böylece `10` sayısını elde ettik. ``int()`` fonksiyonunu sayma sistemleri arasında dönüştürme işlemlerinde kullanabilmek için ilk parametrenin bir karakter dizisi olması gerektiğine dikkat ediyoruz. Bu arada, ``int('12', 8)`` komutununun `12` sayısını sekizli sayma sistemine dönüştürmediğine dikkat edin. Bu komutun yaptığı iş sekizli sayma sistemindeki `12` sayısını onlu sayma sistemine dönüştürmektir. ``int()`` fonksiyonunun bu kullanımıyla ilgili bir örnek daha verelim:: >>> int('4cf', 16) 1231 Burada da, onaltılı sayma sistemine ait bir sayı olan `4cf`'yi onlu sayma sistemine çevirdik ve `1231` sayısını elde ettik. `4cf` sayısını ``int()`` fonksiyonuna parametre olarak verirken bunu karakter dizisi şeklinde yazmayı unutmuyoruz. Aksi halde Python bize bir hata mesajı gösterecektir. str() ******* Bu fonksiyonun, farklı veri tiplerini karakter dizisine dönüştürmek için kullanıldığını biliyorsunuz. Örneğin:: >>> str(12) '12' Burada `12` sayısını bir karakter dizisine dönüştürdük. Şimdi de bir baytı karakter dizisine dönüştürelim:: >>> bayt = b'istihza' Bayt nesnemizi tanımladık. Şimdi bunu bir karakter dizisine dönüştürelim:: >>> kardiz = str(bayt, encoding='utf-8') >>> print(kardiz) istihza Gördüğünüz gibi, bir baytı karakter dizisine dönüştürmek için ``str()`` fonksiyonuna `encoding` adlı bir parametre veriyoruz. Fonksiyonumuz, bu parametrede hangi kodlama biçimi belirtildiyse, baytları bu kodlama biçiminin kurallarına göre bir karakter dizisine dönüştürüyor. Tahmin edebileceğiniz gibi, belirttiğiniz kodlama biçiminin herhangi bir baytı karakter dizisine dönüştüremediği durumlara karşı bir `errors` parametresi de verebiliriz ``str()`` fonksiyonuna. Örneğin elimizde bayt tipinde şöyle bir veri olduğunu varsayalım:: >>> bayt = bytes('kadın', encoding='utf-8') >>> print(bayt) b'kad\xc4\xb1n' Şimdi bu bayt veri tipini bir karakter dizisine dönüştürmeye çalışalım:: >>> kardiz = str(bayt, encoding='ascii') Traceback (most recent call last): File "", line 1, in UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 3: ordinal not in range(128) ASCII adlı kod çözücü, ``b'kadın'`` içindeki baytlardan birini tanıyamadığı için bize bir hata mesajı gösterdi. Bildiğiniz gibi ASCII 128'den büyük baytları dönüştüremez. İşte bu tür durumlara karşı `errors` parametresinden yararlanabilirsiniz:: >>> kardiz = str(bayt, encoding='ascii', errors='ignore') >>> print(kardiz) kadn `errors` parametresine verdiğimiz 'ignore' değeri sayesinde Python bize hata mesajı göstermek yerine, ASCII ile çözülemeyen baytı görmezden geldi. `errors` parametresinin hangi değerleri alabileceğini önceki derslerimizden hatırlıyor olmalısınız. dict() ********** Bu fonksiyon, farklı veri tiplerinden sözlükler üretmemizi sağlar. Örneğin bu fonksiyonu kullanarak boş bir sözlük oluşturabiliriz:: >>> s = dict() Bu fonksiyon, değişkenlerden sözlükler oluşturmamızı da sağlar:: >>> s = dict(a=1, b=2, c=3) {'a': 1, 'b': 2, 'c': 3} ``dict()`` fonksiyonuna parametre olarak iç içe geçmiş listeler veya demetler vererek de sözlük üretebiliriz:: >>> öğeler = (['a', 1], ['b', 2], ['c', 3]) >>> dict(öğeler) {'a': 1, 'b': 2, 'c': 3} callable() ********** Bu fonksiyon, bir nesnenin 'çağrılabilir' olup olmadığını denetler. Peki hangi nesneler çağrılabilir özelliktedir. Mesela fonksiyonlar çağrılabilir nesnelerdir. Değişkenler ise çağrılabilir nesneler değildir. Birkaç örnek verelim bununla ilgili:: >>> callable(open) True Python'ın ``open()`` adlı bir fonksiyonu olduğu için, doğal olarak ``callable()`` fonksiyonu `True` çıktısı veriyor. Bir de şuna bakalım:: >>> import sys >>> callable(sys.version) False Burada da `sys` modülü içindeki `version` adlı nesnenin çağrılabilir özellikte olup olmadığını sorguladık. Daha önceki derslerimizde de gördüğünüz gibi, `sys` modülü içindeki `version` adlı araç bir fonksiyon değil, değişkendir. Dolayısıyla bu değişken ``callable(sys.version)`` sorgusuna `False` yanıtı verir. ord() ******* Bu fonksiyon, bir karakterin karşılık geldiği ondalık sayıyı verir. Örneğin:: >>> ord('a') 97 >>> ord('ı') 305 oct() ****** Bu fonksiyon, bir sayıyı sekizli düzendeki karşılığına çevirmemizi sağlar:: >>> oct(10) '0o12' hex() ******* Bu fonksiyon, bir sayıyı onaltılı düzendeki karşılığına çevirmemizi sağlar:: >>> hex(305) 'Ox131' Yalnız hem ``oct()`` hem de ``hex()`` fonksiyonlarında dikkat etmemiz gereken şey, bu fonksiyonların parametre olarak bir sayı alıp, çıktı olarak bir karakter dizisi veriyor olmasıdır. eval(), exec(), globals(), locals(), compile() ************************************************* Bu bölümde beş farklı fonksiyonu bir arada inceleyeceğiz. Bu fonksiyonları birlikte ele almamızın nedeni bunların birbiriyle yakından bağlantılı olması. Burada işleyeceğimiz bu beş fonksiyon şunlardan oluşuyor: #. ``eval()`` #. ``exec()`` #. ``globals()`` #. ``locals()`` #. ``compile()`` Ancak bu fonksiyonlardan söz etmeye başlamadan önce Python'daki iki önemli kavramı açıklığa kavuşturmamız gerekiyor: Bu kavramlar şunlar: #. ifade #. deyim Öncelikle 'ifade' kavramından başlayalım. İngilizcede *expression* denen 'ifadeler', bir değer üretmek için kullanılan kod parçalarıdır. Karakter dizileri, sayılar, işleçler, öteki veri tipleri, liste üreteçleri, sözlük üreteçleri, küme üreteçleri, fonksiyonlar hep birer ifadedir. Örneğin:: >>> 5 >>> 23 + 4 >>> [i for i in range(10)] >>> len([1, 2, 3]) İngilizcede *statement* olarak adlandırılan 'deyimler' ise ifadeleri de kapsayan daha geniş bir kavramdır. Buna göre bütün ifadeler aynı zamanda birer deyimdir. Daha doğrusu, ifadelerin bir araya gelmesi ile deyimler oluşturulabilir. Deyimlere birkaç örnek verelim:: >>> a = 5 >>> if a: ... print(a) >>> for i in range(10): ... print(i) Python programlama dilinde deyimlerle ifadeleri ayırt etmenin kolay bir yolu da ``eval()`` fonksiyonundan yararlanmaktır. Eğer deyim mi yoksa ifade mi olduğundan emin olamadığınız bir şeyi ``eval()`` fonksiyonuna parametre olarak verdiğinizde hata almıyorsanız o parametre bir ifadedir. Eğer hata alıyorsanız o parametre bir deyimdir. Çünkü ``eval()`` fonksiyonuna parametre olarak yalnızca ifadeler verilebilir. Birkaç örnek verelim:: >>> eval('a = 5') Traceback (most recent call last): File "", line 1, in File "", line 1 a = 5 ^ SyntaxError: invalid syntax Gördüğünüz gibi, ``eval()`` fonksiyonu bize bir hata mesajı verdi. Çünkü ``a = 5`` kodu bir deyimdir. Unutmayın, Python'da bütün değer atama işlemleri birer deyimdir. Dolayısıyla ``eval()`` fonksiyonu bu deyimi parametre olarak alamaz. Bir de şuna bakalım:: >>> eval('5 + 25') 30 Bu defa hata almadık. Çünkü ``eval()`` fonksiyonuna, olması gerektiği gibi, parametre olarak bir ifade verdik. Bildiğiniz gibi, ``5 + 25`` kodu bir ifadedir. Dediğimiz gibi, ``eval()`` fonksiyonu deyimleri parametre olarak alamaz. Ama ``exec()`` fonksiyonu alabilir:: >>> exec('a = 5') Bu şekilde, değeri `5` olan `a` adlı bir değişken oluşturmuş olduk. İsterseniz kontrol edelim:: >>> print(a) 5 Gördüğünüz gibi, ``exec()`` fonksiyonu, mevcut isim alanı içinde `a` adlı bir değişken oluşturdu. Yalnız elbette mevcut isim alanı içinde yeni değişkenler ve yeni değerler oluştururken dikkatli olmamız gerektiğini biliyorsunuz. Zira mesela yukarıdaki komutu vermeden önce mevcut isim alanında zaten `a` adlı bir değişken varsa, o değişkenin değeri değişecektir:: >>> a = 20 Elimizde, değeri `20` olan `a` adlı bir değişken var. Şimdi ``exec()`` fonksiyonu yardımıyla `a` değişkeninin de içinde yer aldığı mevcut isim alanına müdahale ediyoruz:: >>> exec('a = 10') Böylece `a` değişkeninin eski değerini silmiş olduk. Kontrol edelim:: >>> print(a) 10 Bu tür durumlarda, ``exec()`` ile oluşturduğunuz değişkenleri global isim alanına değil de, farklı bir isim alanına göndermeyi tercih edebilirsiniz. Peki ama bunu nasıl yapacağız? Python programlama dilinde isim alanları sözlük tipinde bir veridir. Örneğin global isim alanı basit bir sözlükten ibarettir. Global isim alanını gösteren sözlükte hangi anahtar ve değerlerin olduğunu görmek için ``globals()`` adlı bir fonksiyonu kullanabilirsiniz:: >>> globals() Bu fonksiyonu çalıştırdığımızda şuna benzer bir çıktı alırız:: {'__doc__': None, '__loader__': , '__name__': '__main__', '__package__': None, '__builtins__': } Gördüğünüz gibi, elimizdeki şey gerçekten de bir sözlük. Dolayısıyla bir sözlük ile ne yapabilirsek bu sözlükle de aynı şeyi yapabiliriz... 'globals' adlı bu sözlüğün içeriği, o anda global isim alanında bulunan nesnelere göre farklılık gösterecektir. Örneğin:: >>> x = 10 şeklinde `10` değerine sahip bir `x` nesnesi tanımladıktan sonra ``globals()`` fonksiyonunu tekrar çalıştırırsanız global isim alanına bu nesnenin de eklenmiş olduğunu görürsünüz. Dediğimiz gibi, ``globals()`` fonksiyonundan dönen nesne bir sözlüktür. Bu sözlüğe, herhangi bir sözlüğe veri ekler gibi değer de ekleyebilirsiniz:: >>> globals()['z'] = 23 Bu şekilde global isim alanına `z` adlı bir değişken eklemiş oldunuz:: >>> z 23 Yalnız, Python programlama dili bize bu şekilde global isim alanına nesne ekleme imkanı verse de, biz mecbur değilsek bu yöntemi kullanmaktan kaçınmalıyız. Çünkü bu şekilde sıradışı bir yöntemle değişken tanımladığımız için aslında global isim alanını, nerden geldiğini kestirmenin güç olduğu değerlerle 'kirletmiş' oluyoruz. Bildiğiniz gibi, Python'da global isim alanı dışında bir de lokal isim alanı bulunur. Lokal isim alanlarının, fonksiyonlara (ve ileride göreceğimiz gibi sınıflara) ait bir isim alanı olduğunu biliyorsunuz. İşte bu isim alanlarına ulaşmak için de ``locals()`` adlı bir fonksiyondan yararlanacağız:: def fonksiyon(param1, param2): x = 10 print(locals()) fonksiyon(10, 20) Bu fonksiyonu çalıştırdığınızda şu çıktıyı alacaksınız:: {'param2': 20, 'param1': 10, 'x': 10} Gördüğünüz gibi, ``locals()`` fonksiyonu gerçekten de bize ``fonksiyon()`` adlı fonksiyon içindeki lokal değerleri veriyor. ``globals()`` ve ``locals()`` fonksiyonlarının ne işe yaradığını incelediğimize göre ``exec()`` fonksiyonunu anlatırken kaldığımız yere dönebiliriz. Ne diyorduk? Elimizde, değeri `20` olan `a` adlı bir değişken vardı:: >>> a = 20 ``exec()`` fonksiyonu yardımıyla `a` değişkeninin de içinde yer aldığı mevcut isim alanına müdahale edelim:: >>> exec('a = 3') Bu şekilde `a` değişkeninin varolan değerini silmiş olduk:: >>> print(a) 3 Dediğimiz gibi, bu tür durumlarda, ``exec()`` ile oluşturduğunuz değişkenleri global isim alanı yerine farklı bir isim alanına göndermeyi tercih etmemiz daha uygun olacaktır. Python'da isim alanlarının basit bir sözlük olduğunu öğrendiğimize göre, ``exec()`` ile oluşturduğumuz değişkenleri global isim alanı yerine nasıl farklı bir isim alanına göndereceğimizi görebiliriz. Önce yeni bir isim alanı oluşturalım:: >>> ia = {} Şimdi ``exec()`` ile oluşturacağımız değerleri bu isim alanına gönderebiliriz:: >>> exec('a = 3', ia) Böylece global isim alanındaki `a` değişkeninin değerine dokunmamış olduk:: >>> a 20 Yeni oluşturduğumuz değer ise `ia` adlı yeni isim alanına gitti:: >>> ia['a'] 3 copyright() ************ Bu fonksiyon yardımıyla Python'ın telif haklarına ilişkin bilgilere erişebilirsiniz:: >>> copyright() Copyright (c) 2001-2012 Python Software Foundation. All Rights Reserved. Copyright (c) 2000 BeOpen.com. All Rights Reserved. Copyright (c) 1995-2001 Corporation for National Research Initiatives. All Rights Reserved. Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. All Rights Reserved. credits() ********** Bu fonksiyon, Python programlama diline katkıda bulunanlara teşekkür içeren küçük bir metni ekrana çıktı olarak verir:: >>> credits() Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands for supporting Python development. See www.python.org for more information. license() ********** Bu fonksiyon yardımıyla Python'ın lisansına ilişkin epey ayrıntılı metinlere ulaşabilirsiniz. dir() ********** Eğer ``dir()`` fonksiyonunu parametresiz olarak kullanırsak, mevcut isim alanındaki öğeleri bir liste halinde elde ederiz:: >>> dir() ['__builtins__', '__doc__', '__loader__', '__name__', '__package__'] Bu bakımdan ``dir()`` fonksiyonu ``globals()`` ve ``locals()`` fonksiyonlarına benzer. Ancak onlardan farkı, ``dir()`` fonksiyonunun çıktı olarak bir liste, ``globals()`` ve ``locals()`` fonksiyonlarının ise birer sözlük vermesidir. Ayrıca ``dir()`` fonksiyonunu kullanarak nesnelerin metot ve niteliklerini içeren bir listeye ulaşabileceğimizi de biliyorsunuz. Örneğin bu fonksiyonu kullanarak farklı veri tiplerinin metot ve niteliklerini listeleyebiliriz:: >>> dir('') >>> dir([]) >>> dir({}) divmod() ********** Bu fonksiyonun işlevini bir örnek üzerinden göstermeye çalışalım:: >>> divmod(10, 2) (5, 0) Gördüğünüz gibi ``divmod(10, 2)`` komutu bize iki öğeli bir demet veriyor. Bu demetin ilk öğesi, ``divmod()`` fonksiyonuna verilen ilk parametrenin ikinci parametreye bölünmesi işleminin sonucudur. Demetimizin ikinci öğesi ise, ilk parametrenin ikinci parametreye bölünmesi işleminden kalan sayıdır. Yani demetin ilk parametresi bölme işleminin 'bölüm' kısmını, ikinci öğesi ise 'kalan' kısmını verir. Bu fonksiyonun bölme işlemininin sonucunu tamsayı cinsinden verdiğine dikkat ediyoruz:: >>> divmod(10, 3) (3, 1) `10` sayısı `3` sayısına bölündüğünde tamsayı cinsinden sonuç `3`'tür. Bu bölme işleminin kalanı ise `1`'dir. enumerate() ************* İngilizcede *enumerate* kelimesi 'numaralandırmak' anlamına gelir. ``enumerate()`` fonksiyonunun görevi de kelimenin bu anlamıyla aynıdır. Yani bu fonksiyonu kullanarak nesneleri numaralandırabiliriz. Bu fonksiyon bize bir 'enumerate' nesnesi verir:: >>> enumerate('istihza') Bu nesnenin içeriğine nasıl erişebileceğimizi biliyorsunuz: Nesneyi bir listeye çevirebiliriz:: >>> list(enumerate('istihza')) [(0, 'i'), (1, 's'), (2, 't'), (3, 'i'), (4, 'h'), (5, 'z'), (6, 'a')] veya:: >>> [i for i in enumerate('istihza')] [(0, 'i'), (1, 's'), (2, 't'), (3, 'i'), (4, 'h'), (5, 'z'), (6, 'a')] ``print()`` fonksiyonuna yıldızlı parametre olarak verebiliriz:: >>> print(*enumerate('istihza')) (0, 'i') (1, 's') (2, 't') (3, 'i') (4, 'h') (5, 'z') (6, 'a') veya nesne üzerinde bir döngü kurabiliriz:: >>> for i in enumerate('istihza'): ... print(i) ... (0, 'i') (1, 's') (2, 't') (3, 'i') (4, 'h') (5, 'z') (6, 'a') Gördüğünüz gibi, 'enumerate' nesnesi bize her koşulda iki öğeli demetler veriyor. Bu demetlerin her bir öğesine nasıl ulaşabileceğimizi de biliyor olmalısınız:: >>> for sıra, öğe in enumerate('istihza'): ... print("{}. {:>2}".format(sıra, öğe)) ... 0. i 1. s 2. t 3. i 4. h 5. z 6. a Örneklerden de gördüğünüz gibi, ``enumerate()`` fonksiyonu bize bir dizi içindeki öğelerin sırasını ve öğenin kendisini içeren bir demet veriyor. Dikkat ettiyseniz, her zaman olduğu gibi, Python burada da saymaya 0'dan başlıyor. Yani ``enumerate()`` fonksiyonunun ürettiği öğe sıralamasında ilk öğenin sırası 0 oluyor. Elbette eğer isterseniz ``enumerate()`` fonksiyonunun saymaya kaçtan başlayacağını kendiniz de belirleyebilirsiniz:: >>> for sıra, öğe in enumerate('istihza', 1): ... print("{}. {:>2}".format(sıra, öğe)) ... 1. i 2. s 3. t 4. i 5. h 6. z 7. a ``enumerate()`` fonksiyonuna verdiğimiz ikinci parametre saymaya kaçtan başlanacağını gösteriyor. Eğer bu fonksiyonu ikinci parametre olmadan kullanırsak Python bizim saymaya 0'dan başlamak istediğimizi varsayacaktır. exit() ********** Bu fonksiyon, o anda çalışan programdan çıkmanızı sağlar. Eğer bu komutu etkileşimli kabukta verirseniz o anda açık olan oturum kapanacaktır. help() ********** ``help()`` fonksiyonu gömülü fonksiyonlar içinde en faydalı fonksiyonların başında gelir. Bu fonksiyonu kullanarak Python programlama diline ait öğelere ilişkin yardım belgelerine ulaşabiliriz. Örneğin:: >>> help(dir) Bu komutu verdiğimizde ``dir()`` fonksiyonunun ne işe yaradığını gösteren İngilizce bir belgeye ulaşırız. Gördüğünüz gibi, hakkında bilgi edinmek istediğimiz öğeyi ``help()`` fonksiyonuna parametre olarak vererek ilgili yardım dosyasına erişebiliyoruz. Eğer bu fonksiyonu parametresiz olarak kullanırsak 'etkileşimli yardım' denen ekrana ulaşırız:: >>> help() Welcome to Python 3.3! This is the interactive help utility. If this is your first time using Python, you should definitely check out the tutorial on the Internet at http://docs.python.org/3.3/tutorial/. Enter the name of any module, keyword, or topic to get help on writing Python programs and using Python modules. To quit this help utility and return to the interpreter, just type "quit". To get a list of available modules, keywords, or topics, type "modules", "keywords", or "topics". Each module also comes with a one-line summary of what it does; to list the modules whose summaries contain a given word such as "spam", type "modules spam". help> Bu ekranda, hakkında bilgi edinmek istediğiniz öğeyi ``help>`` ibaresinden hemen sonra, boşluk bırakmadan yazarak öğeye ilişkin bilgilere ulaşabilirsiniz:: help> dir Etkileşimli yardım ekranından çıkmak için 'q' harfine basabilirsiniz. id() ********** Python'da her nesnenin bir kimliğinin olduğunu biliyorsunuz. Kimlik işleçlerini incelediğimiz konuda bundan bir miktar bahsetmiş ve orada ``id()`` adlı bir fonksiyondan söz etmiştik. Orada şöyle bir örnek vermiştik:: >>> a = 50 >>> id(a) 505494576 >>> kardiz = "Elveda Zalim Dünya!" >>> id(kardiz) 14461728 Orada söylediğimiz ve yukarıdaki örneklerden de bir kez daha gördüğünüz gibi, Python’daki her nesnenin kimliği eşşiz, tek ve benzersizdir. input() ********** Bu fonksiyonun ne işe yaradığını gayet iyi biliyorsunuz. ``input()`` adlı bu gömülü fonksiyonu kullanarak kullanıcı ile veri alışverişinde bulunabiliyoruz. format() ********** Bu gömülü fonksiyonun görevi, daha önce karakter dizilerini işlerken, karakter dizilerinin bir metodu olarak öğrendiğimiz ``format()`` metoduna benzer bir şekilde, karakter dizilerini biçimlendirmektir. Ancak ``format()`` fonksiyonu, daha önce öğrendiğimiz ``format()`` metoduna göre daha dar kapsamlıdır. ``format()`` metodunu kullanarak oldukça karmaşık karakter dizisi biçimlendirme işlemlerini gerçekleştirebiliriz, ama birazdan inceleyeceğimiz ``format()`` gömülü fonksiyonu yalnızca tek bir değeri biçimlendirmek için kullanılır. Basit bir örnek verelim: >>> format(12, '.2f') '12.00' Yukarıdaki ifadeyi daha önce gördüğümüz ``format()`` metodu ile şu şekilde yazabiliriz:: >>> '{:.2f}'.format(12) '12.00' filter() ********** Bu gömülü fonksiyon yardımıyla dizi niteliği taşıyan nesneler içindeki öğeler üzerinde belirli bir ölçüte göre bir süzme işlemi uygulayabiliriz. Dilerseniz ``filter()`` fonksiyonunun görevini bir örnek üzerinden anlamaya çalışalım. Diyelim ki elimizde şöyle bir liste var:: >>> l = [400, 176, 64, 175, 355, 13, 207, 298, 397, 386, 31, 120, 120, 236, 241, 123, 249, 364, 292, 153] Amacımız bu liste içindeki tek sayıları süzmek. Daha önce öğrendiğimiz yöntemleri kullanarak bu görevi şu şekilde yerine getirebiliriz:: >>> for i in l: ... if i % 2 == 1: ... print(i) ... 175 355 13 207 397 31 241 123 249 153 Hatta eğer istersek liste üreteçlerini kullanarak aynı işlemi daha kısa bir yoldan da halledebiliriz:: >>> [i for i in l if i % 2 == 1] [175, 355, 13, 207, 397, 31, 241, 123, 249, 153] İşte Python, yukarıdaki işlemi yapabilmemiz için bize üçüncü bir yol daha sunar. Bu üçüncü yolun adı ``filter()`` fonksiyonudur. Dikkatlice bakın:: def tek(sayı): return sayı % 2 == 1 print(*filter(tek, l)) Dilerseniz bu kodları daha iyi anlayabilmek için ``filter()`` fonksiyonuna biraz daha yakından bakalım... ``filter()`` fonksiyonu toplam iki parametre alır. Bu parametrelerden ilki ölçütü belirleyen fonksiyon, ikincisi ise bu ölçütün uygulanacağı öğedir. Yukarıdaki örneğe baktığımızda, ``tek()`` adlı fonksiyonun, `l` adlı öğe üzerine uygulandığını görüyoruz. Yukarıdaki örnekte ilk olarak ``tek()`` adlı bir fonksiyon tanımladık:: def tek(sayı): return sayı % 2 == 1 Bu fonksiyonun görevi, kendisine parametre olarak verilen bir sayının tek sayı olup olmadığını sorgulamak. Eğer verilen parametre bir tek sayı ise fonksiyonumuz `True` değerini, tek sayı değilse `False` değerini döndürecektir. İsterseniz fonksiyonumuzu test edelim:: print(tek(12)) `12` sayısı bir tek sayı olmadığı için fonksiyonumuz bize `False` çıktısı verir. Bir de şuna bakalım:: print(tek(117)) `117` sayısı ise bir tek sayıdır. Bu nedenle fonksiyonumuz bize `True` değerini verecektir. İşte biz bu fonksiyonu, ``filter()`` fonksiyonu yardımıyla şu liste üzerine uygulayacağız:: l = [400, 176, 64, 175, 355, 13, 207, 298, 397, 386, 31, 120, 120, 236, 241, 123, 249, 364, 292, 153] Dediğimiz gibi, ``filter()`` fonksiyonu, dizi özelliği taşıyan nesneler üzerinde belli bir ölçüte göre filtreleme işlemi yapmamızı sağlar. Biz de biraz önce tanımladığımız ``tek()`` adlı fonksiyonu `l` adlı bu listeye uygulayarak liste içindeki tek sayıları filtreleyeceğiz. ``filter()`` fonksiyonunu çalıştıralım:: >>> filter(tek, l) Burada ``filter()`` fonksiyonuna ilk parametre olarak ``tek()`` fonksiyonunu verdik. İkinci parametremiz ise bu fonksiyonu uygulayacağımız `l` adlı liste. Amacımız, `l` adlı liste üzerine ``tek()`` fonksiyonunu uygulayarak, bu liste içindeki öğelerden `True` çıktısı verenleri (yani tek sayıları) ayıklamak. Şimdi de yukarıdaki koddan aldığımız çıktıya bakalım:: Gördüğünüz gibi, bu fonksiyonu bu şekilde kullandığımızda elde ettiğimiz şey bir 'filtre nesnesi'. Bu nesne içindeki öğeleri görebilmek için ne yapabileceğimizi biliyorsunuz:: >>> list(filter(tek, l)) [175, 355, 13, 207, 397, 31, 241, 123, 249, 153] veya:: >>> print(*filter(tek, l)) 175 355 13 207 397 31 241 123 249 153 ya da:: >>> [i for i in filter(tek, l)] [175, 355, 13, 207, 397, 31, 241, 123, 249, 153] Gördüğünüz gibi, gerçekten de `l` adlı liste içindeki bütün tek sayılar süzüldü. Gelin isterseniz ``filter()`` fonksiyonunu biraz daha iyi anlayabilmek için basit bir çalışma yapalım. Elimizde bir sınıftaki öğrencilerin Matematik sınavından aldığı notları içeren bir sözlük var:: notlar = {'Ahmet' : 60, 'Sinan' : 50, 'Mehmet' : 45, 'Ceren' : 87, 'Selen' : 99, 'Cem' : 98, 'Can' : 51, 'Kezban' : 100, 'Hakan' : 66, 'Mahmut' : 80} Okulda kullanılan not sistemine göre yukarıdaki notları şu şekilde sınıflandırabiliyoruz:: def not_durumu(n): if n in range(0, 50): return 'F' if n in range(50, 70): return 'D' if n in range(70, 80): return 'C' if n in range(80, 90): return 'B' if n in range(90, 101): return 'A' Buna göre mesela ``print(not_durumu(54))`` gibi bir kod yazdığımızda bu notun karşılık geldiği 'D' sayısını alabiliyoruz. Peki biz bu notları belli bir ölçüte göre süzmek, ayıklamak istersek ne yapabiliriz? Örneğin notu 70'ten yukarı olan öğrencileri listelemek istersek nasıl bir kod yazabiliriz? İşte böyle bir durumda ``filter()`` adlı gömülü fonksiyonu kullanabiliriz:: notlar = {'Ahmet' : 60, 'Sinan' : 50, 'Mehmet' : 45, 'Ceren' : 87, 'Selen' : 99, 'Cem' : 98, 'Can' : 51, 'Kezban' : 100, 'Hakan' : 66, 'Mahmut' : 80} def süz(n): return n >= 70 print(*filter(süz, notlar.values())) Gördüğünüz gibi, ``filter()`` fonksiyonu, ``süz()`` adlı fonksiyon ile belirlediğimiz ölçütü `notlar` adlı sözlüğün değerleri üzerine tek tek uygulamamızı sağlıyor. hash() ********** Bu fonksiyon, belirli türdeki nesnelere bir karma değeri vermemizi sağlar. Örneğin:: >>> hash('istihza') -840510580 >>> hash('python') 212829695 Ancak bu fonksiyonun ürettiği çıktı aynı nesne için bütün sistemlerde aynı olmayabilir. Yani örneğin yukarıdaki ``hash('istihza')`` komutu 32 bitlik ve 64 bitlik işletim sistemlerinde birbirinden farklı sonuçlar verebilir. Ayrıca bu fonksiyonun ürettiği karma değerlerinin birbiriyle çakışma ihtimali de yüksektir. Dolayısıyla bu fonksiyonu kullanarak, mesela parola girişleri için karma değeri üretmek doğru olmaz. isinstance() ************* Hatırlarsanız daha ilk derslerimizde öğrendiğimiz ``type()`` adlı bir fonksiyon vardı. Bu fonksiyonu bir nesnenin hangi veri tipinde olduğunu tespit etmek için kullanıyorduk:: >>> type('istihza') İşte buna benzer şekilde, tip denetimi için kullanabileceğimiz bir fonksiyon daha var. Bu fonksiyonun adı ``isinstance()``. Bu fonksiyonu şöyle kullanıyoruz:: >>> isinstance('istihza', str) True Gördüğünüz gibi ``'istihza'`` gerçekten bir karakter dizisi (``str``) olduğu için komutumuz `True` çıktısı veriyor. Bir de şuna bakalım:: >>> isinstance('istihza', list) False ``'istihza'`` bir liste (``list``) olmadığı için komutumuz bu kez `False` çıktısı verdi. len() ********** Bu fonksiyon yardımıyla nesnelerin uzunluklarını hesaplayabileceğimizi biliyorsunuz:: >>> len('istihza') 7 >>> l = [1, 4, 5, 3, 2, 9, 10] >>> len(l) 7 map() ********** Diyelim ki elimizde şöyle bir liste var:: >>> l = [1, 4, 5, 4, 2, 9, 10] Amacımız bu liste içindeki her öğenin karesini hesaplamak. Bunun için şöyle bir yol izleyebiliriz:: >>> for i in l: ... i ** 2 ... 1 16 25 16 4 81 100 Böylece, istediğimiz gibi, bütün öğelerin karesini bulmuş olduk. Bu tür bir işlemi yapmanın bir başka yolu da ``map()`` adlı bir gömülü fonksiyondan yararlanmaktır. Dikkatlice bakın:: >>> def karesi(n): ... return n ** 2 ... Burada bir `n` sayısının karesini hesaplayan bir fonksiyon tanımladık. Şimdi bu fonksiyonu `l` listesinin bütün öğeleri üzerine uygulayacağız:: >>> list(map(karesi, l)) [1, 16, 25, 16, 4, 81, 100] max() ********** ``max()`` gömülü fonksiyonunun görevi, bir dizi içindeki en büyük öğeyi vermektir. Bu fonksiyon birkaç farklı parametre alır ve verdiği çıktı, aldığı parametrelerin türüne ve sayısına bağlı olarak değişiklik gösterebilir. Bu fonksiyonu en basit şu şekilde kullanabilirsiniz:: >>> max(1, 2, 3) 3 ``max()`` fonksiyonu yukarıdaki şekilde çalıştırıldığında, kendisine verilen parametreler arasında en büyük olanı bulacaktır. Yukarıdaki parametrelerden en büyüğü `3` olduğu için de yukarıdaki komut `3` çıktısı verecektir. Yukarıdaki kodların sağladığı etkiyi şu şekilde de elde edebiliriz:: >>> liste = [1, 2, 3] >>> max(liste) 3 ``max()`` fonksiyonu yukarıda gösterildiği gibi birtakım isimsiz parametrelerle birlikte `key` adlı isimli bir parametre de alır. Bu parametre yardımıyla ``max()`` fonksiyonunun 'en büyük' kavramını hangi ölçüte göre seçeceğini belirleyebiliriz. Örneğin:: >>> isimler = ['ahmet', 'can', 'mehmet', 'selin', 'abdullah', 'kezban'] >>> max(isimler, key=len) 'abdullah' ``max()`` fonksiyonu öntanımlı olarak, 'en büyük' kavramını sayısal büyüklük üzerinden değerlendirir. Yani herhangi bir `key` parametresi kullanılmadığında, bu fonksiyon otomatik olarak bir dizi içindeki en büyük sayıyı bulur. Ancak eğer biz istersek, yukarıdaki örnekte olduğu gibi, 'en büyük' kavramının uzunluk cinsinden değerlendirilmesini de sağlayabiliriz. Yukarıdaki örnekte elimizde şöyle bir liste var:: >>> isimler = ['ahmet', 'can', 'mehmet', 'selin', 'abdullah', 'kezban'] Amacımız bu liste içindeki isimler arasından, en fazla harf içerenini bulmak. Bildiğiniz gibi Python'da bir karakter dizisinin uzunluğunu belirlemek için ``len()`` adlı bir fonksiyondan yararlanıyoruz. İşte aşağıdaki kod yardımıyla da ``max()`` fonksiyonunun 'en büyük' ölçütünü ``len()`` fonksiyonu üzerinden değerlendirmesini sağlıyoruz:: >>> max(isimler, key=len) Bu arada `key` fonksiyonuna ``len()`` fonksiyonunu parantezsiz olarak verdiğimize dikkat edin. Gelin isterseniz ``max()`` fonksiyonunu biraz daha iyi anlamak için ufak bir çalışma yapalım. Diyelim ki elimizde şöyle bir sözlük var:: askerler = {'ahmet' : 'onbaşı', 'mehmet' : 'teğmen', 'ali' : 'yüzbaşı', 'cevat' : 'albay', 'berkay' : 'üsteğmen', 'mahmut' : 'binbaşı'} Amacımız bu sözlük içindeki en yüksek askeri rütbeyi bulmak. İşte bunun için ``max()`` fonksiyonundan yararlanabiliriz. Bildiğiniz gibi, ``max()`` fonksiyonu ölçüt olarak sayısal büyüklüğü göz önüne alıyor. Elbette askeri rütbeleri böyle bir ölçüte göre sıralamak pek mümkün değil. Ama eğer şöyle bir fonksiyon yazarsak işler değişir:: def en_yüksek_rütbe(rütbe): rütbeler = {'er' : 0, 'onbaşı' : 1, 'çavuş' : 2, 'asteğmen' : 3, 'teğmen' : 4, 'üsteğmen' : 5, 'yüzbaşı' : 6, 'binbaşı' : 7, 'yarbay' : 8, 'albay' : 9} return rütbeler[rütbe] Burada, rütbelerin her birine bir sayı verdik. En küçük rütbe en düşük sayıya, en yüksek rütbe ise en büyük sayıya sahip. Fonksiyonumuz bir adet parametre alıyor. Bu parametrenin adı `rütbe`. Yazdığımız fonksiyon, kendisine parametre olarak verilecek rütbeyi `rütbeler` adlı sözlükte arayıp, bu rütbeye karşılık gelen sayıyı döndürecek. Bu bilgileri kullanarak kodlarımızın son halini düzenleyelim:: def en_yüksek_rütbe(rütbe): rütbeler = {'er' : 0, 'onbaşı' : 1, 'çavuş' : 2, 'asteğmen' : 3, 'teğmen' : 4, 'üsteğmen' : 5, 'yüzbaşı' : 6, 'binbaşı' : 7, 'yarbay' : 8, 'albay' : 9} return rütbeler[rütbe] askerler = {'ahmet': 'onbaşı', 'mehmet': 'teğmen', 'ali': 'yüzbaşı', 'cevat': 'albay', 'berkay': 'üsteğmen', 'mahmut': 'binbaşı'} Artık ``max()`` fonksiyonunu `askerler` adlı sözlük üzerinde uygulayabiliriz:: print(max(askerler.values(), key=en_yüksek_rütbe)) Böylece `askerler` adlı sözlüğün değerleri ``en_yüksek_rütbe()`` fonksiyonunun sunduğu ölçüt üzerinden ele alınacak ve en büyük sayı değerine sahip olan rütbe çıktı olarak verilecektir. Yukarıdaki kodlar problemimizi çözüyor. Peki ama ya biz rütbe ile birlikte bu rütbeyi taşıyan askerin adını da öğrenmek istersek nasıl bir kod yazacağız? Bunun için de şöyle bir kod yazabiliriz:: for k, v in askerler.items(): if askerler[k] in max(askerler.values(), key=en_yüksek_rütbe): print(v, k) Eğer isterseniz burada `in` işleci yerine `==` işlecini de kullanabilirsiniz:: for k, v in askerler.items(): if askerler[k] == max(askerler.values(), key=en_yüksek_rütbe): print(v, k) min() ********** ``min()`` fonksiyonu ``max()`` fonksiyonunun tam tersini yapar. Bildiğiniz gibi ``max()`` fonksiyonu bir dizi içindeki en büyük öğeyi buluyordu. İşte ``min()`` fonksiyonu da bir dizi içindeki en küçük öğeyi bulur. Bu fonksiyonun kullanımı ``max()`` ile aynıdır. open() ********** Bu fonksiyon herhangi bir dosyayı açmak veya oluşturmak için kullanılır. Eğer dosyanın açılması veya oluşturulması esnasında bir hata ortaya çıkarsa ``IOError`` türünde bir hata mesajı verilir. Bu fonksiyonun formülü şudur:: >>> open(dosya_adi, mode='r', buffering=-1, encoding=None, ... errors=None, newline=None, closefd=True, opener=None) Gördüğünüz gibi, bu fonksiyon pek çok farklı parametre alabiliyor. Biz şimdiye kadar bu parametrelerin yalnızca en sık kullanılanlarını işlemiştik. Şimdi ise geri kalan parametrelerin ne işe yaradığını da ele alacağız. Yukarıdaki formülden de görebileceğiniz gibi, ``open()`` fonksiyonunun ilk parametresi `dosya_adi`'dır. Yani açmak veya oluşturmak istediğimiz dosya adını bu parametre ile belirtiyoruz:: >>> open('falanca_dosya.txt') Elbette eğer açmak istediğiniz dosya, o anda içinde bulunduğunuz dizinde değilse dosya adı olarak, o dosyanın tam adresini yazmanız gerekir. Mesela:: >>> open('/home/istihza/Desktop/dosya.txt') Bu arada, dosya adresini yazarken ters taksim yerine düz taksim işaretlerini kullanmak daha doğru olacaktır. Bu taksim türü hem Windows'ta hem de GNU/Linux'ta çalışır. Ancak eğer ters taksim işaretlerini kullanacaksanız, dosya yolu içindeki sinsi kaçış dizilerine karşı dikkatli olmalısınız:: >>> f = open('test\nisan.txt') Traceback (most recent call last): File "", line 1, in OSError: [Errno 22] Invalid argument: 'test\nisan.txt' Burada problemin `nisan.txt` adlı dosyanın ilk harfi ile, bundan önce gelen ters taksim işaretinin birleşerek tesadüfen bir kaçış dizisi oluşturması olduğunu biliyorsunuz. Bu tür hatalara karşı ters taksim yerine düz taksim işaretlerini kullanabileceğiniz gibi `r` adlı kaçış dizisinden de yararlanabilirsiniz:: f = open(r'test\nisan.txt') ``open()`` fonksiyonunun ikinci parametresi olan `mode`'un da ne olduğunu biliyorsunuz. Bu parametre yardımıyla, herhangi bir dosyayı hangi kipte açmak istediğimizi belirtebiliyoruz. Bildiğiniz gibi, eğer `mode` parametresine herhangi bir değer vermezseniz Python ilgili dosyayı okuma kipinde açacaktır. Bu parametreye verebileceğiniz değerleri şöyle özetleyebiliriz: ========= =============================================================== Karakter Anlamı --------- --------------------------------------------------------------- 'r' Okuma kipidir. Öntanımlı değer budur. 'w' Yazma kipidir. Eğer belirtilen adda dosya zaten varsa o dosya silinir. 'x' Yeni bir dosya oluşturulup yazma kipinde açılır. 'a' Dosya ekleme kipinde açılır. Bu kip ile, varolan bir dosyanın sonuna eklemeler yapılabilir. 'b' Dosyaları ikili kipte açmak için kullanılır. 't' Dosyaları metin kipinde açmak için kullanılır. Öntanımlı değerdir. '+' Aynı dosya üzerinde hem okuma hem de yazma işlemleri yapılmasını sağlar. ========= =============================================================== ``open()`` fonksiyonunun alabileceği bir başka parametre de `buffering` parametresidir. Bildiğiniz gibi, ``open()`` fonksiyonuyla bir dosyayı açıp bu dosyaya veri girdiğimizde bu veriler önce tampona alınacak, dosya kapandıktan sonra ise tamponda bekletilen veriler dosyaya işlenecektir. İşte bu `buffering` parametresi yardımıyla bu tampona alma işleminin nasıl yürüyeceğini belirleyebiliriz. Eğer dosyaya işlenecek verilerin tampona alınmadan doğrudan dosyaya işlenmesini isterseniz `buffering` değerini `0` olarak belirlersiniz. Yalnız bu değer sadece ikili kipte etkindir. Yani bir dosyayı eğer metin kipinde açıyorsanız `buffering` parametresinin değerini `0` yapamazsınız. Eğer dosyaya veri işlerken tampona alınan verilerin satır satır dosyaya eklenmesini isterseniz `buffering` değerini `1` olarak belirlersiniz. Bunun nasıl çalıştığını anlamak için şu örneği dikkatlice inceleyin:: >>> f = open('ni.txt', 'w', buffering=1) >>> f.write('birinci satır\n') 14 >>> f.write('ikinci satır\n') 13 >>> f.write('aaa') 3 >>> f.write('\n') 1 Burada her ``write()`` komutundan sonra `ni.txt` adlı dosyayı açıp bakarsanız, şu durumu görürsünüz: * ``f.write('birinci satır\n')`` komutuyla dosyaya bir satırlık veri ekledik ve bu veri dosyaya anında işlendi. * ``f.write('ikinci satır\n')`` komutuyla dosyaya bir satırlık başka bir veri daha ekledik ve bu veri de dosyaya anında işlendi. * ``f.write('aaa')`` komutuyla eklenen veri satır değil. Çünkü satır sonuna işaret eden satır başı kaçış dizisini kullanmadık. * ``f.write('\n')`` komutuyla satır başı kaçış dizisini eklediğimiz anda bir önceki karakter dizisi (``'aaa'``) de dosyaya eklenecektir. Ancak `buffering` parametresi bu `1` değerini yalnızca metin kipinde alabilir. Bu kısıtlamayı da aklımızın bir kenarına not edelim... `0` ve `1` dışında `buffering` parametresine 1'den büyük bir değer verdiğinizde ise tampon boyutunun ne kadar olacağını kendiniz belirlemiş olursunuz. Yalnız çoğu durumda `buffering` parametresine herhangi bir özel değer atamanız gerekmeyecektir. Bu parametreye herhangi bir değer atamadığınızda, kullandığınız işletim sistemi tampona alma işlemlerininin nasıl yürütüleceğine ve tampon boyutuna kendisi karar verecektir. İşletim sisteminin sizin yerinize verdiği bu karar da çoğunlukla istediğiniz şey olacaktır... Eğer kendi sisteminizde öntanımlı tampon boyutunun ne olduğunu merak ediyorsanız şu komutları kullanabilirsiniz:: >>> import io >>> io.DEFAULT_BUFFER_SIZE Çoğu sistemde bu değer 4096 ve 8192 bayt olacaktır. ``open()`` fonksiyonunun alabileceği bir başka parametre de `encoding` parametresidir. Bu parametre, dosyanın hangi karakter kodlaması ile açılacağını belirler. Örneğin bir dosyayı 'UTF-8' karakter kodlaması ile açmak için şu komutu kullanıyoruz:: >>> f = open('dosya', encoding='utf-8') Üzerinde işlem yaptığınız dosyalarda özellikle Türkçe karakter sorunları yaşamak istemiyorsanız, bir dosyayı açarken mutlaka `encoding` parametresinin değerini de ayarlamanızı tavsiye ederim. Bir dosyayı açarken veya okurken herhangi bir karakter kodlama hatası ile karşılaştığınızda Python'ın ne tepki vermesi gerektiğini ise `errors` adlı parametre yardımıyla belirleyebilirsiniz. Eğer bu parametreye `strict` değerini verirseniz karakter kodlama hataları programınızın ``ValueError`` türünde bir hata vererek çalışmayı kesmesine neden olacaktır. Bu parametreye herhangi bir değer vermediğinizde de Python sanki `strict` değerini vermişsiniz gibi davranır. Eğer `errors` parametresine `ignore` değerini verirseniz kodlama hataları görmezden gelinecek, bu hataya sebep olan karakter silinecektir. Yalnız bu değerin veri kaybına yol açma ihtimalini de göz önünde bulundurmalısınız. Eğer `errors` parametresine `replace` değerini verirseniz kodlama hatasına yol açan karater '?' veya '\ufffd' karakterleri ile değiştirilecektir. ``open()`` fonksiyonunun kabul ettiği bir başka parametre de `newline` adlı parametredir. Peki bu parametre ne işe yarar? Windows ve GNU/Linux işletim sistemleri satır sonlarını birbirlerinden farklı şekilde gösterir. GNU/Linux'ta yazılmış dosyalarda satır sonları `\\n` karakteri ile gösterilirken, Windows'ta yazılmış dosyalarda satır sonunda `\\r\\n` karakterleri bulunur. Eğer Windows ve GNU/Linux sistemleri arasında dosya alışverişi yapıyorsanız kimi durumlarda bu farklılık çeşitli sorunların ortaya çıkmasına yol açabilir. İşte dosyalarınızın hangi satır sonu karakterine sahip olacağını yukarıda bahsettiğimiz `newline` adlı parametre ile belirleyebilirsiniz. Örneğin:: >>> f = open('dosya', newline='\n') Bu şekilde dosyanız hangi işletim sisteminde olursa olsun satır sonlarında `\\n` karakterine sahip olacaktır. Dosyaların metotlarını incelerseniz o listede ``fileno()`` adlı bir metodun olduğunu göreceksiniz. Bu metot, bize bir dosyanın 'dosya tanımlayıcısını' (*file descriptor*) verir. Dosya tanımlayıcıları, dosyaya işaret eden pozitif tam sayılardır. `0`, `1` ve `2` sayıları standart girdi, standart çıktı ve standart hata dosyalarına ayrılmış olduğu için, sizin açtığınız ve üzerinde işlem yaptığınız dosyaların tanımlayıcıları `2` sayısından büyük olacaktır. Bir örnek verelim:: >>> f = open('ni.txt') >>> f.fileno() 3 İşte burada gördüğünüz sayı, `ni.txt` adlı dosyanın 'dosya tanımlayıcısıdır. Her dosyanın dosya tanımlayıcısı benzersizdir:: >>> g = open('zi.txt') >>> g.fileno() 4 Python'da bir dosyayı ``open()`` fonksiyonuyla açarken dosya adını vermenin yanı sıra, dosyanın tanımlayıcısını da kullanabilirsiniz:: >>> z = open(4) veya:: >>> z = open(g.fileno()) Bu sayede, eğer isterseniz, elinizdeki dosyalarla daha ileri düzeyli işlemler yapabilirsiniz. Bir örnek verelim. Dediğimiz gibi, bir dosyanın tanımlayıcısı tek ve benzersizdir. Farklı dosyalar aynı tanımlayıcılara sahip olmaz:: >>> a = open('aaa.txt') >>> a.fileno() 3 >>> b = open('bbb.txt') >>> b.fileno() 4 Şimdi şu örneklere bakın:: >>> c = open(b.fileno(), closefd=False) Bu şekilde `b` adlı dosyanın tanımlayıcısını kullanarak, aynı dosyayı bir de `c` adıyla açtık. Ancak burada kullandığımız `closefd=False` parametresine dikkat edin. Normalde dosyayı kapattığımızda dosyanın tanımlayıcısı serbest kalır ve başka bir dosya açıldığında bu tanımlayıcı yeni dosyaya atanır. Ama `closefd` parametresine ``False`` değeri verdiğimizde dosya kapansa bile, o dosyaya ait dosya tanımlayıcısı varolmaya devam edecektir. pow() ********** Daha önceki derslerimizde pek çok kez örneklerini verdiğimiz bu fonksiyon İngilizcedeki *power* (kuvvet) kelimesinin kısaltmasından oluşur. Adının anlamına uygun olarak, bu fonksiyonu bir sayının kuvvetlerini hesaplamak için kullanıyoruz. Bu fonksiyon en temel şekilde şöyle kullanılır:: >>> pow(2, 3) 8 Bu komutla `2` sayısının 3. kuvvetini hesaplamış oluyoruz. ``pow()`` fonksiyonu toplamda üç farklı parametre alır. İlk iki parametrenin ne olduğunu yukarıda örnekledik. Üçüncü parametre ise kuvvet hesaplaması sonucu elde edilen sayının modülüsünü hesaplayabilmemizi sağlar. Yani:: >>> pow(2, 3, 2) 0 Burada yaptığımız şey şu: Öncelikle `2` sayısının 3. kuvvetini hesapladık. Elde ettiğimiz sayı `8`. Ardından da bu sayının `2`'ye bölünmesi işleminden kalan sayıyı elde ettik. Yani `0`. Çünkü bildiğiniz gibi ``8 % 2`` işleminin sonucu `0`'dır. Dolayısıyla yukarıdaki komut şuna eşdeğerdir:: >>> (2 ** 3) % 2 0 Ancak önceki derslerimizde de söylediğimiz gibi, ``pow()`` fonksiyonu çoğunlukla yalnızca ilk iki parametresi ile birlikte kullanılır:: >>> pow(12, 2) 144 print() ********** ``print()`` fonksiyonunu artık gayet iyi tanıyoruz. Bu fonksiyonu, bildiğiniz gibi, kullanıcılarımıza birtakım mesajlar göstermek için kullanıyoruz. Kullanımını daha önce ayrıntılı bir şekilde anlatmış olduğumuz bu fonksiyonu şu şekilde formüle edebiliriz:: print(deg1, deg2, deg3, ..., sep=' ', end='\n', file=sys.stdout, flush=False) Burada; :degx: Çıktı verilecek değerlerin ne olduğunu belirtir. Buraya 256 adete kadar değer yazabilirsiniz. :sep: Çıktı verilirken değerlerin arasına hangi karakterin yerleştirileceğini belirtir. Bu değer öntanımlı olarak boşluk karakteridir. :end: Çıktı verilecek son değerin ardından hangi karakterin iliştirileceğini belirtir. Bu değer öntanımlı olarak satır başı (`\\n`) karakteridir. :file: Çıktıların hangi dosyaya yazılacağını belirtir. Öntanımlı olarak bu parametrenin değeri `sys.stdout`'tur. Yani ``print()`` fonksiyonu çıktılarını öntanımlı olarak standart çıktı konumuna gönderir. :flush: Bildiğiniz gibi, herhangi bir dosyaya yazma işlemi sırasında dosyaya yazılacak değerler öncelikle tampona alınır. İşlem tamamlandıktan sonra tampondaki bu değerler topluca dosyaya aktarılır. İşte bu parametre, değerleri tampona almadan doğrudan dosyaya gönderebilmemizi sağlar. Bu parametrenin öntanımlı değeri `False`'tur. Yani değerler dosyaya yazılmadan önce öntanımlı olarak öncelikle tampona gider. Ama eğer biz bu parametrenin değerini `True` olarak değiştirirsek, değerler doğrudan dosyaya yazılır. quit() ********** Bu fonksiyonu programdan çıkmak için kullanıyoruz. Eğer bu fonksiyonu etkileşimli kabukta verecek olursanız etkileşimli kabuk kapanacaktır. range() ********** Bu fonksiyonu belli bir aralıktaki sayıları listelemek için kullanıyoruz. Yani mesela `0` ile `10` arası sayıların listesini almak istersek şöyle bir komut yazabiliriz:: >>> l = range(0, 10) Ancak burada dikkat etmemiz gereken bir özellik var: Bu fonksiyon aslında doğrudan herhangi bir sayı listesi oluşturmaz. Yukarıda `l` değişkenine atadığımız komutu ekrana yazdırırsak bunu daha net görebilirsiniz:: >>> print(l) range(0, 10) Bir de bu verinin tipine bakalım:: >>> type(l) Gördüğünüz gibi, elimizdeki şey aslında bir sayı listesi değil, bir 'range' (aralık) nesnesidir. Biz bu nesneyi istersek başka veri tiplerine dönüştürebiliriz. Mesela bunu bir listeye dönüştürelim:: >>> list(l) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] veya bir demete:: >>> tuple(l) (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) ya da bir kümeye veya dondurulmuş kümeye:: >>> set(l) #küme {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} >>> frozenset(l) #dondurulmuş küme frozenset({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) Bu 'range' nesnesini istediğiniz veri tipine dönüştürdükten sonra, dönüştürdüğünüz veri tipinin kuralları çerçevesinde elinizdeki veriyi işleyebilirsiniz. ``range()`` fonksiyonundan elde ettiğiniz 'range' nesnesinin içeriğini elde etmek için bunu başka bir veri tipine dönüştürmenin yanısıra, bu nesne üzerinde bir ``for`` döngüsü de kurabilirsiniz:: >>> for i in range(10): ... print(i) ... 0 1 2 3 4 5 6 7 8 9 Ya da yıldızlı parametreler yardımıyla bu nesneyi ``print()`` fonksiyonuna göndererek, bu nesneyi istediğiniz gibi evirip çevirebilirsiniz:: >>> print(*range(10), sep=', ') 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 Esasında, yukarıda nasıl kullanılacağına dair bazı örnekler verdiğimiz bu ``range()`` fonksiyonunu temel olarak şu şekilde formüle edebiliriz:: range(başlangıç_değer, bitiş_değeri, atlama_değeri) Aşağıdaki örneği tekrar ele alalım:: >>> range(0, 10) Burada `0` başlangıç değeri, `10` ise bitiş değeridir. Buna göre oluşturulacak sayılar `0` ile `10` arasında olacaktır. Yalnız burada üretilecek sayı listesinde `0` sayısının dahil, `10` sayısının ise hariç olduğunu unutmuyoruz. Yani bu komutun bize vereceği ilk sayı `0`; son sayı ise `9` olacaktır. ``range()`` fonksiyonunda başlangıç değerinin öntanımlı değeri `0`'dır. Dolayısıyla istersek biz yukarıdaki komutu şöyle de yazabiliriz:: >>> range(10) Böylece Python bizim ``range(0, 10)`` komutunu kastettiğimizi varsayacaktır. Elbette eğer başlangıç değerinin `0` dışında bir değer olmasını istiyorsanız bunu özellikle belirtmeniz gerekir:: >>> range(10, 100) Bu komut bize `10` ile (`10` dahil) `100` arası (`100` hariç) sayıları içeren bir 'range' nesnesi verecektir. Yukarıda verdiğimiz formülden de göreceğiniz gibi, `başlangıç_değer` ve `bitiş_değer` dışında ``range()`` fonksiyonu üçüncü bir parametre daha alabiliyor. Bu parametreye `atlama_değeri` adı verdik. Bu parametreyi şöyle kullanıyoruz:: >>> list(range(0, 10, 2)) [0, 2, 4, 6, 8] Gördüğünüz gibi, ``range()`` fonksiyonuna üçüncü parametre olarak verdiğimiz `2` sayısı, `0` ile `10` arası sayıların ikişer ikişer atlanarak üretilmesini sağladı. reversed() ********** Diyelim ki elimizde şöyle bir liste var:: >>> isimler = ['ahmet', 'mehmet', 'veli', 'ayşe', 'çiğdem', 'ışık'] Eğer bu listedeki isimleri ters çevirmek, yani şöyle bir liste elde etmek isterseniz:: ['ışık', 'çiğdem', 'ayşe', 'veli', 'mehmet', 'ahmet'] ... ne yapmanız gerektiğini biliyorsunuz. Bu amaç için liste dilimleme yöntemlerinden yararlanabilirsiniz:: >>> isimler[::-1] ['ışık', 'çiğdem', 'ayşe', 'veli', 'mehmet', 'ahmet'] İşte aynı işlevi ``reversed()`` adlı bir fonksiyon yardımıyla da yerine getirebilirsiniz:: >>> reversed(isimler) Gördüğünüz gibi, tıpkı ``range()`` fonksiyonunda olduğu gibi, ``reversed()`` fonksiyonu da bize ürettiği öğelerin kendisi yerine, bir 'nesne' veriyor. Ama tabii ki bu bizim için bir sorun değil. Biz bu nesnenin içeriğini nasıl elde edebileceğimizi gayet iyi biliyoruz:: >>> list(reversed(isimler)) ['ışık', 'çiğdem', 'ayşe', 'veli', 'mehmet', 'ahmet'] ``range()`` fonksiyonunu anlatırken sözünü ettiğimiz içerik elde etme yöntemlerini ``reversed()`` fonksiyonuna da uygulayabilirsiniz. sorted() ********** Bu metot, daha önceki derslerimizden de bildiğiniz gibi, bir dizi içindeki öğeleri belirli bir ölçüte göre sıraya dizmemizi sağlıyor. Bununla ilgili çok basit bir örnek verelim:: >>> sorted('ahmet') ['a', 'e', 'h', 'm', 't'] Bu kodlar yardımıyla ``ahmet`` adlı karakter dizisi içindeki harfleri alfabe sırasına dizdik. Elbette bu fonksiyonu sadece karakter dizileri üzerine uygulamıyoruz. ``sorted()`` adlı fonksiyon, dizi özelliği taşıyan her türlü nesne üzerine uygulanabilir. Mesela demetlerin ve listelerin bir dizi olduğunu biliyoruz. Dolayısıyla:: >>> sorted(('elma', 'armut', 'kiraz', 'badem')) ['armut', 'badem', 'elma', 'kiraz'] >>> sorted(['elma', 'armut', 'kiraz', 'badem']) ['armut', 'badem', 'elma', 'kiraz'] ``sorted()`` fonksiyonuna hangi türde bir veri tipi verirseniz verin, aldığınız çıktı her zaman bir liste olacaktır. Bunu unutmayın. Gördüğünüz gibi, ``sorted()`` fonksiyonu nesneler üzerinde bir sıralama işlemi gerçekleştiriyor. Ancak bu fonksiyonun bir problemi var. Dikkatlice bakın:: >>> isimler = ['ahmet', 'çiğdem', 'ışık', 'şebnem', 'zeynep', 'selin'] >>> sorted(isimler) ['ahmet', 'selin', 'zeynep', 'çiğdem', 'ışık', 'şebnem'] Bu fonksiyon, Türkçe karakter içeren öğeleri düzgün sıralayamaz. Bu sorunu *kısmen* çözebilmek için ``locale`` adlı bir modül içindeki ``strxfrm()`` adlı bir fonksiyondan yararlanabilirsiniz:: >>> import locale Henüz modülleri öğrenmemiş de olsak, bir modülü kullanabilmek için öncelikle o modülü 'içe aktarmamız' gerektiğini artık biliyorsunuz. Bu işlemi ``import`` adlı bir komut yardımıyla yaptığımızı da biliyorsunuz. Şimdi de yerelimizi (*locale*) 'Türkçe' olarak ayarlayalım:: >>> locale.setlocale(locale.LC_ALL, 'tr_TR') #GNU/Linux >>> locale.setlocale(locale.LC_ALL, 'Turkish_Turkey.1254') #Windows Bu işlemleri yaptıktan sonra, ``sorted()`` fonksiyonunun `key` adlı bir parametresini kullanarak ve yine ``locale`` modülünün ``strxfrm()`` adlı fonksiyonundan faydalanarak Türkçe karakterler içeren listemizi sıralamayı deneyebiliriz:: >>> sorted(isimler, key=locale.strxfrm) ['ahmet', 'çiğdem', 'ışık', 'selin', 'şebnem', 'zeynep'] ``locale`` modülü içinde bulunan ``strxfrm()`` adlı fonksiyon, karakter dizilerinin, o anda etkin yerel neyse, ona göre muamele görmesini sağlar. Biz yukarıda yerelimizi Türkçe olarak ayarladığımız için ``strxfrm()`` fonksiyonu, ``sorted()`` ile yapılan alfabe sırasına dizme işleminin Türkçenin kurallarına göre yapılmasını sağlıyor. Ancak bu yöntemin de sorunlu olduğunu bir süre sonra kendiniz de farkedeceksiniz. Mesela şu örneği inceleyin:: >>> sorted('afgdhkıi', key=locale.strxfrm) ['a', 'd', 'f', 'g', 'h', 'i', 'ı', 'k'] Gördüğünüz gibi, listede 'i' harfi 'ı' harfinden önce geliyor. Ama aslında bunun tersi olmalıydı. İşte böyle bir durumda, kendi sıralama mekanizmamızı kendimiz icat etmeliyiz. Peki ama nasıl? Bilgisayarlar farklı dillerdeki karakterleri her zaman doğru sıralayamasa da, sayıları her zaman doğru sıralar:: >>> sorted([10, 9, 4, 14, 20]) [4, 9, 10, 14, 20] Bilgisayarların bu özelliğinden ve Python'daki sözlük veri tipinden yararlanarak kendi sıralama mekanizmamızı rahatlıkla icat edebiliriz. Öncelikle harflerimizi yazalım:: >>> harfler = "abcçdefgğhıijklmnoöprsştuüvyz" Burada Türk alfabesini oluşturan harfleri sırasına göre dizdik. Şimdi bu harflerin her birine bir sayı vereceğiz:: >>> çevrim = {'a': 0, 'b': 1, 'c': 2, 'ç': 3, 'd': 4, ... 'e': 5, 'f': 6, 'g': 7, 'ğ': 8, 'h': 9, ... 'ı': 10, 'i': 11, 'j': 12, 'k': 13, ... 'l': 14, 'm': 15, 'n': 16, 'o': 17, ... 'ö': 18, 'p': 19, 'r': 20, 's': 21, ... 'ş': 22, 't': 23, 'u': 24, 'ü': 25, ... 'v': 26, 'y': 27, 'z': 28} Yalnız böyle her harfe karşılık gelen sayıyı elle yazmak yorucu olacaktır. Bu işlemi daha kolay bir şekilde yapabilmek için farklı teknikleri kullanabilirsiniz. Mesela daha önce öğrendiğimiz sözlük üreteçlerinden yararlanabilirsiniz:: >>> çevrim = {i: harfler.index(i) for i in harfler} Bu şekilde `harfler` değişkeni içindeki her bir harfin bir anahtar; bu harflerin `harfler` değişkeni içindeki sırasını gösteren her bir sayının ise bir değer olduğu bir sözlük oluşturmuş olduk. Şimdi isim listemizi alalım karşımıza:: isimler = ["ahmet", "ışık", "ismail", "çiğdem", "can", "şule"] Normal bir ``sorted()`` işleminin yanlış sonuç döndüreceğini biliyoruz:: >>> sorted(isimler) ['ahmet', 'can', 'ismail', 'çiğdem', 'ışık', 'şule'] Aynı şekilde `key` parametresine ``locale.strxfrm`` değerinin verilmesi de yetersiz kalacaktır:: >>> sorted(isimler, key=locale.strxfrm) ['ahmet', 'can', 'çiğdem', 'ismail', 'ışık', 'şule'] Ama biraz önce oluşturduğumuz `çevrim` anahtarını kullanırsak durum bambaşka olacaktır:: >>> sorted(isimler, key=lambda x: çevrim.get(x[0])) ['ahmet', 'can', 'çiğdem', 'ışık', 'ismail', 'şule'] Ancak aslında burada da oldukça sinsi bir problem var. Bu metot ile kelime listesini oluşturan kelimeleri yalnızca ilk harflerine göre sıralıyoruz (``x[0]``). Peki ya aynı liste içinde ilk harfleri aynı olup, sonraki harflerde farklılaşan kelimeler varsa ne olacak? Yani mesela bu metot acaba 'ismail' ve 'iskender' kelimelerini doğru bir şekilde sıralayabilir mi? Bakalım:: harfler = "abcçdefgğhıijklmnoöprsştuüvyz" çevrim = {i: harfler.index(i) for i in harfler} isimler = ["ahmet", "ışık", "ismail", "çiğdem", "can", "şule", "iskender"] print(sorted(isimler, key=lambda x: çevrim.get(x[0]))) Buradan şu çıktıyı alıyoruz:: ['ahmet', 'can', 'çiğdem', 'ışık', 'ismail', 'iskender', 'şule'] Gördüğünüz gibi 'ismail' ve 'iskender' kelimeleri doğru bir şekilde sıralanmadı; 'iskender' kelimesinin 'ismail' kelimesinden önce gelmesi gerekiyordu... Demek ki şimdiye kadar kullandığımız bütün sıralama yöntemlerinin bir eksiği varmış. O halde başka bir metot bulmaya çalışalım. Dikkatlice bakın:: harfler = 'abcçdefgğhıijklmnoöprsştuüvyz' çevrim = {i: harfler.index(i) for i in harfler} def sırala(kelime): return ([çevrim.get(kelime[i]) for i in range(len(kelime))]) isimler = ['ahmet', 'can', 'iskender', 'cigdem', 'ismet', 'ismail', 'ismit', 'çiğdem', 'ismıt', 'ışık', 'şule'] print(*sorted(isimler, key=sırala), sep='\n') Gelin bu kodları biraz inceleyelim. Burada ilk gördüğümüz kodlar şunlar:: harfler = 'abcçdefgğhıijklmnoöprsştuüvyz' çevrim = {i: harfler.index(i) for i in harfler} Esasında siz bu kodların anlamını biliyorsunuz. Önceki derslerimizde de aynı kodları birkaç kez kullanmıştık. Yalnız biz burada, örnek olması açısından, `harfler` değişkeni için değer olarak yalnızca küçük harfleri kullandık. Bu kodları daha kapsamlı bir program içinde kullanacaksanız bu değişkenin uygun yerlerine mesela büyük harfleri ve noktalama işaretleriyle sayıları da eklemek isteyebilirsiniz. Sonraki satırlarda ``sırala()`` adlı bir fonksiyon tanımladık:: def sırala(kelime): return ([çevrim.get(kelime[i]) for i in range(len(kelime))]) Burada liste üreteçlerinden yararlandığımıza dikkatinizi çekmek isterim:: [çevrim.get(kelime[i]) for i in range(len(kelime))] Bu kod yardımıyla `kelime` içinde geçen her bir harfi `çevrim` adlı sözlükte sorgulayarak, sözlükte ilgili harfe karşılık gelen sayıyı buluyoruz. Aslında bu kodları daha iyi anlayabilmek için Python'daki ``sorted()`` fonksiyonunun mantığını biraz daha derinlemesine incelememiz gerekiyor. Gelin şimdi bu inceleme işini yapalım: Diyelim ki elimizde şöyle bir liste var:: elemanlar = [('ahmet', 33, 'karataş'), ('mehmet', 45, 'arpaçbahşiş'), ('sevda', 24, 'arsuz'), ('arzu', 40, 'siverek'), ('abdullah', 30, 'payas'), ('ilknur', 40, 'kilis'), ('abdurrezzak', 40, 'bolvadin')] Bu liste, her biri 'isim', 'yaş' ve 'memleket' bilgilerini içeren üç öğeli birer demetten oluşuyor. Eğer biz bu liste üzerine ``sorted()`` fonksiyonunu uygularsak:: print(*sorted(elemanlar), sep='\n') Python elemanları demetlerin ilk öğesine göre sıralayacaktır. Yani isme göre. Peki ya biz bu elemanları yaşa göre sıralamak istersek ne yapacağız? Bu amacı gerçekleştirmek için şöyle bir kod yazabiliriz:: def sırala(liste): return liste[1] elemanlar = [('ahmet', 33, 'karataş'), ('mehmet', 45, 'arpaçbahşiş'), ('sevda', 24, 'arsuz'), ('arzu', 40, 'siverek'), ('abdullah', 30, 'payas'), ('ilknur', 40, 'kilis'), ('abdurrezzak', 40, 'bolvadin')] print(*sorted(elemanlar, key=sırala), sep='\n') Bu örnek bize `key` parametresinin de ne işe yaradığını açık seçik gösteriyor. Eğer Python'ın kendi sıralama yönteminin dışında bir sıralama yöntemi uygulayacaksak, bu sıralama yönteminin ne olduğunu bir fonksiyon yardımıyla tarif edip bunu `key` parametresine değer olarak veriyoruz. Örneğin biz yukarıdaki Python'ın `elemanlar` adlı listeyi ilk sütuna ('isim' sütunu) göre değil, ikinci sütuna ('yaş' sütunu) göre sıralamasını istedik. Bunun için de şöyle bir fonksiyon yazdık:: def sırala(liste): return liste[1] Bu fonksiyon, kendisine parametre olarak verilen nesnenin ikinci öğesini döndürüyor. İşte biz ``sorted()`` fonksiyonunun `key` parametresine bu fonksiyonu verdiğimizde Python sıralama işleminde `elemanlar` listesinin ikinci öğesini dikkate alacaktır. Eğer Python'ın sıralama işleminde mesela üçüncü sütunu dikkate almasını isterseniz ``sırala()`` fonksiyonunu şöyle yazabilirsiniz:: def sırala(liste): return liste[2] Gördüğünüz gibi, `elemanlar` listesinin ikinci sütununda değeri aynı olan öğeler var. Mesela 'arzu', 'ilknur' ve 'abdurrezzak' 40 yaşında. Python bu öğeleri sıralarken, bunların listede geçtiği sırayı dikkate alacaktır. Ama bazen biz sıralamanın böyle olmasını istemeyebiliriz. Mesela bizim istediğimiz şey, değeri aynı olan öğeler için üçüncü sütunun (veya birinci sütunun) dikkate alınması olabilir. İşte bunun için de ``sırala()`` fonksiyonunu şu şekilde tanımlayabiliriz:: def sırala(liste): return (liste[1], liste[2]) Gördüğünüz gibi burada ``sırala()`` fonksiyonu bize iki öğeli bir demet döndürüyor. Kodlarımız tam olarak şöyle görünecek:: def sırala(liste): return (liste[1], liste[2]) elemanlar = [('ahmet', 33, 'karataş'), ('mehmet', 45, 'arpaçbahşiş'), ('sevda', 24, 'arsuz'), ('arzu', 40, 'siverek'), ('abdullah', 30, 'payas'), ('ilknur', 40, 'kilis'), ('abdurrezzak', 40, 'bolvadin')] print(*sorted(elemanlar, key=sırala), sep='\n') Kodlarımızı böyle yazdığımızda Python listeyi ilk olarak ikinci sütundaki 'yaş' değerlerine göre sıralar. Değeri aynı olan öğelerle karşılaştığında ise üçüncü sütundaki 'memleket' değerlerine bakar ve sıralamayı ona göre yapar. Bütün bu açıklamalardan sonra yukarıdaki şu kodları daha iyi anlıyor olmalısınız:: harfler = 'abcçdefgğhıijklmnoöprsştuüvyz' çevrim = {i: harfler.index(i) for i in harfler} def sırala(kelime): return ([çevrim.get(kelime[i]) for i in range(len(kelime))]) isimler = ['ahmet', 'can', 'iskender', 'cigdem', 'ismet', 'ismail', 'ismit', 'çiğdem', 'ismıt', 'ışık', 'şule'] print(*sorted(isimler, key=sırala), sep='\n') Biz yine de her şeyin iyiden iyine anlaşıldığından emin olmak için durumu kısaca açıklayalım. Öncelikle ilgili fonksiyonu önümüze alalım:: def sırala(kelime): return ([çevrim.get(kelime[i]) for i in range(len(kelime))]) Burada yaptığımız şey biraz önce yaptığımız şeyle tamamen aynı aslında. Tek fark, Python'ın sıralamada kullanmasını istediğimiz öğeleri tek tek elle yazmak yerine, bunları bir liste üreteci yardımıyla otomatik olarak belirlemek. Eğer yukarıdaki kodları şöyle yazsaydık:: def sırala(kelime): return (çevrim.get(kelime[0])) Bu durumda Python sıralamada kelimelerin yalnızca ilk harflerini dikkate alacaktı. İlk harfi aynı olan kelimeleri ise bu yüzden düzgün sıralayamayacaktı. Elbette Python'ın önce ilk harfe, sonra ikinci harfe, sonra da üçüncü harfe bakmasını sağlayabiliriz:: def sırala(kelime): return (çevrim.get(kelime[0]), çevrim.get(kelime[1]), çevrim.get(kelime[2])) Ancak bu yöntemin uygulanabilir ve pratik olmadığı ortada. Kendi kendinize bazı denemeler yaparak bunu kendiniz de rahatlıkla görebilirsiniz. Python'ın, sıralama yaparken kelimelerin önce ilk harflerini, sonra ikinci, sonra üçüncü, vb. harflerini karşılaştırmasını sağlamanın en uygun yolu şu olacaktır:: def sırala(kelime): return ([çevrim.get(kelime[i]) for i in range(len(kelime))]) Gördüğünüz gibi, burada kelimelerdeki harflerin sırasını tek tek elle yazmak yerine, bunu bir ``for`` döngüsü içinde otomatik olarak yaptırıyoruz. Dolayısıyla ``sırala()`` fonksiyonuna verilen parametrenin mesela `ahmet` olduğu bir durumda yukarıdaki fonksiyon şu demeti döndürüyor:: def sırala('ahmet'): return (çevrim.get('ahmet'[0]), çevrim.get('ahmet'[1]), çevrim.get('ahmet'[2]), çevrim.get('ahmet'[3]), çevrim.get('ahmet'[4])) Mesela 'can' için ise şunu:: def sırala('can'): return (çevrim.get('can'[0]), çevrim.get('can'[1]), çevrim.get('can'[2])) Böylece Python, hangi uzunlukta bir isimle karşılaşırsa karşılaşsın, sıralama işlemini düzgün bir şekilde gerçekleştirebiliyor. Bu bölümde Python'da sıralama konusunu epey ayrıntılı bir şekilde ele aldık. .. note:: 'Sıralama' konusuna ilişkin bir tartışma için https://web.archive.org/web/20161017211231/www.istihza.com/forum/viewtopic.php?f=25&t=1523 adresindeki konuyu inceleyebilirsiniz. slice() ********** Bildiğiniz gibi, birtakım öğelerden oluşan bir nesnenin yalnızca belli kısımlarını ayırıp alma işlemine 'dilimleme' adı veriliyor. Örneğin elimizde şöyle bir liste olduğunu düşünelim:: >>> l = ['ahmet', 'mehmet', 'ayşe', 'senem', 'salih'] 5 öğeli bu listenin yalnızca ilk iki öğesini almak, yani dilimlemek için şu yapıyı kullanıyoruz:: >>> l[0:2] ['ahmet', 'mehmet'] Dilimleme işleminin şöyle bir formülden oluştuğunu biliyoruz:: l[başlangıç:bitiş:atlama_değeri] Başlangıç parametresinin öntanımlı değeri `0` olduğu için yukarıdaki kodu şöyle de yazabilirdik:: >>> l[:2] ['ahmet', 'mehmet'] Aynı listenin, ilk öğeden itibaren sonuna kadar olan bütün öğelerini almak için ise şunu yazıyoruz:: >>> l[1:] Eğer bu listeyi, öğelerini ikişer ikişer atlayarak dilimlemek istersek de şu yolu takip ediyoruz:: >>> l[::2] ['ahmet', 'ayşe', 'salih'] Bu örnekte başlangıç ve bitiş parametrelerinin öntanımlı değerlerini kullandık. O yüzden o kısımları boş bıraktık. Öğeleri ikişer ikişer atlayabilmek için ise atlama_değeri olarak `2` sayısını kullandık. İşte yukarıdakine benzer dilimleme işlemleri için ``slice()`` adlı bir gömülü fonksiyondan da yararlanabiliriz. Dikkatlice bakın: Listemiz şu:: >>> l = ['ahmet', 'mehmet', 'ayşe', 'senem', 'salih'] Bir 'dilimleme' (*slice*) nesnesi oluşturuyoruz:: >>> dl = slice(0, 3) Bu nesneyi liste üzerine uyguluyoruz:: >>> l[dl] ['ahmet', 'mehmet', 'ayşe'] Gördüğünüz gibi, ``slice()`` fonksiyonunu yukarıda iki parametre ile kullandık. Tahmin edebileceğiniz gibi, bu fonksiyonunu formülü şu şekildedir:: slice(başlangıç, bitiş, atlama) sum() ********** Bu fonksiyonun temel görevi, bir dizi içindeki değerlerin toplamını bulmaktır. Örneğin:: >>> l = [1, 2, 3] >>> sum(l) 6 Bu fonksiyon genellikle yukarıdaki gibi tek parametreyle kullanılır. Ama aslında bu fonksiyon ikinci bir parametre daha alır. Dikkatlice bakın:: >>> l = [1, 2, 3] >>> sum(l, 10) 16 Gördüğünüz gibi, Python ``sum()`` fonksiyonuna verilen ikinci parametreyi, birinci parametredeki toplam değerin üzerine ekliyor. type() ********** ``type()`` fonksiyonunun görevi bir nesnenin hangi veri tipine ait olduğunu söylemektir. Bu fonksiyonu artık yakından tanıyorsunuz:: >>> type('elma') zip() ********** Gelin isterseniz bu fonksiyonu bir örnek üzerinden açıklamaya çalışalım. Diyelim ki elimizde şöyle iki farklı liste var:: >>> a1 = ['a', 'b', 'c'] >>> a2 = ['d', 'e', 'f'] Eğer bu listelerin öğelerini birbirleriyle eşleştirmek istersek ``zip()`` fonksiyonundan yararlanabiliriz. Dikkatlice bakın:: >>> zip(a1, a2) Gördüğünüz gibi, yukarıdaki kod bize bir 'zip' nesnesi veriyor. Bu nesnenin öğelerine nasıl ulaşabileceğinizi biliyorsunuz:: >>> print(*zip(a1, a2)) ('a', 'd') ('b', 'e') ('c', 'f') >>> list(zip(a1, a2)) [('a', 'd'), ('b', 'e'), ('c', 'f')] >>> for a, b in zip(a1, a2): ... print(a, b) ... a d b e c f Yukarıdaki çıktıları incelediğimizde, ilk listenin ilk öğesinin, ikinci listenin ilk öğesiyle; ilk listenin ikinci öğesinin, ikinci listenin ikinci öğesiyle; ilk listenin üçüncü öğesinin ise, ikinci listenin üçüncü öğesiyle eşleştiğini görüyoruz. Bu özellikten pek çok farklı şekilde yararlanabilirsiniz. Örneğin:: >>> isimler = ['ahmet', 'mehmet', 'zeynep', 'ilker'] >>> yaşlar = [25, 40, 35, 20] >>> for i, y in zip(isimler, yaşlar): ... print('isim: {} / yaş: {}'.format(i, y)) ... isim: ahmet / yaş: 25 isim: mehmet / yaş: 40 isim: zeynep / yaş: 35 isim: ilker / yaş: 20 Burada `isimler` ve `yaşlar` adlı listelerin öğelerini ``zip()`` fonksiyonu yardımıyla birbirleriyle eşleştirdik. vars() ********** Bu fonksiyon, mevcut isim alanı içindeki metot, fonksiyon ve nitelikleri listeler. Eğer bu fonksiyonu parametresiz olarak kullanırsak, daha önce gördüğümüz ``locals()`` fonksiyonuyla aynı çıktıyı elde ederiz:: >>> vars() {'__builtins__': , '__name__': '__main__', '__package__': None, '__loader__': , '__doc__': None} Bu fonksiyonu, nesnelerin metotlarını ve niteliklerini öğrenmek için de kullanabilirsiniz:: >>> vars(str) >>> vars(list) >>> vars(dict) Yukarıda sırasıyla karakter dizilerinin, listelerin ve sözlüklerin metotlarını listeledik. Bu yönüyle ``vars()`` fonksiyonu ``dir()`` fonksiyonuna benzer. Böylece Python'daki gömülü fonksiyonları tek tek incelemiş olduk. Bu bölümde incelemediğimiz gömülü fonksiyonlar şunlar: #. ``memoryview`` #. ``iter`` #. ``next`` #. ``object`` #. ``property`` #. ``staticmethod`` #. ``super`` #. ``getattr`` #. ``hasattr`` #. ``delattr`` #. ``classmethod`` #. ``issubclass`` #. ``setattr`` #. ``__import__`` Bu fonksiyonları, ilerleyen derslerle birlikte Python bilgimiz biraz daha arttığında ele alacağız.