Modüller

Bu bölümde Python’daki en önemli konulardan biri olan modüllerden söz edeceğiz. Ancak modülleri kullanabilmek için tabii ki öncelikle “modül” denen şeyin ne olduğunu anlamamız gerekiyor.

Şöyle düşünün: Diyelim ki bir program yazıyorsunuz. Yazdığınız bu programın içinde karakter dizileri, sayılar, değişkenler, listeler, demetler, sözlükler, kümeler ve fonksiyonlar var. Programınız da .py uzantılı bir metin dosyası içinde yer alıyor. İşte bütün bu öğeleri ve veri tiplerini içeren .py uzantılı dosyaya modül adı verilir. Bu bilgiye göre, şimdiye kadar yazdığınız ve bundan sonra yazacağınız bütün Python programları aynı zamanda birer modüldür.

Peki, bu bilginin bize ne faydası var? Ya da şöyle soralım: Yazdığımız bir Python programının modül olması neden bu kadar önemli?

Hatırlarsanız bir önceki bölümde Python’daki fonksiyonlardan bahsetmiştik. Yine hatırlarsanız o bölümde carp() adlı bir fonksiyon da tanımlamıştık. Bu fonksiyonu kullanabilmek için ne yapmamız gerektiğini biliyorsunuz. carp() fonksiyonuna ihtiyacımız olduğunda bu fonksiyonu çağırmamız yeterli oluyor. Şimdi şöyle bir düşünelim: Biz bu carp() fonksiyonuna ihtiyacımız olduğunda fonksiyonu çağırmak yoluyla aynı program içinde kullanabiliyoruz. Peki ya aynı fonksiyona başka bir Python programında da ihtiyacımız olursa ne yapacağız? O fonksiyonu kopyalayıp öbür Python programına yapıştıracak mıyız? Tabii ki hayır! Kodları alıp oradan oraya kopyalamak programcılık tecrübeniz açısından hiç de verimli bir yöntem değildir. Üstelik doğası gereği “kopyala-yapıştır” tekniği hatalara oldukça açık bir yoldur. Biz herhangi bir Python programında bulunan herhangi bir fonksiyona (veya niteliğe) ihtiyaç duyduğumuzda o fonksiyonu (veya niteliği) programımıza “aktaracağız”. Peki, bunu nasıl yapacağız?

Dediğimiz gibi bütün Python programları aynı zamanda birer modüldür. Bu özellik sayesinde Python programlarında bulunan fonksiyon ve nitelikler başka Python programları içine aktarılabilirler. Böylece bir Python programındaki işlevsellikten, başka bir Python programında da yararlanabilirsiniz.

İşte bu bölümde, bütün bu işlemleri nasıl yapacağımızı öğreneceğiz. Dilerseniz lafı daha fazla dolandırmadan modüller konusuna hızlı bir giriş yapalım.

Modüllerin Çeşitleri

Python’da modüller çeşit çeşittir. Temel olarak Python’da üç çeşit modülden söz edilebilir:

  1. Kendi Yazdığınız Modüller
  2. Geliştiricilerin Yazdığı Modüller
  3. Üçüncü Şahısların Yazdığı Modüller

Kendi yazdığınız modüller, adından da anlaşılacağı gibi, bir Python programcısı olarak oturup sizin yazdığınız modüllerdir.

Geliştiricilerin yazdığı modüller, sizin modüllerinizin aksine Python geliştiricileri tarafından yazılıp Python programlama diline entegre edilmiş olan ve bu bakımdan dilin bir parçası olan modüllerdir.

Üçüncü şahısların yazdığı modüller, genellikle internet üzerindeki kaynaklardan edinebileceğiniz, Python programcıları tarafından hazırlanıp herkesin kullanımına sunulmuş olan modüllerdir.

Biz bu bölümde, yukarıda saydığımız üç modül türünü de olabildiğince ayrıntılı bir şekilde incelemeye çalışacağız. Dilerseniz öncelikle kendi yazdığımız modüllerden başlayalım...

Kendi Yazdığınız Modüller

Yukarıda da tanımladığımız gibi, kendi yazdığınız modüller, birer Python programcısı olarak oturup sizin yazdığınız Python programlarıdır. Mesela bir program yazdınız ve adını da deneme.py koydunuz. Bu programın içeriği şöyle olsun:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def carp(liste):
    a = 1
    for i in liste:
        a = a * i
    print a

İşte deneme.py adlı bu Python programı bir modüldür ve bu modül, carp() adlı tek bir fonksiyondan oluşur. Elbette modüller tek bir fonksiyondan ibaret olmak zorunda değildir. Bir modül pek çok farklı fonksiyondan oluşabilir. Örneğin:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def carp(liste):
    a = 1
    for i in liste:
        a = a * i
    return a

def bol(bolen, bolunen, hassas=True):
    sonuc = bolen / float(bolunen)

    if hassas:
        return float(sonuc)

    if not hassas:
        return int(sonuc)

def topla(*args):
    toplam = 0
    for i in args:
        toplam += i

    return toplam

def cikar(bir, iki):
    return iki - bir

Burada dört farklı fonksiyona sahip bir modül tanımladık. Dilerseniz bu modülü masaüstüne aritmetik.py adıyla kaydedelim.

Bu noktada Modül nedir? sorusunu tekrar sormakta fayda var. Bu bölümün en başında yaptığımız tanıma göre, carp(), bol(), topla() ve cikar() fonksiyonlarını içeren yukarıdaki aritmetik.py adlı program bir modüldür. Bu modülün adı da aritmetik‘tir. Python’da modüller (genellikle) .py uzantısına sahiptir. Ancak bir modülün adı söylenirken bu .py uzantısı es geçilir ve sadece isim kısmı dikkate alınır. Bu yüzden elinizdeki aritmetik.py adlı program aritmetik modülü olarak adlandırılacaktır.

Dediğimiz gibi, bu modül içinde toplam dört adet fonksiyon var. Biz bu fonksiyonları aynı modül içinde rahatlıkla kullanabiliriz. Mesela cikar() fonksiyonuna ihtiyacımız olduğunda yapmamız gereken tek şey bu fonksiyonu çağırmaktır:

print cikar(1545, 1432)

Veya topla() fonksiyonuna gereksinim duyarsak, yine bu fonksiyonu çağırmak çok kolaydır:

print topla(3, 15, 43, 23, 88)

Peki ya bu fonksiyonlara başka bir programda da ihtiyaç duyarsak ne olacak? Böyle bir durumda yapacağımız şey bu fonksiyonu o program içinden çağırmak olacak. Ancak bunu yapmanın belli kuralları var. Peki, nedir bu kurallar? İşte şimdi bu kuralların ne olduğunu inceleyeceğiz...

Modülleri İçe Aktarmak

Bu bölümün başında şöyle bir cümle sarfetmiştik:

Herhangi bir Python programında bulunan herhangi bir fonksiyona (veya niteliğe) ihtiyaç duyduğumuzda o fonksiyonu (veya niteliği) programımıza aktarabiliriz.

Python’da bir modülü başka bir programa taşıma işlemine içe aktarma adı verilir. İngilizce’de ise bu işleme import deniyor.

Şimdi yukarıda aritmetik.py adıyla kaydettiğimiz dosyanın bulunduğu dizin içinde bir komut satırı açıp Python’un etkileşimli kabuğunu çalıştırın. Mesela eğer aritmetik.py dosyasını masaüstüne kaydettiyseniz bir komut satırı açın, cd Desktop komutuyla masaüstüne gelin ve orada python komutunu vererek etkileşimli kabuğu başlatın. Şimdi şu komutu verin:

>>> import aritmetik

Eğer hiçbir şey olmadan bir alt satıra geçildiyse modülünüzü başarıyla içe aktardınız demektir. Eğer şöyle bir hata çıktısıyla karşılaşıyorsanız, muhtemelen Python’u masaüstünün olduğu dizinde başlatamamışsınızdır:

>>> import aritmetik
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named aritmetik

import aritmetik komutunun başarılı olduğunu varsayarak yolumuza devam edelim...

Modülü içe aktardıktan sonra dir() adlı özel bir fonksiyondan yararlanarak, içe aktardığımız bu modül içindeki kullanılabilir fonksiyon ve nitelikleri görebileceğimizi biliyorsunuz:

>>> dir(aritmetik)

Bu komut bize şöyle bir çıktı verir:

['__builtins__', '__doc__', '__file__', '__name__',
'__package__', 'bol', 'carp', 'cikar', 'topla']

Burada bizi ilgilendiren kısım bol, carp, cikar ve topla adlı öğeler. Bu çıktıdan anlıyoruz ki, aritmetik adlı modülün içinde bol, carp, cikar ve topla adlı fonksiyonlar var ve biz bu fonksiyonları kullanma imkânına sahibiz. O halde gelin mesela bu modül içindeki carp() adlı fonksiyonu kullanabilmek için sırasıyla şöyle bir şeyler yazalım:

>>> liste = [45, 66, 76, 12]
>>> aritmetik.carp(liste)

Bu komutlar şöyle bir çıktı verir:

2708640

Gördüğünüz gibi, aritmetik modülü içindeki carp() adlı fonksiyonu kullanarak “liste” içindeki sayıları birbiriyle çarptık. aritmetik modülünü nasıl içe aktardığımıza ve bu modülün içindeki bir fonksiyon olan carp() fonksiyonunu nasıl kullandığımıza çok dikkat edin. Önce modülümüzün adı olan “aritmetik”i yazıyoruz. Ardından bir nokta işareti koyup, ihtiyacımız olan fonksiyonun adını belirtiyoruz. Yani şöyle bir formül takip ediyoruz:

modül_adı.fonksiyon

Böylece modül içindeki fonksiyona erişmiş olduk. Yalnız burada asla unutmamamız gereken şey öncelikle kullanacağımız modülü import modül_adı komutuyla içe aktarmak olacaktır. Modülü içe aktarmazsak tabii ki o modüldeki fonksiyon veya niteliklere erişemeyiz.

