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ı
-O
bağımsız değişkeni 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; sadeceassert
deyimlerini siliyor.-O
bağımsız değişkeni kullanıldığında tüm ikilik kod eniyileştirilir,.pyc
dosyaları göz ardı edilir ve.py
dosyaları eniyileştirilmiş ikilik kod olarak derlenir. -
Yorumlayıcıya iki tane
-O
bağı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.pyo
dosyaları ü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
.pyc
ya da.pyo
dosyasından okunduğunda.py
dosyası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
.pyc
ya da.pyo
dosyası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.pyc
ya da.pyo
dosyası da ismi verilerek doğrudan çalıştırılabilir. -
spam.py
dosyası olmadan daspam.pyc
(ya da-O
kullanı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. -
compileall
modülü bir dizindeki bütün dosyalar içinspam.pyc
(ya da-O
kullanı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.