6. Modüller
- 6.1. Modüller Üzerine Daha Fazla Bilgi
-
- 6.1.1. Modül Arama Yolu
- 6.1.2. "Derlenmiş" Python Dosyaları
- 6.2. Standart Modüller
- 6.3.
dir()İşlevi - 6.4. Paketler
-
- 6.4.1. Bir paketten * yüklemek
- 6.4.2. Birbirlerini Yükleyen Modüller
Python yorumlayıcısını kapatıp tekrar açarsanız yaptığınız tanımlar (işlevler ve değişkenler) kaybolur. Uzunca bir yazılım yazmak isterseniz bunun için yazılımınızı bir metin düzenleyici ile hazırlayıp yazdığınız dosyayı yorumlayıcı girişi olarak kullanırsanız daha iyi olur. Bu işleme betik yazmak denir. Programınız uzadıkça bunu daha kolay idare etmek için birkaç dosyaya bölmek isteyebilirsiniz. Yazdığınız bir işlev tanımını kopyalamaya ihtiyaç duymaksızın birkaç yazılımda 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üklenebilir.
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 dizge) o
modülün adını verir. Örneğin, favori metin düzenleyiciniz 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 işlev tanımlarını yürürlükte olan simge tablosuna eklemez; sadece modül adı fibo tabloya eklenir. İşlevlere 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 işlevi 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
6.1. Modüller Üzerine Daha Fazla Bilgi
İşlev 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ışır.[70]
Her modülün o modül içindeki bütün işlevler 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çnde global değişkenler
kullanabilir. Modülü kullanan diğer kişilerin global değişkenleri ile
isim çakışması olmaz. Modül 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ükleyebilir. 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 eklenir.
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 şeklinde yüklemenin yapıldığı modül adı yerel simge tablosuna eklenmez (yani örnekteki fibo 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.
6.1.1. Modül Arama Yolu
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. Genelde bu /usr/local/lib/python
dizinidir.
Aslında modüller sys.path değişkeninde bulunan dizin
listesinde aranır. 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 yazılımları modül
arama yolunu değiştirebilir.
6.1.2. "Derlenmiş" Python Dosyaları
Derlenmiş Python dosyaları yazılımların çalışmaya başlaması için
gereken süreyi kısaltır. Örneğin spam.py adlı
dosyanın bulunduğu dizinde spam.pyc adlı bir dosya
varsa bu modul, spam modülünün ikilik derlenmiş
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 dosyasının oluşması için bir şey yapmanız
gerekmez. spam.py her ne zaman başarılı olarak
derlenirse yazılımı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ı
-Obağımsız değişkeni ile çalıştırıldığında eniyileştirilmiş (optimized) kod üretilir ve.pyouzantılı dosyalarda saklanır. Eniyileştircinin (optimizer) şu anda pek bir yararı olmuyor; sadeceassertdeyimlerini siliyor.-Obağımsız değişkeni kullanıldığında tüm ikilik kod eniyileştirilir,.pycdosyaları göz ardı edilir ve.pydosyaları eniyileştirilmiş ikilik kod olarak derlenir. -
Yorumlayıcıya iki tane
-Obağımsız değişkeni (-OO) vermek derleyicinin bazı ender durumlarda doğru çalışmayan yazılımlara neden olan eniyileştirmeler yapmasına neden olur. Şu anda sadece__doc__dizgeleri silinerek daha küçük.pyodosyaları üretilmektedir. Bazı yazılımların çalışması bunların varlığına bağımlı olabileceğinden bu bağımsız değişkeni kullanırken dikkatli olun. -
Bir yazılım
.pycya da.pyodosyasından okunduğunda.pydosyasından okunan halinden daha hızlı çalışmaz; sadece yüklenme süresi kısalır. -
Bir betik komut satırından ismi verilerek çalıştırıldığında bunun ikilik kodu asla bir
.pycya da.pyodosyasına yazılmaz. Bu yüzden betiğin başlama süresini kısaltmak için bunun bir kısmı bir modüle aktarılarak ve bu modülü yükleyen küçük bir başlatıcı betik kullanılarak kısaltılabilir. Komut satırından bir.pycya da.pyodosyası da ismi verilerek doğrudan çalıştırılabilir. -
spam.pydosyası olmadan daspam.pyc(ya da-Okullanıldığındaspam.pyo) dosyası kullanılabilir. Bunlar bir Python kodu kütüphanesinin tersine mühendisliği zorlaştıran şekilde dağıtılmasında kullanılabilir. -
compileallmodülü bir dizindeki bütün dosyalar içinspam.pyc(ya da-Okullanıldığındaspam.pyo) dosyaları yaratabilir.
6.2. Standart Modüller
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 yorumlayı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 dizgeleri 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ır.
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 öntanımlı değerini alır. Bunun değeri
listelere uygulana işlemler ile değiştirilebilir:
>>>import sys>>>sys.path.append('/ufs/guido/lib/python')
6.3. dir() İşlevi
Yerleşik işlev dir() bir modülün hangi isimleri
tanımladığını bulmak içik kullanılır. Bu işlev dizgelerden 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']
Bağımsız değişken kullanmadan çağırılan dir()
işlevi 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, işlev vs. gibi her tür ismini listelediğine dikkat ediniz.
dir() yerleşik işlev 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']
6.4. Paketler
Paketler "noktalı modül isimleri" kullanarak Python'un modül isim
alanının düzenlenmesinde kullanılır. Ö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ı birbirlerinin kullandığı global değişkenleri
dert etmekten kurtarıyorsa, paketler de NumPy ya da
PyOpenGL gibi çok sayıda modül içeren paketlerin
birbirlerinin 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ı biçemlerdeki ses
dosyalarını (.wav, .aiff,
.au gibi dosya uzantıları olan) birbirine 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 biçemleri 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 gereklidir. Bunlar aynı isimli
dizinlerin modül arama yolunda bulunacak diğer geçerli modülleri istemdışı
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 istenen işlev 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() işlevini doğrudan erişilebilir kılar:
echofilter(input, output, delay=0.7, atten=4)
from PAKET import İSİM kullanılırken İSİM bir alt
modül, alt paket ya da paket içinde tanımlı bir işlev, 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 ÖĞE.ALTÖĞE.ALTALTÖĞE 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 işlev ya da
değişken olamaz.
6.4.1. Bir paketten * yüklemek
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. Bu uzun zaman alabilir ve alt modüllerin içe aktarılmasının, yalnızca alt modül açıkça içe aktarıldığında ortaya çıkan istenmeyen yan etkileri olabilir.
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 PAKET import * ifadesi kullanıldığında
yüklenecek modül isimlerinin listesi olarak kullanılır. Paketin 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ürlü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üklenir. 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 GEREKLİ_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.
6.4.2. Birbirlerini Yükleyen Modüller
Alt modüller çoğu kez birbirlerine atıfta bulunur. Ö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 yapmaya ç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.
[70] Aslında işlev tanımları da `çalıştırılan' ifadelerdir; işlev adını modülün global simge tablosuna ekler.