Şimdi aritmetik.py adlı dosyanızı açıp dosyanın en başına şu kodu ekleyin:

pi_sayisi = 22/7.0

Yani aritmetik.py dosyasının son hali şöyle olsun:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

pi_sayisi = 22/7.0

def carp(liste):
    a = 1
    for i in liste:
        a = a * i
    return a

def bol(bolen, bolunen, hassas=True):
    sonuc = bolen / float(bolunen)

    if hassas:
        return float(sonuc)

    if not hassas:
        return int(sonuc)

def topla(*args):
    toplam = 0
    for i in args:
        toplam += i

    return toplam

def cikar(bir, iki):
    return iki - bir

Şimdi tekrar komut satırına dönüp şu komutu verin:

dir(aritmetik)

Bu komut biraz öncekiyle aynı çıktıyı verecektir. Halbuki biz modülümüze pi_sayisi adlı bir değişken daha ekledik. O halde neden bu değişken listede görünmüyor?

Python’da bir modülü komut satırında içe aktardıktan sonra eğer o modülde bir değişiklik yaparsanız, o değişikliğin etkili olabilmesi için modülü yeniden yüklemeniz gerekir. Bu işlemi reload() adlı özel bir fonksiyon yardımıyla yapıyoruz:

>>> reload(aritmetik)

Bu komut şöyle bir çıktı verir:

<module 'aritmetik' from 'aritmetik.py'>

Bu çıktı modülün başarıyla yeniden yüklendiğini gösteriyor. Şimdi dir(aritmetik) komutunu tekrar verelim:

>>> dir(aritmetik)

Bu defa listede bol, carp, cikar ve topla öğeleriyle birlikte pi_sayisi öğesini de göreceksiniz. Dolayısıyla artık bu öğeye de erişebilirsiniz:

>>> aritmetik.pi_sayisi

3.1428571428571428

Eh, yarım yamalak da olsa pi sayısını elde etmiş olduk!..

Buraya kadar modülleri hep etkileşimli kabukta içe aktardık. Ama tabii ki önemli olan bir modülü başka bir python programı içinden çağırabilmektir. İsterseniz şimdi bir modülü başka bir Python programı içinden nasıl çağırabileceğimizi öğrenelim.

Şimdi masaüstünde test.py adlı bir dosya oluşturun ve Kwrite, Kate, Gedit veya IDLE adlı metin düzenleyicilerden birini kullanarak bu dosyayı açın. Dosyaya şu satırları yazın:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import aritmetik

İlk iki satır zaten demirbaş. Burada önemli olan satır import aritmetik. Bu satırla, yine masaüstünde kayıtlı bulunan aritmetik.py adlı programı, yani aritmetik modülünü içe aktardık. Bu modülü içe aktardığımıza göre, artık bu modülün içindeki bütün fonksiyon ve nitelikleri kullanabiliriz. O halde yazmaya devam edelim:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import aritmetik

print aritmetik.cikar(1455, 32)

Yazdığımız son satırda, aritmetik modülünün içinde yer alan cikar() adlı fonksiyonu kullanmış olduk. Böylece daha önce bir kez tanımladığımız cikar() adlı fonksiyona başka bir Python programında da ihtiyaç duyduğumuzda, bu fonksiyonu tekrar yazmak zorunda kalmadan, gerekli fonksiyonu barındıran modülü programımız içine aktararak (import) işimizi hallettik. Aynı şekilde aritmetik modülü içindeki öbür fonksiyonları ve nitelikleri de kullanabilirsiniz. Mesela modül içinde yer alan pi_sayisi niteliğini de kullanabiliriz:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import aritmetik

print aritmetik.cikar(1455, 32)

print "pi sayısının değeri: %s" %aritmetik.pi_sayisi

Şimdi bu test.py adlı programı çalıştırın ve nasıl bir sonuç aldığınızı inceleyin.

Modülleri İçe Aktarma Yöntemleri

Python’da programımız içinde kullanacağımız modülleri birkaç farklı yöntemle içe aktarabiliriz. Biz şimdiye kadar sadece import modül_adı yöntemini öğrendik. Hemen kısaca bu yöntemleri inceleyelim:

import modül_adı

Bu yöntemle bir modülü, bütün içeriğiyle birlikte içe aktarabiliriz. Başka bir deyişle bir modülün içinde ne var ne yoksa programımız içine davet edebiliriz. Yukarıda kullandığımız da zaten bu yöntemdir.

from modül_adı import *

Bu yöntemle bir modül içinde adı “__” ile başlayanlar hariç bütün fonksiyonları programımız içine aktarabiliriz. Yani bu yöntem de tıpkı yukarıda anlatılan yöntemde olduğu gibi, bütün fonksiyonları alacaktır. Yalnız “__” ile başlayan fonksiyonlar hariç...

Eğer bir modülü bu yöntemi kullanarak içe aktarmışsanız, içe aktardığımız modülün nitelik ve fonksiyonlarına doğrudan nitelik veya fonksiyon adını kullanarak erişebilirsiniz. Örneğin import modül_adı yöntemiyle içe aktardığımız modüllerin nitelik ve fonksiyonlarını şöyle kullanıyorduk:

>>> modül_adı.fonksiyon

from modül_adı import * yöntemiyle içe aktardığımız modüllerin nitelik ve fonksiyonlarını ise şöyle kullanıyoruz:

>>> fonksiyon

Mesela yukarıda bahsettiğimiz aritmetik modülünü örnek alalım:

>>> from aritmetik import *

>>> liste = [2, 3, 4]

>>> print carp(liste)

24

Gördüğünüz gibi, bu defa aritmetik.carp(liste) gibi bir komut vermedik. carp() fonksiyonunu doğrudan kullanabildik. Bu yöntem oldukça pratiktir. Programcıya aynı işi daha az kodla yapma imkânı sağlar. Ancak bu yöntemin bazı sakıncaları vardır. Bunlara biraz sonra değineceğiz.

from modül_adı import falanca, filanca

Bu yöntem ise bir modülden falanca ve filanca adlı fonksiyonları çağırmamızı sağlayacaktır. Yani bütün içeriği değil, bizim istediğimiz fonksiyonları içe aktarmakla yetinecektir. Örneğin:

>>> from aritmetik import carp

Bu şekilde aritmetik modülünün yalnızca carp() fonksiyonunu içe aktarmış olduk. Bu şekilde carp() fonksiyonuna erişebiliriz:

>>> liste = [2, 3, 4]

>>> print carp(liste)

24

Ama pi_sayisi niteliğine erişemeyiz. Çünkü biz burada sadece carp() fonksiyonunu içe aktardık. Eğer pi_sayisi niteliğine de erişebilmek istersek modülümüzü şu şekilde içe aktarmamız gerekir:

>>> from deneme import carp, pi_sayisi

Bu şekilde hem carp() fonksiyonunu, hem de pi_sayisi niteliğini içe aktarmış olduk.

import modül_adı as yeni_isim

Diyelim ki herhangi bir sebepten, modülün adını programınız içinde doğrudan kullanmak istemiyorsunuz. O zaman bu yöntemi kullanarak modüle farklı bir ad verebilirsiniz:

>>> import aritmetik as arit

>>> liste = [2, 3, 4]

>>> arit.carp(liste)

Mesela içe aktaracağınız modül adı çok uzunsa ve her defasında bu uzun ismi yazmak size zor geliyorsa bu yöntemi kullanarak modül adını kısaltabilirsiniz. Ayrıca programınızda zaten aritmetik adlı başka bir nitelik veya fonksiyon varsa bu ikisinin birbirine karışmasını engellemek için de bu yöntemi kullanmayı tercih edebilirsiniz.

Peki bu yöntemlerden hangisini kullanmak daha iyidir? Eğer ne yaptığınızdan tam olarak emin değilseniz veya o modülle ilgili bir belgede farklı bir yöntem kullanmanız önerilmiyorsa, anlatılan birinci yöntemi kullanmak her zaman daha güvenlidir (import modül_adı). Çünkü bu şekilde bir fonksiyonun nereden geldiğini karıştırma ihtimaliniz ortadan kalkar. Mesela aritmetik.carp(liste) gibi bir komuta baktığınızda carp() fonksiyonunun aritmetik adlı bir modül içinde olduğunu anlayabilirsiniz. Ama sadece carp(liste) gibi bir komutla karşılaştığınızda bu fonksiyonun program içinde mi yer aldığını, yoksa başka bir modülden mi içe aktarıldığını anlayamazsınız. Ayrıca mesela programınız içinde zaten carp() adlı bir fonksiyon varsa, aritmetik adlı modülden carp() fonksiyonunu aldığınızda isim çakışması nedeniyle hiç istemediğiniz sonuçlarla karşılaşabilirsiniz. Buna bir örnek verelim. Komut satırında şöyle bir kod yazın:

>>> pi_sayisi = 46

Şimdi aritmetik adlı modülü şu yöntemle içe aktarın:

>>> from aritmetik import *

Bakın bakalım pi_sayisi değişkeninin değeri ne olmuş?

>>> print pi_sayisi

3.1428571428571428

Gördüğünüz gibi, aritmetik modülündeki pi_sayisi niteliği sizin kendi programınızdaki pi_sayisi değişkenini silip attı. Herhalde böyle bir şeyin başınıza gelmesini istemezsiniz. O yüzden içeriğini bilmediğiniz modülleri içe aktarırken import modül_adı yöntemini kullanmak sizi büyük baş ağrılarından kurtarabilir.

Geliştiricilerin Yazdığı Modüller

