Python yorumlayıcısını kapatıp tekrar açarsanız yaptığınız tanımlar (fonksiyonlar ve değişkenler) kaybolur. Uzunca bir program yazmak isterseniz bunun için programınızı bir metin editörü ile hazırlayıp yarattığınız dosyayı yorumlayıcı girişi olarak kullanırsanız daha iyi olur. Bu işleme betik (script) yazmak denir. Programınız uzadıkça bunu daha kolay idare etmek için birkaç dosyaya bölmek isteyebilirsiniz. Yazdığınız bir fonksiyonu tanımını kopyalamaya ihtiyaç duymaksızın birkaç programda kullanmayı da isteyebilirsiniz.
Bu iş için Python'da modül denen dosyalar var. Bunlara yazılan
tanımlar diğer modüllere ya da etkileşimli kipteki yorumlayıcıya
import
deyimi ile yüklenebilirler.
Modüller .py uzantılı metin dosyalarıdır ve içlerinde Python
deyimleri ve tanımları bulur. Bir modül içerisinde __name__
global değişkeninin değeri (bir karakter dizisi) o modülün adını
verir.
Örneğin, favori metin editörünüz ile fibo.py adlı bir dosya
yaratıp Python yorumlayıcısının bulabileceği bir dizine kaydedin.
Dosyanın içeriği de şu olsun:
# Fibonacci sayıları modülü def fib(n): # n e kadar Fibonacci serisini yazdır a, b = 0, 1 while b < n: print b, a, b = b, a+b def fib2(n): # n e kadar Fibonacci serisi geri döndürür sonuc = [] a, b = 0, 1 while b < n: sonuc.append(b) a, b = b, a+b return sonuc
Yorumlayıcıyı açıp bu modülü şu komut ile yükleyin:
>>> import fibo
Bu fibo
içindeki fonksiyon tanımlarını yürürlükte olan simge
tablosuna eklemez; sadece modül adı fibo
tabloya eklenir.
Fonksiyonlara modül adı kullanarak erişilebilir:
>>> fibo.fib(1000) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 >>> fibo.fib2(100) [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] >>> fibo.__name__ 'fibo'
Bir fonksiyonu sık sık kullanmak isterseniz bunu yerel bir isme atayabilirsiniz:
>>> fib = fibo.fib >>> fib(500) 1 1 2 3 5 8 13 21 34 55 89 144 233 377
Fonksiyon tanımlarının yanısıra modül içinde çalıştırılabilir ifadeler de olabilir. Bu ifadeler modülün ilk kullanıma hazırlanması için kullanılabilirler ve sadece modülün ilk yüklenişinde çalışırlar.6.1
Her modülün o modül içindeki bütün fonksiyonlar tarafından global
simge tablosu olarak kullanılan kendi simge tablosu vardır. Bu özellik
sayesinde modülü yazan kişi rahatlıkla modül içinde global değişkenler
kullanabilir. Modülü kullanan diğer kişilerin global değişkenleri ile
isim çakışması olmaz. Modul içindeki global değişkenlere de
modulAdi.degiskenAdi
şeklinde ulaşmak ve istenirse bunları
değiştirmek mümkündür.
Modüller diğer modülleri yükleyebilirler. Bütün import ifadelerinin modülün (ya da betiğin) başına konması gelenektendir; ancak şart değildir. Yüklenen modüller kendilerini yükleyen modülün global simge tablosuna ekleniriler.
import deyiminin bir modüldeki isimleri doğrudan yükleyen modülün simge tablosuna ekleyen kullanım şekli var. Örnek:
>>> from fibo import fib, fib2 >>> fib(500) 1 1 2 3 5 8 13 21 34 55 89 144 233 377
Bu kullanım şekinde yüklemenin yapıldığı modül adı yerel simge tablosuna eklenmez (yani örnekteki codefibo tanımlı değildir).
Bir modülde tanımlanmış bütün isimleri de yüklemek şu şekilde mümkündür:
>>> from fibo import * >>> fib(500) 1 1 2 3 5 8 13 21 34 55 89 144 233 377
Bu altçizgi (_
) ile başlayanlar dışındaki bütün isimleri
yükler.
spam isimli bir modül yüklenmek istendiğinde yorumlayıcı önce çalıştırıldığı dizinde ve sonra PYTHONPATH ortam değişkenince tanımlanan dizinler içinde spam.py isimli bir dosya arar. PYTHONPATH dizin isimlerinden oluşan bir listedir ( PATH gibi). Aranan dosya bulunmazsa arama kuruluma bağlı başka bir yolda da aranabilir. Unix işletim sisteminde bu .:/usr/local/lib/python dizinidir.
Aslında modüller sys.path
değişkeninde bulunan dizin
listesinde aranırlar. Bu değişken değerini betiğin çalıştırıldığı
dizin, PYTHONPATH ve kuruluma bağlı diğer dizinlerden alır.
sys.path
değişkeni sayesinde Python programları modül arama
yolunu değiştirebilirler.
Derlenmiş Python dosyaları programların çalışmaya başlaması için gereken süreyi kısaltırlar. Örneğin spam.py adlı dosyanın bulunduğu dizinde spam.pyc adlı bir dosya varsa bu modüle spam modülünün ``bayta derlenmiş'' (byte-compiled) halidir. spam.py dosyasının son değiştirilme tarihi spam.pyc dosyasının içinde de kayıtlıdır ve bu tarihler aynı değil ise .pyc dosyası dikkate alınmaz.
spam.pyc dosaysının oluşması için bir şey yapmanız gerekmez. spam.py her ne zaman başarılı olarak derlenirse programın derlenmiş hali spam.pyc dosyasına kaydedilir. Bunun yapılamaması bir hata değildir; herhangi bir nedenle .pyc dosyası tam olarak yazılamazsa geçersiz sayılır ve dikkate alınmaz. .pyc dosyalarının içeriği platformdan bağımsızdır. Bu sayede bir Python modülü dizini farklı mimarideki makineler tarafından paylaşılabilir.
Uzmanlar için birkaç ip ucu:
Python yorumlayıcısı -O parametresi ile çalıştırıldığında
eniyileştirilmiş (optimized) kod üretilir ve .pyo uzantılı
dosyalarda saklanır. Eniyileştircinin (optimizer) şu anda pek bir
yararı olmuyor; sadece assert deyimlerini siliyor.
-O parametresi
kullanıldığında tüm baytkodu eniyileştirilir, .pyc
dosyaları göz ardı edilir ve .py
dosyaları eniyileştirilmiş
baytkoduna derlenir.
__doc__
karakter dizileri silinerek daha küçük
.pyo dosyaları üretilmektedir. Bazı programların çalışması
bunların varlığına bağımlı olabileceğinden bu parametreyi kullanırken
dikkatli olun.
Python zengin bir standart modül kütüphanesine sahiptir. Bazı modüller
yorumlayıcı ile bütünleşiktir. Bu modüller dilin parçası olmadıkları
halde verimlerini artırmak ya da sistem çağrıları gibi işletim
sistemine ait özelliklere erişim için yrumlayıcı içine dahil
edilmişlerdir. Bunlara iyi bir örnek her Python yorumlayıcısına dahil
edilen sys modülüdür. sys.ps1
ve
sys.ps2
değişkenleri de birincil ve ikincil komut satırı olarak
kullanılan karakter dizilerini belirlerler:
>>> import sys >>> sys.ps1 '>>> ' >>> sys.ps2 '... ' >>> sys.ps1 = 'C> ' C> print 'Böö !' Böö ! C>
Bu iki değişken yorumlayıcı sadece etkileşimli kipte iken tanımlıdırlar.
sys.path
değişkeni de yorumlayıcının modül arama yolunu
belirler. Bu değerini ortam değişkeni PYTHONPATH belirler.
PYTHONPATH değişkenine değer atanmadıysa sys.path
varsayılan (default) değerini alır. Bunun değeri listelere uygulana
işlemler ile değiştirilebilir:
>>> import sys >>> sys.path.append('/ufs/guido/lib/python')
Yerleşik fonksiyon dir() bir modülün hangi isimleri tanımladığını bulmak içik kullanılır. Bu fonksiyon karakter dizilerinden oluşan bir liste geri döndürür:
>>> import fibo, sys >>> dir(fibo) ['__name__', 'fib', 'fib2'] >>> dir(sys) ['__displayhook__', '__doc__', '__excepthook__', '__name__', '__stderr__', '__stdin__', '__stdout__', '_getframe', 'argv', 'builtin_module_names', 'byteorder', 'copyright', 'displayhook', 'exc_info', 'exc_type', 'excepthook', 'exec_prefix', 'executable', 'exit', 'getdefaultencoding', 'getdlopenflags', 'getrecursionlimit', 'getrefcount', 'hexversion', 'maxint', 'maxunicode', 'modules', 'path', 'platform', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setdlopenflags', 'setprofile', 'setrecursionlimit', 'settrace', 'stderr', 'stdin', 'stdout', 'version', 'version_info', 'warnoptions']
Argüman kullanmadan çağırılan dir() fonksiyonu o anda tanımlamış olduğunuz isimleri geri döndürür:
>>> a = [1, 2, 3, 4, 5] >>> import fibo, sys >>> fib = fibo.fib >>> dir() ['__name__', 'a', 'fib', 'fibo', 'sys']
Bunun değişken, modül, fonksiyon vs. gibi her tip ismi listelediğine dikkat ediniz.
dir() yerleşik fonksiyon ve değişkenlerin isimlerini listelemez. Bunların bir listesini isterseniz, standart modül __builtin__ içinde bulabilirsiniz:
>>> import __builtin__ >>> dir(__builtin__) ['ArithmeticError', 'AssertionError', 'AttributeError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'IOError', 'ImportError', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'OverflowWarning', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeError', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '__debug__', '__doc__', '__import__', '__name__', 'abs', 'apply', 'bool', 'buffer', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'min', 'object', 'oct', 'open', 'ord', 'pow', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'round', 'setattr', 'slice', 'staticmethod', 'str', 'string', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip']
Paketler ``noktalı modül isimleri'' kullanarak Python'un modül isim alanının düzenlenmesinde kullanılırlar. Örneğin modül adı A.B adı "A" olan bir paket içindeki "B" adlı alt modülü gösterir. Nasıl modüller farklı modül yazarlarını birbirilerinin kullandığı global değişkenleri dert etmekten kurtarıyorsa, paketler de NumPy ya da PyOpenGL gibi çok sayıda modül içeren paketlerin biribirilerinin modül isimlerinin çakışması tehlikesinden kurtarır.
Ses dosyaları ve ses verisi üzerinde işlem yapacak bir modül kolleksiyonu (bir ``paket'') geliştirmek istediğinizi düşünelim. Farklı formatlardaki ses dosyalarını (.wav, .aiff, .au gibi dosya uzantıları olan) biribirine dönüştürmek, seslere efektler uygulamak veya sesleri filtrelemek için pek çok modüle ihtiyacınız olacak. Paketinizin muhtemel dizin yapısı şöyle olabilir:
Sound/ Paketin en üst seviyesi __init__.py paketi ilk kullanıma hazırlama Formats/ Farklı dosya formatları için alt paket __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... Effects/ ses efektleri alt paketi __init__.py echo.py surround.py reverse.py ... Filters/ filtre alt paketi __init__.py equalizer.py vocoder.py karaoke.py ...
__init__.py dosyaları Python'un bu dizinleri paket içeren
dizinler olarak algılaması için gereklidirler. Bunlar aynı isimli
dizinlerin modül arama yolunda bulunacak diğer geçerli modülleri istem
dışı saklamasını engeller. __init__.py boş bir dosya
olabileceği gibi paketi ilk çalışmaya hazırlayabilir ya da daha sonra
açıklanacak olan __all__
değişkenine değer atıyor olabilir.
Paketin kullanıcısı paketten dilediği bir modülü yükleyebilir.
import Sound.Effects.echo
Bu Sound.Effects.echo modülünü yükler. Modüle tüm ismi ile atıfta bulunulmalı:
Sound.Effects.echo.echofilter(input, output, delay=0.7, atten=4)
Aynı modülü yüklemenin bir diğer yolu:
from Sound.Effects import echo
Bu da echo alt modülünü yükler; ancak bunu paket adı verilmeden erişilebilir kılar ve modül şu şekilde kullanılabilir:
echo.echofilter(input, output, delay=0.7, atten=4)
Bir diğer yol da istene fonksiyon ya da değişkeni doğrudan yüklemektir:
from Sound.Effects.echo import echofilter
Bu da echo modülünü yükler; ancak echofilter() fonksiyonnu doğrudan erişilebilir kılar:
echofilter(input, output, delay=0.7, atten=4)
from paket import isim
kullanılırken isim bir
alt modül, alt paket ya da paket içinde tanımlı bir fonksiyon, sınıf
veya değişken ifade eden herhangi bir isim olabilir. import
deyimi önce ismin pakette tanımlı olup olmadığına bakar; tanımlı değil
ise bunun bir modül olduğunu varsayar ve bunu yüklemeye teşebbüs eder.
Modülü bulamaz ise ImportError istisnası oluşur.
import item.subitem.subsubitem
ifadesinde ise son ismin
dışındaki isimler paket olmalıdır. Son isim bir modül veya paket
olabilir; ancak bir önceki ismin içinde tanımlanan bir fonksiyon ya
da değişken olamaz.
Kullanıcı from Sound.Effects import *
yazdığında ne olur ?
Dosya sistemine ulaşılıp paketin içinde hangi alt paketlerin olduğunun
bulunması ve hepsinin yüklenmesi beklenir. Ne yazık ki bu işlem küçük/
büyük harf ayrımının olmadığı Windows ve Mac işetim sistemlerinde pek
iyi çalışmaz. Bu işletim sistemlerinde ECHO.PY gibi bir
dosyanın echo, Echo veya ECHO isimlerinden
hangisi ile yüklenmesi gerektiğini belirlemenin garantili bir yolu
yoktur. Örneğin, Windows 95 dosya adlarının ilk harfini daima büyük
harf ile gösterir. DOS'un 8+3 harflik dosya adı uzunluğu kısıtlaması
da uzun modül isimleri için sorun olmaktadır.
Tek çözüm paket yazarının açık bir paket indeksi hazırlamasıdır. Bir
paketin __init__.py dosyası __all__
adlı bir liste
tanımlıyorsa bu liste from package import *
ifadesi
kullanıldığında yüklenecek modül isimlerinin listesi olarak
kullanılır. Pedein yeni bir sürümü hazırlandığında bu listenin uygun
şekilde güncellenmesi paket yazarının sorumluğundadır. Eğer paketten *
yüklemeye ihtiyaç duyulmayacağına karar verilirse bu özellik
kullanılmayabilir. Örneğin Sounds/Effects/__init__.py
dosyasının içeriği şöyle olabilir:
__all__ = ["echo", "surround", "reverse"]
Bu from Sound.Effects import *
ifadesinin Sound
paketinden isimleri __all__
içinde geçen üç modülün yüklemesini
sağlar.
__all__
tanımlanmamış ise from Sound.Effects import *
ifadesi Sound.Effects paketindeki bütün alt modülleri
yürülükte olan isim alanına yüklemez; sadece
Sound.Effects paketinin ve içindeki isimlerin yüklenmesini sağlar (
muhtemelen __init__.py) dosyasını çalıştırdıktan sonra). Bundan
önceki import deyimlerince yüklenen alt paketler de
yüklenir. Şu koda bir bakalım:
import Sound.Effects.echo import Sound.Effects.surround from Sound.Effects import *
Bu örnekte echo ve surround modülleri from...import
ifadesi
çalıştırıldığında Sound.Effects paketinde tanımlı oldukları
için yürürlükte olan isim alanına yüklenirler. Bu __all__
tanımlı olduğunda da bu çalışır.
Genel olarak bir modül ya da paketten * yüklemek hoş karşılanmaz; çünkü çoğunlukla zor okunan koda neden olur. Bunun etkileşimli kipte kullanılmasının bir sakıncası yoktur. Ayrıca bazı modüller sadece belirli bir kalıba uyan isimleri verecek şekilde tasarlanmışlardır.
from Paket import gerekli_altmodül
ifadesini kullanmanın hiç
bir kötü tarafı yoktur. Yükleyen modül farklı paketlerden aynı isimli
modüller yüklemeye gereksinim duymadığı sürece tavsiye edilen kullanım
şekli de budur.
Alt modüller çoğu kez birbirilerine atıfta bulunurlar. Örneğin
surround modülü echo modülüne ihtiyaç duyabilir.
Aslında bu türden atıflar öyle yaygındır ki import
deyimi
standart modül arama yoluna bakmadan önce çağırıldığı paketin içinde
arama yapar. Bu şekilde surround modülü import echo
veya from echo import echofilter
ifadeleri ile kolayca
echo modülüne kavuşabilir. Yüklenmek istenen modül içinde bulunan
pakette (yükleme yağmaya çalışan modülün bulunduğu paket) bulunamaz
ise import
deyimi aynı isimli üst seviyeli bir modül arar.
Paketler Sound paketindeki gibi alt paketler şeklinde
düzenlenmişler ise farklı alt paketler içindeki modüllerin
birbirilerine atıfta bulunmasının kısa bir yolu yoktur; paketin tam
adı kullanılmalıdır. Örneğin, Sound.Filters.vocoder modülünün
echo modülünü kullanması gerekiyor ise from
Sound.Effects import echo
ifadesi ile buna erişebilir.