Buraya kadar kendi kendimize nasıl Python modülü yazacağımızı ve yazdığımız bu modülleri nasıl kullanacağımızı gördük. Ama modül çeşitlerinden bahsederken de söylediğimiz gibi, Python sadece kendi modüllerimizi yazmamıza izin vermez. Bir de hazır yazılmış modüller vardır. Python programlama dili içinde çok sayıda modül kullanıma hazır bir şekilde bizi bekler. Python modüllerinin listesine http://docs.python.org/modindex.html adresinden erişebilirsiniz. Biz bu bölümde, os adlı bir modül üzerinden, size geliştiricilerin yazdığı modülleri tanıtmaya çalışacağız.

os Modülü

os adlı modül Python’daki en önemli modüllerden biridir. Bu bölümün en başında yaptığımız modül tanımını dikkate alacak olursak, aslında os modülü, bilgisayarımızda bulunan os.py adlı bir Python programıdır. Peki biz bu os.py programını nereden bulabiliriz. GNU/Linux sistemlerinde bu modül çoğunlukla /usr/lib/python2.6/ dizini içinde bulunur. Windows sistemlerinde ise bu modülü bulmak için C:/Python26/Lib adlı dizinin içine bakabilirsiniz.

os.py dosyasını açıp içine baktığınızda, aslında bu dosyanın birtakım fonksiyon ve niteliklerden oluşan alelade bir Python programı olduğunu göreceksiniz. Bu dosyanın sizin yazdığınız Python programlarından hiç bir farkı yoktur. Kendi yazdığınız modüller içindeki fonksiyonları, modülü içe aktarmak suretiyle nasıl kullanıyorsanız, os modülünü de aynen öyle içe aktarıp bunun içindeki fonksiyon ve nitelikleri kullanacaksınız.

os modülü bize, işletim sistemleriyle ilgili işlemler yapma olanağı sunar. Bu modüle ilişkin resmi (İngilizce) belgelere http://docs.python.org/library/os.html adresinden erişebilirsiniz. Modülün kendi belgelerinde belirtildiğine göre, bu modülü kullanan programların farklı işletim sistemleri üzerinde çalışma şansı daha fazladır. Bunun neden böyle olduğunu biraz sonra daha iyi anlayacaksınız.

Bu modülü, tıpkı kendi yazdığımız modülleri içe aktarıyormuşuz gibi aktaracağız:

>>> import os

Gördüğünüz gibi, kullanım olarak kendi yazdığımız bir modülü nasıl içe aktarıyorsak os modülünü de aynen öyle içe aktarıyoruz. Neticede bu modülü siz de yazmış olabilirdiniz. Dolayısıyla, içeriği dışında, bu modülün sizin yazdığınız herhangi bir Python programından (başka bir söyleyişle “Python modülünden”) hiç bir farkı yoktur. Tabii bu modülün sizin yazdığınız modülden önemli bir farkı, komut satırını hangi dizin altında açmış olursanız olun os modülünü içe aktarabilmenizdir. Yani bu modülü kullanabilmek için os.py dosyasının bulunduğu dizine gitmenize gerek yok. Bunun neden böyle olduğunu biraz sonra açıklayacağız. O yüzden bunu şimdilik dert etmeyin. Neyse, biz konumuza dönelim...

Burada en önemli konu, bu modülü içe aktarmaktır. Bu modülün içindeki herhangi bir fonksiyonu ya da niteliği kullanabilmek için öncelikle modülü içe aktarmalıyız. Eğer bu şekilde modülü “import” etmezsek, bu modülle ilgili kodlarımızı çalıştırmak istediğimizde Python bize bir hata mesajı gösterecektir.

Bu modülü programımız içine nasıl davet edeceğimizi öğrendiğimize göre, os modülü içindeki fonksiyonlardan ve niteliklerden söz edebiliriz. Öncelikle, isterseniz bu modül içinde neler var neler yok şöyle bir listeleyelim.

Python komut satırında “>>>” işaretinden hemen sonra:

>>> import os

komutuyla os modülünü içe aktarıyoruz. Daha sonra şu komutu veriyoruz:

>>> dir(os)

İsterseniz daha anlaşılır bir çıktı elde edebilmek için bu komutu şu şekilde de verebilirsiniz:

>>> for icerik in dir(os):
...     print icerik

Gördüğünüz gibi, bu modül içinde bir yığın fonksiyon ve nitelik var. Şimdi biz bu fonksiyonlar ve niteliklerden önemli olanlarını incelemeye çalışalım.

name Niteliği

dir(os) komutuyla os modülünün içeriğini incelediğinizde orada name adlı bir nitelik olduğunu göreceksiniz. Bu nitelik, kullandığınız işletim sisteminin ne olduğu hakkında bilgi verir.

Basit bir örnekle başlayalım:

>>> print os.name

Bu komutu hangi işletim sisteminde verdiğinize bağlı olarak aldığınız çıktı da farklı olacaktır. Mesela ben bu komutu GNU/Linux işletim sistemi üzerinde verdiğim için ‘posix’ çıktısı aldım.

os modülünde işletim sistemi isimleri için öntanımlı olarak şu ifadeler bulunur:

GNU/Linux için “posix”,

Windows için “nt”, “dos”, “ce”

Macintosh için “mac”

OS/2 için “os2”

Risc Os için “riscos”

Eğer mesela siz bu komutu Windows XP üzerinde verdiyseniz ‘nt’ çıktısı almış olmalısınız...

Öğrendiğimiz bu bilgiyi kullanarak şöyle basit bir şey yazabiliriz:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os

if os.name == "posix":
    a = raw_input("Linus Torvalds'a mesajınızı yazın:")

if os.name == "nt":
    a = raw_input("Bill Gates'e mesajınızı yazın:")

Bu basit örnekte öncelikle os adlı modülü bütün içeriğiyle birlikte programımıza aktardık. Daha sonra bu modül içindeki name niteliğinden yararlanarak, kullanılan işletim sistemini sorguladık. Buna göre bu program çalıştırıldığında, eğer kullanılan işletim sistemi GNU/Linux ise, kullanıcıdan “Linus Torvalds’a mesajını yazması” istenecektir. Eğer kullanılan işletim sistemi Windows ise, “Bill Gates’e mesaj yazılması istenecektir. Aynı komutları şu şekilde de yazabiliriz:

#!/usr/bin/env python
#-*- coding:utf-8 -*-

from os import name

if name == "posix":
    a = raw_input("Linus Torvalds'a mesajınızı yazın:")

if name == "nt":
    a = raw_input("Bill Gates'e mesajınızı yazın:")

Dikkat ederseniz burada from os import name komutuyla, os modülü içindeki name niteliğini aldık yalnızca. Ayrıca program içinde kullandığımız os.name ifadesini de name şekline dönüştürdük. Çünkü from os import name komutuyla yalnızca name niteliğini çektiğimiz, aslında os modülünü çekmediğimiz için, os.name yapısını kullanırsak Python bize “os” isminin tanımlanmadığını söyleyecektir.

Bu name niteliğinin ne kadar faydalı bir şey olduğunu tahmin edersiniz. Eğer yazdığınız bir programda name niteliğini kullanarak işletim sistemi sorgulaması yaparsanız, yazdığınız programın birden fazla işletim sistemi üzerinde çalışma imkânı olacaktır. Çünkü bu sayede programınızın, kullanılan işletim sistemine göre işlem yapmasını sağlayabilirsiniz.

system() Fonksiyonu

Bu fonksiyon, kullandığımız işletim sistemine ait sistem komutlarını çalıştırmamızı sağlar. Peki “sistem komutu” ne demek? Sistem komutu, üzerinde çalıştığımız işletim sisteminin bir parçası olan ve bu işletim sistemine ilişkin işlemleri yerine getirmemizi sağlayan komutlardır. Örneğin GNU/Linux’ta ls bir sistem komutudur ve bu komutun görevi o anda içinde bulunduğunuz dizindeki dosya ve klasörleri listelemektir. Bu komutun Windows’taki karşılığı ise dir komutudur.

İşte buna benzer sistem komutlarını Python yardımıyla çalıştırabilmek için os modülünün bize sunduğu system() adlı fonksiyondan yararlanacağız. Örneğin:

>>> os.system("ls")

veya:

>>> os.system("dir")

Gördüğünüz gibi, system() komutunu kullanmak çok basit. Yapmamız gereken tek şey parantez içinde, çalıştırılmasını istediğimiz sistem komutunu belirtmek...

Bir örnek daha verelim. Diyelim ki GNU/Linux’taki Kwrite programını kullanarak bir dosya açmak istiyoruz:

>>> os.system("kwrite dosyaadı.txt")

Ancak bir dosyayı açtırırken, o dosyayı açacak programı doğrudan belirtmek pek doğru bir yol değildir. Çünkü mesela Kwrite her GNU/Linux kullanıcısının bilgisayarında kurulu olmayabilir. Kwrite yerine mesela Gedit olabilir... Bu yüzden Python’da herhangi bir dosya veya klasörü açtırmak için en güvenilir yol xdg-open adlı sistem komutundan yararlanmak olacaktır. Bunu şöyle kullanabiliriz:

>>> os.system("xdg-open dosyaadı.txt")

Burada kullandığımız xdg-open komutu bütün GNU/Linux sistemlerinde çalışan bir sistem komutudur. Bu komutun görevi herhangi bir dosya veya klasörü sistemdeki varsayılan uygulamayla açmaktır. Yani mesela bir sistemde metin dosyalarını açan öntanımlı program Kwrite ise dosya Kwrite ile açılacaktır. Eğer metin dosyalarını açan öntanımlı program başka bir şeyse (mesela Gedit), dosya o programla açılacaktır. xdg-open komutu özellikle bir dizini açtırmaya çalışırken çok işe yarar. Çünkü GNU/Linux sistemlerinde dizin görüntüleyici uygulamanın hangisi olduğunu kestirmek çok güçtür. Sistemde Konqueror, Dolphin, Thunar ve benzeri dizin görüntüleyicilerden hangisinin bulunduğuna emin olamazsınız. xdg-open komutu bu noktada size yardımcı olacaktır. Örneğin /usr/share dizinini görüntülemek için şöyle bir kod yazabilirsiniz:

>>> os.system("xdg-open /usr/share")

Böylece, acaba kullanıcının bilgisayarında hangi dizin görüntüleyici uygulama kurulu, diye endişe etmenize gerek kalmaz. xdg-open komutu, sistemde hangi görüntüleyici varsa /usr/share dizinini onunla açacaktır.

Yukarıda Kwrite ile yaptığımız işlemi bir de Windows’ta Notepad programıyla yapalım:

>>> os.system("notepad dosyaadı.txt")

Tıpkı GNU/Linux’ta olduğu gibi, Windows’ta da bir işlemi yapacak uygulamayı doğrudan belirtmek iyi bir fikir değildir. GNU/Linux’taki xdg-open yerine os modülünün startfile() adlı fonksiyonundan yararlanabilirsiniz. Örneğin:

# -*- coding: cp1254 -*-

import os

dosya = "falancadosya"

os.startfile(dosya)

startfile() fonksiyonu GNU/Linux’ta bulunmaz. Bu fonksiyon yalnızca Windows’ta geçerlidir ve GNU/Linux’taki xdg-open komutunun yaptığı şeye benzer bir işlevi vardır.

Yukarıdaki bilgileri kullanarak örneğin şu basit programı yazabiliriz:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os

dosya = "falanca.txt"

print "%s adlı dosya açılıyor..." %dosya

if os.name == "nt":
    os.startfile(dosya)

elif os.name == "posix":
    os.system("xdg-open %s" %dosya)

Bu program oldukça küçük bir kod parçasından ibaret olmasına rağmen, bize os modülüyle ilgili çok önemli bilgiler veriyor. Gelin isterseniz yukarıdaki kod parçasının ne işler çevirdiğini adım adım inceleyelim:

  1. İlk iki satırın ne iş yaptığını söylememize gerek yok. Artık siz bu satırların ne olduğunu adınız gibi biliyorsunuz.
  2. Üçüncü satır da artık bizim için oldukça tanıdık bir koddan oluşuyor. Bu komutla os modülünü bütün içeriğiyle birlikte programımızın içine aktarıyoruz.
  3. Sonraki satırda “falanca.txt” adlı bir dosya tanımladık. Bu değişkenin yerine, bilgisayarınızda bulunan herhangi bir dosyanın adını yazabilirsiniz.
  4. print "%s adlı dosya açılıyor..." %dosya satırıyla kullanıcıya falanca.txt dosyasının açılmak üzere olduğuna dair bilgi veriyoruz.
  5. Eğer kullanıcının işletim sistemi Windows XP ise (if os.name == "nt":) os modülünün startfile() adlı fonksiyonunu kullanarak dosyayı açıyoruz (os.startfile(dosya))
  6. Eğer kullanıcının işletim sistemi GNU/Linux ise (if os.name == "posix":) os modülünün system() adlı fonksiyonunu kullanarak dosyayı açıyoruz (os.system("xdg-open %s" %dosya))

Dediğimiz gibi, system() fonksiyonu her türlü sistem komutunu çalıştırmanıza izin verir. Mesela Windows’ta Python yardımıyla Program Files dizinini görüntüleyelim:

>>> os.system("explorer C:\\Program Files")

Burada kullandığımız bölü işaretinin iki adet ters bölü (\\) olduğuna dikkat ediyoruz.

Aynı şekilde, Internet Explorer programı ile bir web sitesini açmak için de system() fonksiyonundan yararlanabilirsiniz:

>>> os.system("start iexplore.exe http://www.istihza.com")

Burada da Windows’un start adlı sistem komutunu kullanarak IE ile istihza.com sitesini görüntüledik.

listdir() Fonksiyonu

Python yardımıyla bir dizin içindeki dosyaları görüntülemek istersek, system() fonksiyonundan yardım alabileceğimizi biliyoruz. Bunun için GNU/Linux kullanıcıları şunu yazabilir:

>>> os.system("ls")

Windows kullanıcıları ise şunu:

>>> os.system("dir")

Ancak bu işlemi Python’da çok daha kolay ve esnek bir biçimde yapmanın bir yolu daha var. os modülü içinde yer alan listdir() adlı fonksiyon bize bir dizin içindeki dosyaları veya klasörleri listeleme imkânı veriyor. Mesela /usr/bin dizini içindeki bütün dosyaları listelemek için şöyle bir şey yazabiliriz:

>>> import os

>>> a = os.listdir("/usr/bin")

>>> print a

Yukarıdaki örnekte her zamanki gibi, modülümüzü import os komutuyla programımıza aktardık ilk önce. Ardından kullanım kolaylığı açısından listdir() fonksiyonunu a adlı bir değişkene atadık. Örnekte listdir() fonksiyonunun nasıl kullanıldığını görüyorsunuz. Örneğimizde /usr/bin dizini altındaki dosya ve klasörleri listeliyoruz. Burada parantez içinde tırnak işaretlerini ve yatık çizgileri nasıl kullandığımıza dikkat edin. En son da print a komutuyla /usr/bin dizininin içeriğini liste olarak ekrana yazdırıyoruz. Çıktının tipinden anladığımız gibi, elimizde olan şey, öğeleri yan yana dizilmiş bir liste. Eğer biz dizin içeriğinin böyle yan yana değil de alt alta dizildiğinde daha şık görüneceğini düşünüyorsak, kodlarımızı şu biçime sokabiliriz:

import os

a = os.listdir("/usr/bin")

for dosyalar in a:
    print dosyalar

Eğer dosyalarımıza numara da vermek istersek şöyle bir şey yazabiliriz:

import os

a = os.listdir("/usr/bin")
c = 0

for dosyalar in a:
    if c < len(a):
        c = c+1
        print c, dosyalar

Hatta daha önce öğrendiğimiz enumerate() fonksiyonunu kullanarak bu işlemi çok daha kısa bir yoldan halledebilirsiniz:

import os

a = os.listdir("/usr/bin")

for numara, dosya in enumerate(a, 1):
    print numara, dosya

Eğer amacınız, o anda içinde bulunduğunuz dizindeki dosyaları listelemekse listdir() fonksiyonunu şu şekilde kullanabilirsiniz:

>>> os.listdir(".")

Buradaki ”.” argümanı, o anda içinde bulunulan dizini temsil eder. Eğer bir üst dizinin içeriğini listelemek isterseniz tek nokta yerine iki nokta işaretini kullanabilirsiniz:

>>> os.listdir("..")

Bu komut o anda içinde bulunduğunuz dizine göre bir üst dizinin içeriğini ekrana liste olarak verecektir. Yani mesela o anda /usr/local/bin dizini içindeyseniz yukarıdaki komut /usr/local dizininin içeriğini listeleyecektir.

Bu fonksiyonu ve daha önce öğrendiğimiz system() fonksiyonunu kullanarak, bir dizin içindeki bütün dosyaları açan ve bu sebeple bilgisayarınızın bir süre yanıt vermemesine bile yol açabilecek korkunç bir program yazabilirsiniz! (Denemeyin!)

#!/usr/bin/env python
# -*- coding: utf-8 -*-

if os.name == "posix":
    for i in os.listdir("/usr/bin"):
        os.system("xdg-open %s%s" %("/usr/bin/", i))

elif os.name == "nt":
    for i in os.listdir("C:\\Program Files"):
        os.startfile("%s%s" %("C:\\Program Files\\", i))

Sırada yine önemli bir fonksiyon var...

getcwd() Fonksiyonu

os modülü içinde yer alan bu fonksiyon bize o anda hangi dizin içinde bulunduğumuza dair bilgi verir. İsterseniz bu fonksiyonun tam olarak ne işe yaradığını bir örnek üzerinde görelim:

>>> os.getcwd()

Gördüğünüz gibi bu komut bize o anda hangi dizin içinde bulunduğumuzu söylüyor. Bu arada İngilizce bilenler için söyleyelim, buradaki “cwd”nin açılımı “current working directory”. Yani kabaca “mevcut çalışma dizini”... Daha açık ifade etmek gerekirse: “O anda içinde bulunduğumuz dizin”. Şöyle bir örnek vererek konuyu biraz açalım:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os

mevcut_dizin = os.getcwd()

if mevcut_dizin == "/home/istihza/Desktop":
    for i in os.listdir(mevcut_dizin):
        print i

else:
    print ("Bu program yalnızca /home/istihza/Desktop "
    "dizininin içeriğini gösterebilir!")

Yukarıdaki örnekte öncelikle os modülünü içe aktardık. Daha sonra mevcut_dizin adında bir değişken tanımlayıp getcwd() fonksiyonunun kendisini bu değişkenin değeri olarak atadık. Ardından, “eğer mevcut_dizin /home/istihza/Desktop ise bu dizin içindeki dosyaları bize listele ve sonucu ekrana yazdır, yok eğer mevcut_dizin /home/istihza/Desktop değil ise, ‘bu program yalnızca /home/istihza/Desktop dizininin içeriğini gösterebilir,’ cümlesini göster” dedik. Burada dikkat ederseniz if deyiminden sonra for döngüsünü kullandık. Bu işlemi, ekran çıktısı daha düzgün olsun diye yaptık. Eğer böyle bir kaygımız olmasaydı,

if mevcut_dizin == "/home/istihza/Desktop":

satırının hemen altına:

print mevcut_dizin

yazıp işi bitirirdik.

Biz burada getcwd() fonksiyonu için basit örnekler verdik, ama eminim siz yaratıcılığınızla çok daha farklı ve kullanışlı kodlar yazabilirsiniz. Mesela kendi yazdığınız bir modülü içe aktarmak istediğinizde neden hata verdiğini anlamak için bu fonksiyondan yararlanabilirsiniz. Eğer bu fonksiyonun verdiği çıktı, içe aktarmaya çalıştığınız modülün bulunduğu dizinden farklıysa o modülü boşuna içe aktarmaya çalışıyorsunuz demektir!

Şimdi de os modülü içindeki başka bir fonksiyona değinelim.

chdir() Fonksiyonu

Bu fonksiyon yardımıyla içinde bulunduğumuz dizini değiştirebiliriz. Diyelim ki o anda /usr/share/apps dizini içindeyiz. Eğer bir üst dizine, yani /usr/share/ dizinine geçmek istiyorsak, şu komutu verebiliriz:

>>> import os

>>> os.chdir(os.pardir)

>>> print os.getcwd()

Hatırlarsanız bir üst dizini temsil etmek için ”..” işaretinden yararlanıyorduk. İşte pardir de bu işaretin yaptığı işi yapar. Buradaki pardir niteliği, İngilizce “parent directory” (bir üst dizin) ifadesinin kısaltması oluyor. pardir niteliği dışında, bir de curdir niteliği vardır. Bu sabiti kullanarak “mevcut dizin” üzerinde işlemler yapabiliriz. Tıpkı ”.” işaretinde olduğu gibi...:

>>> import os

>>> os.listdir(os.curdir)

Gördüğünüz gibi bu curdir niteliği getcwd() fonksiyonuna benziyor. Bunun dışında, istersek gitmek istediğimiz dizini kendimiz elle de belirtebiliriz:

>>> import os
>>> os.chdir("/var/tmp")

Böylece doğrudan /var/tmp dizinine ulaşmış olduk. Yukarıdaki komutun ardından şu komutu verirseniz bu durumu teyit edebilirsiniz:

>>> os.getwd()

'/var/tmp'

mkdir() ve makedirs() Fonksiyonları

Bu iki fonksiyon yardımıyla dizin veya dizinler oluşturacağız. Mesela:

>>> import os

>>> os.mkdir("/test")

Bu kod / dizini altında “test” adlı boş bir klasör oluşturacaktır. Eğer bu kodu şu şekilde yazarsak, mevcut çalışma dizini içinde yeni bir dizin oluşacaktır:

>>> import os

>>> os.mkdir("test")

Yani, mesela mevcut çalışma dizini masaüstü ise bu “test” adlı dizin masaüstünde oluşacaktır. İsterseniz bu kodları şu şekle getirerek yeni oluşturulan dizinin nerede olduğunu da görebilirsiniz:

>>> import os

>>> print os.getcwd()

>>> os.mkdir("test")

Bundan başka, eğer isterseniz mevcut bir dizin yapısı içinde başka bir dizin de oluşturabilirsiniz. Yani mesela /home/kullanıcı_adınız/ dizini içinde “deneme” adlı boş bir dizin oluşturabilirsiniz:

>>> import os

>>> os.mkdir("/home/istihza/deneme")

Peki diyelim ki iç içe birkaç tane yeni klasör oluşturmak istiyoruz. Yani mesela /home/kullanıcı_adınız dizini altında yeni bir “Programlar” dizini, onun altında da “Python” adlı yeni başka bir dizin daha oluşturmak istiyoruz.

Hemen deneyelim:

>>> import os

>>> os.mkdir("/home/istihza/Programlar/Python")

Ne oldu? Şöyle bir hata çıktısı elde ettik, değil mi?

>>> os.mkdir("/home/istihza/Programlar/Python")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 2] No such file or directory:
'/home/istihza/Programlar/Python'

Demek ki bu şekilde çoklu dizin oluşturamıyoruz. İşte bu amaç için elimizde makedirs() fonksiyonu var. Hemen deneyelim yine:

>>> import os

>>> os.makedirs("/home/istihza/Programlar/Python")

Gördüğünüz gibi, /home/kullanıcı_adımız/ dizini altında yeni bir “Programlar” dizini ve onun altında da yeni bir “Python” dizini oluştu. Buradan çıkan sonuç, demek ki mkdir() fonksiyonu bize yalnızca bir adet dizin oluşturma izni veriyor. Eğer biz birden fazla, yani çoklu yeni dizin oluşturmak istiyorsak makedirs() fonksiyonunu kullanmamız gerekiyor.

Küçük bir örnek daha verip bu bahsi kapatalım:

>>> import os

>>> print os.getcwd()

>>> os.makedirs("test/test1/test2/test3")

Tahmin ettiğiniz gibi bu kod mevcut çalışma dizini altında iç içe “test”, “test1”, “test2” ve “test3” adlı dizinler oluşturdu. Eğer “test” ifadesinin soluna “/” işaretini eklerseniz, bu boş dizinler kök dizini altında oluşacaktır.

rmdir() ve removedirs() fonksiyonları

Bu fonksiyonlar bize mevcut dizinleri silme olanağı tanıyor. Yalnız, burada hemen bir uyarı yapalım: Bu fonksiyonları çok dikkatli kullanmamız gerekiyor. Ne yaptığınızdan, neyi sildiğinizden emin değilseniz bu fonksiyonları kullanmayın! Çünkü Python bu komutu verdiğinizde tek bir soru bile sormadan silecektir belirttiğiniz dizini. Gerçi, bu komutlar yalnızca içi boş dizinleri silecektir, ama yine de uyaralım...

Hemen bir örnek verelim. Diyelim ki mevcut çalışma dizinimiz olan masaüstünde “TEST” adlı boş bir dizin var ve biz bu dizini silmek istiyoruz:

>>> import os

>>> os.rmdir("TEST")

Böylece “TEST” dizini silindi.

Bir de şu örneğe bakın:

>>> import os

>>> os.rmdir("/home/istihza/TEST")

Bu kod ise /home/kullanıcı_adı dizini altındaki boş “TEST” dizinini silecektir.

Tıpkı mkdir() ve makedirs() fonksiyonlarında olduğu gibi, iç içe birden fazla boş dizini silmek istediğimizde ise removedirs() fonksiyonundan yararlanıyoruz:

>>> import os

>>> os.removedirs("test1/test2")

Yine hatırlatmakta fayda var: Neyi sildiğinize mutlaka dikkat edin...

Python’da dizinleri nasıl yöneteceğimizi, nasıl dizin oluşturup sileceğimizi basitçe gördük. Şimdi de bu “dizinleri yönetme” işini biraz irdeleyelim. Şimdiye kadar hep bir dizin, onun altında başka bir dizin, onun altında da başka bir dizini nasıl oluşturacağımızı çalıştık. Peki, aynı dizin altında birden fazla dizin oluşturmak istersek ne yapacağız? Bu işlemi çok kolay bir şekilde şöyle yapabiliriz:

>>> import os

>>> os.makedirs("test1/test2")

>>> os.makedirs("test1/test3")

Bu kodlar mevcut çalışma dizini altında “test1” adlı bir dizin ile bunun altında “test2” ve “test3” adlı başka iki adet dizin daha oluşturacaktır. Peki, bu “test1”, “test2” ve “test3” ifadelerinin sabit değil de değişken olmasını istersek ne yapacağız. Şöyle bir şey deneyelim:

>>> import os

>>> test1 = "Belgelerim"

>>> test2 = "Hesaplamalar"

>>> test3 = "Resimler"

>>> os.makedirs(test1/test2)
>>> os.makedirs(test1/test3)

Bu kodları çalıştırdığımızda Python bize şöyle bir şey söyler:

>>> os.makedirs(test1/test3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s)
for /: 'str' and 'str'

Peki, neden böyle oldu ve bu hata ne anlama geliyor?

Kod yazarken bazı durumlarda “/” işareti programcıları sıkıntıya sokabilir. Çünkü bu işaret Python’da hem “bölme” işleci hem de “dizin ayracı” olarak kullanılıyor. Biraz önce yazdığımız kodda Python bu işareti “dizin ayracı” olarak değil “bölme işleci” olarak algıladı ve sanki “test1” ifadesini “test2” ifadesine bölmek istiyormuşuz gibi davrandı bize. Ayrıca kullandığımız os.makedirs() fonksiyonunu da gördüğü için ne yapmaya çalıştığımızı anlayamadı ve kafası karıştı. Peki, bu meseleyi nasıl halledeceğiz?

Bu meseleyi halletmek için kullanmamız gereken başka bir nitelik var Python’da...

sep niteliği

Bu nitelik, işletim sistemlerinin dizin ayraçları hakkında bize bilgi veriyor. Eğer yazdığımız bir programın farklı işletim sistemleri üzerinde çalışmasını istiyorsak bu fonksiyon epey işimize yarayacaktır. Çünkü her işletim sisteminin dizin ayracı birbiriyle aynı değil. Bunu şu örnekle gösterebiliriz: Hemen bir Python komut satırı açıp şu komutları verelim:

>>> import os

>>> os.sep

'/'

Bu komutu GNU/Linux’ta verdiğimiz için komutun çıktısı “/” şeklinde oldu. Eğer aynı komutu Windows’ta verirsek sonuç şöyle olacaktır:

>>> import os
>>> os.sep

'\\'

Peki bu sep niteliği ne işe yarar? Yazdığımız kodlarda doğrudan dizin ayracı vermek yerine bu niteliği kullanırsak, programımızı farklı işletim sistemlerinde çalıştırırken, sistemin kendine özgü dizin ayracının kullanılmasını sağlamış oluruz. Yani mesela:

>>> import os

>>> os.makedirs("test/test2")

komutu yerine;

>>> import os

>>> os.makedirs("test" + os.sep + "test2")

komutunu kullanırsak programımızı farklı işletim sistemlerinde çalıştırırken herhangi bir aksaklık olmasını önlemiş oluruz. Çünkü burada sep niteliği, ilgili işletim sistemi hangisiyse ona ait olan dizin ayracının otomatik olarak yerleştirilmesini sağlayacaktır.

Bu sep niteliği ayrıca dizin adlarını “değişken” yapmak istediğimizde de bize yardımcı olacaktır. Hatırlarsanız yukarıda şöyle bir kod yazmıştık:

>>> import os

>>> test1 = "Belgelerim"

>>> test2 = "Hesaplamalar"

>>> test3 = "Resimler"

>>> os.makedirs(test1/test2)

>>> os.makedirs(test1/test3)

Yine hatırlarsanız bu kodu çalıştırdığımızda Python hata vermişti. Çünkü Python burada “/” işaretini bölme işleci olarak algılamıştı. İşte bu hatayı almamak için sep niteliğinden faydalanabiliriz. Şöyle ki:

>>> import os

>>> test1 = "Belgelerim"

>>> test2 = "Hesaplamalar"

>>> test3 = "Resimler"

>>> os.makedirs(test1)

>>> os.makedirs(os.sep.join([test1, test2]))

>>> os.makedirs(os.sep.join([test1, test3]))

Dikkat ederseniz, burada sep niteliğini join() adlı bir fonksiyon ile birlikte kullandık. (join() fonksiyonunu birkaç ders sonra daha ayrıntılı bir şekilde inceleyeceğiz). Yukarıdaki kod sayesinde doğrudan “/” işaretine bulaşmadan, başımızı derde sokmadan işimizi halledebiliyoruz. Ayrıca burada parantez ve köşeli parantezlerin nasıl kullanıldığına da dikkat etmemiz gerekiyor.

Yukarıda “test1”, “test2” ve “test3” değişkenlerinin adlarını doğrudan kod içinde verdik. Tabii eğer istersek raw_input() fonksiyonuyla dizin adlarını kullanıcıya seçtirebileceğimiz gibi, şöyle bir şey de yapabiliriz:

import os

def dizinler(test1, test2, test3):
    os.makedirs(test1)
    os.makedirs(os.sep.join([test1, test2]))
    os.makedirs(os.sep.join([test1, test3]))

Dikkat ederseniz, burada öncelikle os modülünü çağırıyoruz. Daha sonra dizinler() adlı bir fonksiyon oluşturup parametre olarak “test1”, “test2” ve “test3” adlı değişkenler belirliyoruz. Ardından os.makedirs(test1) komutuyla “test1” adlı bir dizin oluşturuyoruz. Tabii bu “test1” bir değişken olduğu için adını daha sonradan biz belirleyeceğiz. Alttaki satırda ise os.makedirs() ve os.sep.join() komutları yardımıyla, bir önceki satırda oluşturduğumuz “test1” adlı dizinin içinde “test2” adlı bir dizin daha oluşturuyoruz. Burada os.sep.join() fonksiyonu “/” işaretiyle uğraşmadan dizinleri birleştirme imkânı sağlıyor bize. Hemen alttaki satırda da benzer bir işlem yapıp kodlarımızı bitiriyoruz. Böylece bir fonksiyon tanımlamış olduk. Şimdi bu dosyayı deneme.py adıyla masaüstüne kaydedelim. Böylelikle kendimize bir modül yapmış olduk. Şimdi Python komut satırını açalım ve şu komutları verelim:

>>> import deneme

>>> deneme.dizinler("Belgelerim", "Videolar", "Resimler")

Burada öncelikle import deneme satırıyla deneme adlı modülümüzü çağırdık. Daha sonra deneme.dizinler satırıyla bu modül içindeki dizinler() adlı fonksiyonu çağırdık. Böylelikle masaüstünde “Belgelerim” adlı bir klasörün içinde “Videolar” ve “Resimler” adlı iki klasör oluşturmuş olduk. Bu os.sep.join() ifadesi ile ilgili son bir şey daha söyleyip bu konuya bir nokta koyalım.

Şimdi Python komut satırını açarak şu kodları yazalım:

>>> import os

>>> os.sep.join(["Dizin1", "Dizin2"])

ENTER tuşuna bastığımızda, bu komutların çıktısı şöyle olur:

'Dizin1/Dizin2'

Aynı kodları Windows üzerinde verirsek de şu çıktıyı alırız:

'Dizin1\\Dizin2'

Gördüğünüz gibi farklı platformlar üzerinde, os.sep çıktısı birbirinden farklı oluyor. Bu örnek, sep niteliğinin, yazdığımız programların “taşınabilirliği” (portability), yani “farklı işletim sistemleri üzerinde çalışabilme kabiliyeti” açısından ne kadar önemli olabileceğini gösteriyor.

Üçüncü Şahısların Yazdığı Modüller

Buraya kadar kendi yazdığımız modülleri ve geliştiriciler tarafından yazılıp dilin içine entegre edilen modülleri ayrı ayrı gördük. Bunların dışında bir de üçüncü şahıslar tarafından yazılan modüller vardır. Bu modüller, yazarları tarafından genellikle internet üzerinden erişime sunulmuştur. Dolayısıyla bu modülleri, yazarlarının internet sitelerinden indirip bilgisayarınıza kurabilir, bu modülleri de herhangi bir Python modülü gibi kullanabilirsiniz. Piyasada pek çok üçüncü şahıs modülü bulunur. Bu modüller sayesinde, çok zor bazı işleri çok kolay bir şekilde halledebiliriz. Biz bu bölümde pyPdf adlı bir örnek modül üzerinden, üçüncü şahıs modüllerini tanımaya çalışacağız.

Ancak bu noktada küçük bir uyarı yapalım. Aşağıda inceleyeceğimiz PyPdf modülünü anlatırken, henüz öğrenmediğimiz bazı şeylerle de karşılaşacaksınız. Anlayamadığınız noktalar olursa bunlara çok fazla takılmayın. Zira bütün o ayrıntıları sonraki derslerimizde inceleyeceğiz. Bizim burada amacımız, Python’da üçüncü şahıs modüllerinin neye benzediği ve bunların nasıl kullanılacağı hakkında yalnızca bir fikir vermekten ibarettir.

pyPdf Modülü

Bu bölümde inceleyeceğimiz örnek modülün adı pyPdf. Bu modül, Python’da pdf dosyaları ile ilgili temel işlemleri yapmamızı sağlıyor. Mathieu Fenniak tarafından yazılmış olan bu üçüncü şahıs modülünün anasayfasına http://pybrary.net/pyPdf/ adresinden ulaşabilirsiniz.

pyPdf modülü bir üçüncü şahıs modülü olduğundan, bunu kullanabilmek için öncelikle bu modülü bilgisayarımıza kurmamız gerekiyor. Eğer bu modülü kurmazsak elbette kullanmamız mümkün olmaz. Gelin bir deneme yapalım:

>>> import pyPdf
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named pyPdf

Gördüğünüz gibi, bilgisayarımızda pyPdf modülü olmadığı için import pyPdf komutu hata veriyor. O yüzden öncelikle bu modülü bilgisayarımıza kuracağız.

Bu modül GNU/Linux dağıtımlarının paket depolarında bulunur. Eğer Ubuntu kullanıyorsanız, pyPdf modülünü şu komut yardımıyla sisteminize kurabilirsiniz:

sudo apt-get install python-pypdf

Eğer Ubuntu dışında bir GNU/Linux dağıtımı kullanıyorsanız, paket yöneticiniz yardımıyla “pypdf” şeklinde bir arama yapmanızı öneririm.

Kullandıkları dağıtımın paket depolarında pyPdf modülünü bulamayan arkadaşlarım şu adresten ilgili tar.gz dosyasını indirerek kaynaktan kurulum yapmayı tercih edebilirler: http://pybrary.net/pyPdf/

Bu sıkıştırılmış dosyayı bilgisayarımıza indirdikten sonra dosyayı açıp, orada şu komutu veriyoruz:

sudo python setup.py install

Eğer herhangi bir aksilik olmadıysa pyPdf modülü bu komutun ardından sistemimize kurulacaktır.

Windows kullanıcıları ise şu adresten .exe dosyasını indirip çift tıklayarak modülü bilgisayarlarına kurabilir: http://pybrary.net/pyPdf/

Gelin isterseniz biraz önce içe aktarırken hata aldığımız komutu tekrar vererek pyPdf modülünü doğru bir şekilde kurup kuramadığımızı denetleyelim:

>>> import pyPdf

Bu komutu verdiğinizde şöyle bir uyarı mesajı almış olabilirsiniz:

>>> import pyPdf
DeprecationWarning: the sets module is deprecated
  from sets import ImmutableSet

pyPdf modülünün uyumlu olduğu son Python sürümü 2.5’tir. Bu modül Python’un 2.6 sürümünde de çalışıyor, ancak program çıktısında bazı uyarılar alıyoruz. Bu uyarılar, Python’un 3.x sürümünde kullanımdan kaldırılacak özelliklere ilişkindir. Ancak bu uyarılara rağmen bu modül Python 2.6 sürümünde de kullanılabilir. Yukarıdaki uyarı mesajı modülümüzün çalışmasını engellemez. pyPdf modülünün Python3.x sürümlerine uyumlu hale getirilmesi için çalışmalar da sürdürülmektedir.

Bu arada pyPdf modülünü içe aktarırken büyük-küçük harfe dikkat etmelisiniz...

pyPdf modülünü kurduğumuza göre artık bu modülü incelemeye başlayabiliriz.

pdf Bilgilerine Ulaşmak

Başta da söylediğimiz gibi pyPdf modülünü kullanarak pdf belgelerine ait bazı bilgileri toplayabilirsiniz. Bu bilgiler neler olabilir? Mesela belgenin başlığı, belgenin yazarı, belgenin hangi yazılım ile oluşturulduğu, vb... Birkaç örnek verelim.

Öncelikle pyPdf modülünden bazı fonksiyonları içe aktarıyoruz:

from pyPdf import PdfFileWriter, PdfFileReader

import komutunu nasıl verdiğimize dikkat edin. Daha önce modüllerin içe aktarılma yöntemlerini incelerken bu biçimi öğrendiğimizi hatırlıyor olmalısınız. pyPdf modülünün tamamına değil de, bunun içindeki sadece iki fonksiyona ihtiyaç duyduğumuz için yalnızca o iki fonksiyonu içe aktarıyoruz.

Şimdi de okuyacağımız pdf dosyasını tanımlıyoruz:

belge = "diveintopython.pdf"

Ben örnek olarak kendime diveintopython.pdf adlı bir pdf dosyası seçtim. Siz elbette başka bir dosya ile çalışabilirsiniz.

Yukarıda tanımladığımız belge adlı pdf dosyasını okumak üzere açıyoruz:

kaynak = PdfFileReader(open(belge, "rb"))

Burada belge adlı pdf dosyasını “rb” kipinde açtığımıza dikkat edin. pdf dosyaları ikili (binary) düzende oldukları için, bunları okurken “rb” kipini kullanmamız gerekir.

Daha önce de dediğimiz gibi, bu konuyu anlatırken henüz yabancısı olduğumuz kavramlarla karşılaşıyoruz. Ama bunları çok fazla dert edinmeyin. Siz şimdilik sadece üçüncü şahıs modüllerin neye benzediği üzerine yoğunlaşmaya çalışın. Neyse... Biz incelememize devam edelim.

Şimdi de pyPdf modülü içinde bulunan getDocumentInfo() fonksiyonunun title adlı niteliğini kullanarak, belge adlı pdf dosyamızın başlığını alalım:

print (u"%s adlı dosyanın başlığı şudur: %s"
%(belge, kaynak.getDocumentInfo().title))

Burada, Türkçe karakterlerin düzgün görüntülenememesi gibi bir sorunla karşılaşmamak için, “u” harfini kullanarak karakter dizimizi “unicode” haline getiriyoruz. “unicode” kavramından birkaç ders sonra daha ayrıntılı olarak bahsedeceğiz.

İsterseniz yazdığımız kodları topluca görelim:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pyPdf import PdfFileWriter, PdfFileReader

belge = "diveintopython.pdf"

kaynak = PdfFileReader(open(belge, "rb"))

print (u"%s adlı dosyanın başlığı şudur: %s"
%(belge, kaynak.getDocumentInfo().title))

Daha önce de dediğimiz gibi, eğer sisteminizdeki Python sürümü 2.6 ise, yukarıdaki kodları çalıştırdığınızda şuna benzer uyarılar alabilirsiniz:

istihza@istihza:~/Desktop$ python deneme.py
DeprecationWarning: the sets module is deprecated
  from sets import ImmutableSet

Bu uyarılar programımızın çalışmasını engellemez. Çünkü bunlar birer hata değil, sadece uyarıdır. Bu uyarıya göre, pyPdf kütüphanesi içinde kullanılmış olan bazı modüller, Python’un mevcut sürümünde çalışıyor olsa bile, bir üst sürümde artık kullanılmayacak. Eğer siz bu uyarıları almak istemiyorsanız, programımızı şöyle yazabilirsiniz:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import warnings

warnings.simplefilter("ignore", DeprecationWarning)

from pyPdf import PdfFileWriter, PdfFileReader

belge = "diveintopython.pdf"

kaynak = PdfFileReader(open(belge, "rb"))

print (u"%s adlı dosyanın başlığı şudur: %s"
%(belge, kaynak.getDocumentInfo().title))

Burada warnings adlı bir başka modülü içe aktardığımıza dikkat edin. Bu modül geliştiricilerin yazdığı modüllerden biridir. Dolayısıyla bilgisayarımıza herhangi bir program kurmaya gerek kalmadan doğrudan programlarımız içinde kullanılabilir. Bu modülün simplefilter() adlı fonksiyonunu kullanarak “DeprecationWarning” olarak ifade edilen, “tedavülden kalkacak özellikler” hakkındaki uyarıları etkisizleştiriyoruz. Bu kodları çalıştırdığımız zaman şöyle bir çıktı elde edeceğiz:

diveintopython.pdf adlı dosyanın başlığı şudur: Dive Into Python

Her pdf belgesinin başlığı olmayabilir. Dolayısıyla eğer sizin çalıştığınız belgenin bir başlığı yoksa, başlık yerine None değerini alacaksınız.

pyPdf modülü yardımıyla bir belgenin başlığı dışında, yazarının kim olduğunu da öğrenebiliriz. Bunun için title yerine author niteliğini kullanıyoruz:

#!/usr/bin/env python
#-*- coding: utf-8 -*-

import warnings

warnings.simplefilter("ignore", DeprecationWarning)

from pyPdf import PdfFileWriter, PdfFileReader

belge = "falanca.pdf"

kaynak = PdfFileReader(open(belge, "rb"))

print (u"%s adlı dosyanın yazarı şudur: %s"
%(belge, kaynak.getDocumentInfo().author))

Tıpkı title niteliğinde olduğu gibi, eğer pdf belgesinde yazar bilgisi geçmiyorsa, None değerini alırız.

Bir pdf belgesinin hangi yazılım ile oluşturulduğunu öğrenmek için ise creator niteliğini kullanıyoruz:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import warnings

warnings.simplefilter("ignore", DeprecationWarning)

from pyPdf import PdfFileWriter, PdfFileReader

belge = "falanca.pdf"

kaynak = PdfFileReader(open(belge, "rb"))

print (u"%s adlı dosya şu yazılımla oluşturulmuştur: %s"
%(belge, kaynak.getDocumentInfo().creator))

Bu kodları çalıştırdığımızda şuna benzer çıktılar alabiliriz:

Scribus 1.3.3.12, Writer, Adobe InDesign CS3 (5.0.4), vb...

Bu çıktılar, elimizdeki pdf belgesinin hangi yazılımın hangi sürümü kullanılarak oluşturulduğunu gösterir. Eğer belge başka bir formattan pdf formatına dönüştürülmüşse, özgün formatı oluşturmak için kullanılan yazılım görünecektir. Mesela bir belge önce OpenOffice ile yazılıp daha sonra OpenOffice kullanılarak pdf formatına dönüştürülmüşse çıktıda OpenOffice görünecektir. (OpenOffice çıktıda “Writer” olarak görünür.)

creator niteliğine benzer bir şekilde, pdf belgesini oluşturan yazılımı görüntüleyen bir başka metot da producer adlı niteliktir. Bu niteliği şu şekilde kullanıyoruz (Sadece ilgili kod parçasını gösteriyoruz)

kaynak.getDocumentInfo().producer

Örneğin, creator niteliği ile “Scribus 1.3.3.12” çıktısını almışsak, producer niteliği bize şu çıktıyı verebilir:

Scribus PDF Library 1.3.3.12

Veya creator niteliği bize Adobe InDesign CS3 (5.0.4) çıktısını verdiyse, producer niteliği şuna benzer bir çıktı verebilir:

Adobe PDF Library 8.0

Ya da creator niteliği ile “Writer” çıktısı elde etmişsek, producer niteliğiyle şunu elde edebiliriz:

OpenOffice.org 2.3

Daha önce de belirttiğimiz gibi, her pdf dosyası yukarıdaki özelliklerin hepsini barındırmayabilir. Yani mesela her pdf belgesinin bir başlığı (title) olmayabilir... Böyle bir pdf belgesine title niteliğini uyguladığımızda None çıktısı alırız.

getDocumentInfo() fonksiyonunun en önemli metotlarını gördüğümüze göre, pyPdf modülünün başka bir özelliğini incelemeye başlayabiliriz.

pyPdf ile pdf Belgelerinden Sayfa Almak

pyPdf modülünü kullanarak bir pdf belgesinden istediğimiz sayfaları alabiliriz. Örneğin, eğer bir pdf belgesinin ilk sayfasını almak istiyorsak şöyle bir işlem yapmamız gerekir:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pyPdf import PdfFileReader, PdfFileWriter

kaynak = PdfFileReader(open("falanca.pdf", "rb"))
nesne = PdfFileWriter()
hedef = open("hedef.pdf", "wb")

nesne.addPage(kaynak.getPage(0))

nesne.write(hedef)
hedef.close()

Daha önce bahsettiğimiz gibi, bu kodları çalıştırdığınızda bazı zararsız uyarılar alacaksınız. İsterseniz yukarıda gösterdiğimiz şekilde bu uyarıları kapatabilirsiniz. Yukarıdaki programı bir dosyaya kaydedip çalıştırdığınızda, çalışma dizininiz içinde hedef.pdf adında bir pdf belgesi oluşacak. Bu yeni pdf belgesini açıp baktığınızda, içeriğinin falanca.pdf adlı belgenin ilk sayfası olduğunu göreceksiniz. Bu demek oluyor ki, yukarıdaki kodlar yardımıyla bir pdf dosyasının ilk sayfasını alıp başka bir pdf dosyası oluşturabiliyoruz...

Gelin isterseniz bu kodları biraz açıklayalım:

Burada öncelikle pyPdf modülünden, pdf dosyasını okumamıza yarayan PdfFileReader() fonksiyonunu ve pdf dosyasından okuduğumuz parçaları yazmamızı sağlayan PdfFileWriter() fonksiyonunu içe aktarıyoruz. Daha sonra, kaynak = PdfFileReader(open("falanca.pdf", "rb")) satırıyla kaynak dosyamızı tanımlıyoruz. Burada okuyacağımız kaynak pdf dosyamızın adı falanca.pdf. Bu dosyayı “rb” kipiyle açıyoruz. (Bu kiplerin ne demek olduğunu bir sonraki bölümde öğreneceğiz) Ardından, falanca.pdf dosyasından okuduğumuz verileri hedef dosyaya yazmadan önce, PdfFileWriter() fonksiyonunu kullanarak, yazacağımız verileri bir “pyPdf.pdf.PdfFileWriter nesnesi” haline getiriyoruz. Eğer yukarıdaki kodları şu şekilde yazacak olursanız:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import warnings

warnings.simplefilter("ignore", DeprecationWarning)

from pyPdf import PdfFileReader, PdfFileWriter

kaynak = PdfFileReader(open("falanca.pdf", "rb"))
nesne = PdfFileWriter()
print nesne

Şöyle bir çıktı alırsınız:

<pyPdf.pdf.PdfFileWriter object at 0xb7cdea0c>

Demek ki, aslında kaynak değişkeni içinde depoladığımız “şey” bir nesnedir. Biz bu nesneyi alıp doğruca hedef dosyamıza yazacağız. Tabii ki önce hedef dosyamızı tanımlamamız gerekiyor. Bunu da yukarıdaki kodlardaki şu satırla hallettik:

hedef = open("hedef.pdf", "wb")

Burada hedef.pdf adlı dosyamızı yine “ikili” düzende (binary) açtığımıza dikkat edin.

Artık bir önceki adımda oluşturduğumuz “pyPdf.pdf.PdfFileWriter nesnesini” hedef dosyamıza yazdırabiliriz. Bu işlemi yapan satırlarımız şunlar:

nesne.addPage(kaynak.getPage(0))
nesne.write(hedef)
hedef.close()

Burada öncelikle, kaynak.getPage(0) satırı yardımıyla kaynak dosyasının sıfırıncı (yani ilk) sayfasını alıyoruz. pyPdf modülünün addPage() fonksiyonunu kullanarak, aldığımız bu sıfırıncı sayfayı bir önceki satırda oluşturduğumuz nesnenin içine ekliyoruz. Sondan bir önceki satır yardımıyla da, içini doldurduğumuz bu nesneyi hedef adlı dosyaya yazdırıyoruz. Son satırımız ise hedef dosyayı kapatmamızı sağlıyor.

Pdf Belgelerinin Sayfa Sayısını Öğrenmek

pyPdf modülü yardımıyla, elimizdeki pdf belgelerinin sayfa sayısını da rahatlıkla sorgulayabiliriz. Bu işlemi yapmak için pyPdf modülünün getNumPages() fonksiyonundan yararlanacağız:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import warnings

warnings.simplefilter("ignore", DeprecationWarning)

from pyPdf import PdfFileReader

kaynak = PdfFileReader(open("python.pdf", "rb"))

print kaynak.getNumPages()

Gördüğünüz gibi, getNumPages() fonksiyonunu kullanarak bir pdf belgesinin sayfa sayısını öğrenmek son derece kolay.

Böylelikle Python’la temel pdf işlemlerini yapmamızı sağlayan pyPdf modülünü kısaca tanımış olduk. Bu modül aynı zamanda HARMAN programında da kullanılmıştır. Bu programı ve kaynak kodlarını incelemek için http://istihza.com/harman/icindekiler_harman.html adresini ziyaret edebilirsiniz.

Bu bölümde pek çok yeni şey öğrendik. Öğrendiklerimizin bir kısmı henüz bize çok fazla şey ifade etmemiş olabilir. Ama birkaç ders sonra burada anlatılan her şeyin zihninizde berraklaştığını göreceksiniz.

Modüllerin Yolu

Kendi yazdığımız modülleri anlatırken şöyle bir problemden söz etmiştik: Kendimiz bir modül yazdığımızda, bu modülü düzgün bir şekilde içe aktarabilmemiz için o modülün mevcut çalışma dizini içinde yer alıyor olması gerekiyor. Yani eğer içe aktarmaya çalıştığımız modül, o anda bulunduğumuz dizin içinde değilse ImportError adlı bir hata alıyoruz. Ancak böyle bir problem, mesela os modülünde bulunmuyor. Biz o anda hangi dizin altında bulunursak bulunalım, her halükarda os modülünü rahatlıkla içe aktarabiliyoruz. İşte bu bölümde biz bu durumun nedenini anlatmaya çalışacağız.

Python bir modülü içe aktarmaya çalışırken belli dizinlerin içine bakar. Eğer aranan modül o dizinlerin içinde yoksa Python yukarıda bahsettiğimiz ImportError hatasını verecektir. Peki Python bir modülü ararken hangi dizinlerin içine bakar?

Python bir modülü ararken ilk olarak mevcut çalışma dizinine bakar. Yani içe aktarmaya çalıştığımız modülü ilk olarak, komut satırının açıldığı dizin içinde bulmaya çalışır. Peki ya aranan modül mevcut çalışma dizini içinde yoksa?

Böyle bir durumda Python tabii ki hemen pes etmez. Çünkü bakması gereken başka dizinler de vardır...

Python’da sys adlı bir modül bulunur. (Bu modüle ilişkin bilgiyi “Modül Dizini” başlıklı bölümümüzde bulabilirsiniz.) Bu modülün path adlı bir niteliği vardır. İşte Python bir modülü ararken bu niteliğin gösterdiği dizinlerin içine bakar. Yani:

>>> import sys

>>> sys.path

['', '/usr/local/lib/python2.6/dist-packages/setuptools-0.6c11-py2.6.egg',
'/usr/local/lib/python2.6/dist-packages/docutils-0.6-py2.6.egg',
'/usr/local/lib/python2.6/dist-packages/Jinja2-2.4.1-py2.6.egg',
'/usr/local/lib/python2.6/dist-packages/Pygments-1.3.1-py2.6.egg',
'/usr/local/lib/python2.6/dist-packages/Sphinx-1.0b2-py2.6.egg',
'/usr/lib/python2.6', '/usr/lib/python2.6/plat-linux2',
'/usr/lib/python2.6/lib-tk', '/usr/lib/python2.6/lib-old',
'/usr/lib/python2.6/lib-dynload', '/usr/lib/python2.6/dist-packages',
'/usr/lib/python2.6/dist-packages/PIL', '/usr/lib/python2.6/dist-packages/gst-0.10',
'/usr/lib/pymodules/python2.6', '/usr/lib/python2.6/dist-packages/gtk-2.0',
'/usr/lib/pymodules/python2.6/gtk-2.0', '/usr/local/lib/python2.6/dist-packages']

Elbette kullandığınız işletim sistemine bağlı olarak sizde bu komutun çıktısı farklı olacaktır.

İşte Python bir modülü içe aktarmaya çalıştığımız zaman bu çıktıda görünen dizinlerin içini tek tek kontrol edecek ve aradığımız modülün bu dizinlerden herhangi birinin içinde olup olmadığına bakacaktır. Eğer aradığımız modül bu dizinlerden herhangi birinin içindeyse ne ala! Ama eğer modül bu dizinlerin hiç birinde yoksa işte o zaman biraz önce bahsettiğimiz o ImportError hatasını alırız.

Gördüğünüz gibi, sys.path çıktısı aslında basit bir listeden ibarettir. Dolayısıyla listeler üzerinde yapabileceğiniz her şeyi bu sys.path çıktısı üzerinde de yapabilirsiniz. Mesela bu listeye yeni dizinler ekleyebilirsiniz:

>>> sys.path.append("/herhangi/bir/dizin")

Ancak unutmayın ki, sys.path listesine sonradan eklediğiniz dizinler kalıcı değildir. Yazdığınız program sona erdiğinde sys.path listesi de eski haline dönecektir.

Bölüm Soruları

1. Modüller konusunu anlatırken şöyle bir örnek vermiştik:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import aritmetik

print aritmetik.cikar(1455, 32)

print "pi sayısının değeri: %s" %aritmetik.pi_sayisi

Bu programda, aritmetik modülünün içe aktarılması sırasında bir hata ortaya çıkabileceğini göz önüne alarak bu programı yeniden yazın.

2. Dediğimiz gibi, bütün Python programları temelde birer modüldür. Ancak modül ve alelade bir Python programı arasında bazı farklar da vardır. Modüller konusunu anlatırken söylediklerimizi de dikkate alarak, modülleri alelade Python programlarından ayıran özelliklerin neler olabileceğini tartışın. Bir Python programının gerçek anlamda bir modül olabilmesi ve ciddi olarak bir işe yarayabilmesi için modülü yazarken sizce hangi noktalara dikkat etmek gerekir?

3. Python modüllerini kaç farklı şekilde içe aktarabiliyoruz? Bu içe aktarma biçimleri arasındaki farklar nelerdir? Bunlar içinde sizce en mantıklısı ve en kullanışlısı hangisidir?

4. Modüller, yazdığınız Python programlarını organize etmenizi sağlar. Örneğin binlerce satırdan oluşan tek bir .py dosyası yazmaktansa, programınızı ayrı ayrı modüllere bölebilirsiniz. Mesela programınızda arayüzle ilgili olan kodları bir modül, asıl işi yapan kodları ise başka bir modül olarak düzenleyebilirsiniz. Ya da mesela programınızla ilgili ayarları kontrol eden kodları farklı bir modüle yerleştirebilirsiniz. Daha sonra birbirinden ayırdığınız bu modülleri içe aktarmak suretiyle kullanabilirsiniz. Böylece kalabalık kod yığınlarını yönetmek ve bunların bakımını yapmak çok daha kolay bir iş haline gelir. Bu bilgiler ışığında, şu ana kadar Python programlama dilini öğrenirken alıştırma olsun diye yazdığınız programları modüllere ayırmaya çalışın. Programlarınızı modüllere ayırmanın getirileri üzerinde düşünün.

5. os modülünü kullanarak, yalnızca GNU/Linux veya yalnızca Windows üzerinde çalışan bir program yazın.

6. pyPdf modülünden yararlanarak bir pdf belgesinin 2, 5 ve 7. sayfalarını ayrı bir pdf belgesi olarak kaydetmeyi deneyin.

7. Bir dizin içinde yer alan bütün dosyalar içinde, yalnızca uzantısı .txt olanları listeleyin.

8. Python’da sys.path gibi bir niteliğin olmasının, yazacağınız programlar açısından ne gibi faydaları olabileceğini tartışın.

9. os modülündeki system() fonksiyonu son derece güçlü bir araçtır. Bu güçlü aracın, yanlış kullanıldığında nelere mal olabileceği üzerinde düşünün.