6. Modüller
***********

Python yorumlayıcısından çıkıp tekrar girerseniz, yaptığınız tanımlar
(fonksiyonlar  ve değişkenler) kaybolur. Bu nedenle, daha uzun bir
program yazmak istiyorsanız, girdiyi yorumlayıcıya hazırlarken bir
metin düzenleyicisi kullanmak ve o dosyayla girdi olarak çalıştırmak
daha iyidir.  Bu bir *script* oluşturma olarak bilinir.  Programınız
uzadıkça, daha kolay bakım için birkaç dosyaya bölmek
isteyebilirsiniz.  Ayrıca, tanımını her programa kopyalamadan, birkaç
programda yazdığınız kullanışlı bir fonksiyonu kullanmak
isteyebilirsiniz.

Bunu desteklemek için Python, tanımları bir dosyaya koymanın ve
bunları bir komut dosyasında veya yorumlayıcının etkileşimli bir
örneğinde kullanmanın bir yolunu sağlar. Böyle bir dosyaya *module*
denir; bir modülden alınan tanımlar diğer modüllere veya *main*
modülüne (en üst düzeyde ve hesap makinesi modunda yürütülen bir komut
dosyasında erişiminiz olan değişkenlerin derlenmesi) aktarılabilir.

Modül, Python tanımlarını ve ifadelerini içeren bir dosyadır.  Dosya
adı, ".py" son ekini içeren modül adıdır.  Bir modül içinde, modülün
adı (dize olarak) "__name__" genel değişkeninin değeri olarak
kullanılabilir.  Örneğin, geçerli dizinde aşağıdaki içeriklerle
"fibo.py" adlı bir dosya oluşturmak için en sevdiğiniz metin
düzenleyicisini kullanın:

   # Fibonacci numbers module

   def fib(n):    # write Fibonacci series up to n
       a, b = 0, 1
       while a < n:
           print(a, end=' ')
           a, b = b, a+b
       print()

   def fib2(n):   # return Fibonacci series up to n
       result = []
       a, b = 0, 1
       while a < n:
           result.append(a)
           a, b = b, a+b
       return result

Şimdi Python yorumlayıcısına girin ve bu modülü aşağıdaki komutla içe
aktarın:

   >>> import fibo

Bu, "fibo" 'da tanımlanan işlevlerin adlarını doğrudan geçerli
*namespace* 'e  eklemez (daha fazla ayrıntı için bkz. Python Etki
Alanları ve Ad Alanları); oraya sadece "fibo" modül adını ekler. Modül
adını kullanarak şu işlevlere erişebilirsiniz:

   >>> fibo.fib(1000)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
   >>> fibo.fib2(100)
   [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
   >>> fibo.__name__
   'fibo'

Bir işlevi sık sık kullanmayı düşünüyorsanız, işlevi yerel bir ada
atayabilirsiniz:

   >>> fib = fibo.fib
   >>> fib(500)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377


6.1. Modüller hakkında daha fazla
=================================

Bir modül, işlev tanımlarının yanı sıra çalıştırılabilir ifadeler de
içerebilir. Bu ifadeler modülü başlatmayı amaçlamaktadır. Yalnızca bir
import ifadesinde modül adıyla karşılaşıldığında *ilk* kez
yürütülürler. [1] (Dosya komut dosyası olarak yürütülürse de
çalıştırılırlar.)

Her modülün, modülde tanımlanan tüm işlevler tarafından genel ad alanı
olarak kullanılan kendi özel ad alanı vardır. Böylece, bir modülün
yazarı, bir kullanıcının genel değişkenleriyle yanlışlıkla çakışma
endişesi duymadan, modüldeki genel değişkenleri kullanabilir. Öte
yandan, ne yaptığınızı biliyorsanız, bir modülün global
değişkenlerine, işlevlerine atıfta bulunmak için kullanılan
"modname.itemname" notasyonuyla dokunabilirsiniz.

Modüller diğer modülleri içe aktarabilir. Tüm "import" ifadelerinin
bir modülün (veya bu konuda betiğin) başına yerleştirilmesi alışılmış
bir durumdur ancak gerekli değildir. İçe aktarılan modül adları, bir
modülün en üst düzeyine yerleştirilirse (herhangi bir işlev veya
sınıfın dışında), modülün genel ad alanına eklenir.

"import" ifadesinin, bir modülden adları doğrudan içe aktaran modülün
ad alanına aktaran bir çeşidi vardır. Örneğin:

   >>> from fibo import fib, fib2
   >>> fib(500)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

Bu, içe aktarmaların yerel ad alanında alındığı modül adını
tanıtmaz(bu nedenle örnekte "fibo" tanımlanmamıştır).

Bir modülün tanımladığı tüm adları içe aktarmak için bir varyant bile
vardır:

   >>> from fibo import *
   >>> fib(500)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

Bu, alt çizgiyle başlayanlar ("_") dışındaki tüm isimleri alır. Çoğu
durumda Python programcıları bu özelliği kullanmaz, çünkü
yorumlayıcıya bilinmeyen bir ad kümesi ekler ve muhtemelen önceden
tanımladığınız bazı şeyleri gizler.

Genel olarak, bir modülden veya paketten "*" içeri aktarma
uygulamasının, genellikle okunamayan koda neden olduğundan hoş
karşılanmadığına dikkat edin. Ancak, etkileşimli oturumlarda yazmayı
kaydetmek için kullanmak sorun değildir.

Modül adının ardından "as" geliyorsa, "as" 'den sonraki ad doğrudan
içe aktarılan modüle bağlanır.

   >>> import fibo as fib
   >>> fib.fib(500)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

Bu, modülün "import fibo" 'nun yapacağı şekilde etkin bir şekilde içe
aktarılmasıdır, tek farkı "fib" olarak mevcut olmasıdır.

Benzer efektlere sahip "from" kullanılırken de kullanılabilir:

   >>> from fibo import fib as fibonacci
   >>> fibonacci(500)
   0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

Not:

  Verimlilik nedeniyle, her modül yorumlayıcı oturumu başına yalnızca
  bir kez içe aktarılır.  Bu nedenle, modüllerinizi değiştirirseniz,
  yorumlayıcıyı yeniden başlatmanız gerekir - veya etkileşimli olarak
  test etmek istediğiniz tek bir modülse, "importlib.reload()",
  örneğin "importlib; importlib.reload(modulename)".


6.1.1. Modülleri komut dosyası olarak yürütme
---------------------------------------------

Bir Python modülünü :: ile çalıştırdığınızda:

   python fibo.py <arguments>

modüldeki kod, içe aktardığınız gibi yürütülür, ancak "__name__"
""__main__"" olarak ayarlanır. Bu, modülünüzün sonuna bu kodu
ekleyerek:

   if __name__ == "__main__":
       import sys
       fib(int(sys.argv[1]))

dosyayı bir komut dosyası ve içe aktarılabilir bir modül olarak
kullanılabilir hale getirebilirsiniz, çünkü komut satırını ayrıştıran
kod yalnızca modül "main" dosya olarak yürütülürse çalışır:

   $ python fibo.py 50
   0 1 1 2 3 5 8 13 21 34

Modül içe aktarılırsa kod çalıştırılmaz:

   >>> import fibo
   >>>

Bu genellikle bir modüle uygun bir kullanıcı arabirimi sağlamak veya
test amacıyla kullanılır (modülü komut dosyası olarak çalıştırmak bir
test paketi yürütür).


6.1.2. Modül Arama Yolu
-----------------------

"spam" adında bir modül içe aktarıldığında, yorumlayıcı ilk olarak bu
ada sahip gömülü bir modül arar. Bu modül adları
"sys.builtin_module_names" içinde listelenir. Bulamazsa, "sys.path"
değişkeni tarafından verilen dizin listesinde "spam.py" adlı bir dosya
arar. "sys.path" bu konumlardan başlatılır:

* Girdi komut dosyasını içeren dizin (veya dosya belirtilmediğinde
  geçerli dizin).

* "PYTHONPATH" (kabuk değişkeni "PATH" ile aynı sözdizimine sahip
  dizin adlarının listesi).

* Kuruluma bağlı varsayılan (kural olarak, "site" modülü tarafından
  işlenen bir "site-packages" dizini dahil).

Daha fazla ayrıntı The initialization of the sys.path module search
path adresindedir.

Not:

  Symlink'leri destekleyen dosya sistemlerinde, symlink izlendikten
  sonra girdi komut dosyasını içeren dizin hesaplanır. Başka bir
  deyişle, symlink içeren dizin modül arama yoluna **not** eklenir.

Başlatıldıktan sonra Python programları "sys.path" değiştirebilir.
Çalıştırılmakta olan komut dosyasını içeren dizin, arama yolunun
başına, standart kitaplık yolunun önüne yerleştirilir. Bu, kitaplık
dizininde aynı ada sahip modüller yerine bu dizindeki komut
dosyalarının yüklanacağı anlamına gelir. Değiştirme amaçlanmadığı
sürece bu bir hatadır.  Daha fazla bilgi için Standart modüller
bölümüne bakın.


6.1.3. "Derlenmiş" Python dosyaları
-----------------------------------

Modüllerin yüklenmesini hızlandırmak için Python, her modülün
derlenmiş sürümünü "__pycache__" dizininde "module.*version*.pyc" adı
altında önbelleğe alır; burada sürüm, derlenen dosyanın biçimini
kodlar; genellikle Python sürüm numarasını içerir. Örneğin, CPython
3.3 sürümünde spam.py'nin derlenmiş sürümü
"__pycache__/spam.cpython-33.pyc" olarak önbelleğe alınacaktır. Bu
adlandırma kuralı, farklı sürümlerden ve Python'un farklı
sürümlerinden derlenmiş modüllerin bir arada var olmasına izin verir.

Python, eski olup olmadığını ve yeniden derlenmesi gerekip
gerekmediğini görmek için kaynağın değişiklik tarihini derlenmiş
sürümle karşılaştırır. Bu tamamen otomatik bir işlemdir. Ayrıca,
derlenen modüller platformdan bağımsızdır, bu nedenle aynı kitaplık
farklı mimarilere sahip sistemler arasında paylaşılabilir.

Python iki durumda önbelleği kontrol etmez. İlk olarak, doğrudan komut
satırından yüklenen modülün sonucunu her zaman yeniden derler ve
saklamaz. İkincisi, kaynak modül yoksa önbelleği kontrol etmez. Kaynak
olmayan (yalnızca derlenmiş) bir dağıtımı desteklemek için, derlenen
modül kaynak dizinde olmalı ve bir kaynak modül olmamalıdır.

Uzmanlar için bazı ipuçları:

* Derlenmiş bir modülün boyutunu küçültmek için Python komutundaki
  "-O" veya "-OO" anahtarlarını kullanabilirsiniz. "-O" anahtarı,
  onaylama ifadelerini kaldırır, "-OO" anahtarı, hem assert
  ifadelerini hem de __doc__ dizelerini kaldırır. Bazı programlar
  bunların kullanılabilir olmasına güvenebileceğinden, bu seçeneği
  yalnızca ne yaptığınızı biliyorsanız kullanmalısınız. "Optimize
  edilmiş" modüller bir "opt-" etiketine sahiptir ve genellikle daha
  küçüktür. Gelecekteki sürümler, optimizasyonun etkilerini
  değiştirebilir.

* Bir program ".pyc" dosyasından okunduğunda, ".py" dosyasından
  okunduğundan daha hızlı çalışmaz; ".pyc" dosyaları hakkında daha
  hızlı olan tek şey, yüklenme hızlarıdır.

* "compileall" modülü, bir dizindeki tüm modüller için .pyc dosyaları
  oluşturabilir.

* **PEP 3147** 'de, kararların bir akış şeması da dahil olmak üzere,
  bu süreç hakkında daha fazla ayrıntı bulunmaktadır.


6.2. Standart modüller
======================

Python, ayrı bir belge olan Python Kütüphane Referansında (buradan
itibaren "Kütüphane Referansı") açıklanan standart modüllerden oluşan
bir kütüphaneyle birlikte gelir.  Bazı modüller yorumlayıcıda yerleşik
olarak bulunur; bunlar dilin çekirdeğinin bir parçası olmayan ancak
yine de verimlilik için veya sistem çağrıları gibi işletim sistemi
ilkellerine erişim sağlamak için yerleşik olarak bulunan işlemlere
erişim sağlar.  Bu tür modüllerin kümesi, altta yatan platforma da
bağlı olan bir yapılandırma seçeneğidir.  Örneğin, "winreg" modülü
yalnızca Windows sistemlerinde sağlanır. Belirli bir modül biraz
ilgiyi hak ediyor: "sys", her Python yorumlayıcısında yerleşik olarak
bulunur.  "sys.ps1" ve "sys.ps2" değişkenleri birincil ve ikincil
istemler olarak kullanılan dizeleri tanımlar:

   >>> import sys
   >>> sys.ps1
   '>>> '
   >>> sys.ps2
   '... '
   >>> sys.ps1 = 'C> '
   C> print('Yuck!')
   Yuck!
   C>

Bu iki değişken yalnızca yorumlayıcı etkileşimli moddaysa tanımlanır.

"sys.path" değişkeni, yorumlayıcının modüller için arama yolunu
belirleyen bir dizeler listesidir. "PYTHONPATH" ortam değişkeninden
veya "PYTHONPATH" ayarlanmamışsa yerleşik bir varsayılan değerden
alınan varsayılan bir yola başlatılır. Standart liste işlemlerini
kullanarak değiştirebilirsiniz:

   >>> import sys
   >>> sys.path.append('/ufs/guido/lib/python')


6.3. "dir()" Fonksiyonu
=======================

Yerleşik fonksiyon "dir()", bir modülün hangi adları tanımladığını
bulmak için kullanılır. Sıralanmış bir dize listesi döndürür:

   >>> import fibo, sys
   >>> dir(fibo)
   ['__name__', 'fib', 'fib2']
   >>> dir(sys)  
   ['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__',
    '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__',
    '__stderr__', '__stdin__', '__stdout__', '__unraisablehook__',
    '_clear_type_cache', '_current_frames', '_debugmallocstats', '_framework',
    '_getframe', '_git', '_home', '_xoptions', 'abiflags', 'addaudithook',
    'api_version', 'argv', 'audit', 'base_exec_prefix', 'base_prefix',
    'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing',
    'callstats', 'copyright', 'displayhook', 'dont_write_bytecode', 'exc_info',
    'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info',
    'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth',
    'getallocatedblocks', 'getdefaultencoding', 'getdlopenflags',
    'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile',
    'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval',
    'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info',
    'intern', 'is_finalizing', 'last_traceback', 'last_type', 'last_value',
    'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks',
    'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'pycache_prefix',
    'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'setdlopenflags',
    'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr',
    'stdin', 'stdout', 'thread_info', 'unraisablehook', 'version', 'version_info',
    'warnoptions']

Argümanlar olmadan, "dir()", şu anda tanımladığınız adları listeler:

   >>> a = [1, 2, 3, 4, 5]
   >>> import fibo
   >>> fib = fibo.fib
   >>> dir()
   ['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']

Her tür adın listelendiğini unutmayın: değişkenler, modüller,
fonksiyonlar vb.

"dir()" yerleşik fonksiyonlarun ve değişkenlerin adlarını listelemez.
Bunların bir listesini istiyorsanız, standart modül "builtins" 'de
tanımlanırlar:

   >>> import builtins
   >>> dir(builtins)  
   ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException',
    'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning',
    'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError',
    'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning',
    'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False',
    'FileExistsError', 'FileNotFoundError', 'FloatingPointError',
    'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError',
    'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError',
    'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError',
    'MemoryError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented',
    'NotImplementedError', 'OSError', 'OverflowError',
    'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError',
    'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning',
    'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError',
    'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError',
    'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError',
    'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning',
    'ValueError', 'Warning', 'ZeroDivisionError', '_', '__build_class__',
    '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs',
    'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable',
    'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits',
    'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit',
    'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr',
    'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass',
    'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview',
    'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property',
    'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice',
    'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars',
    'zip']


6.4. Paketler
=============

Paketler, Python'un modül isim alanını "noktalı modül isimleri"
kullanarak yapılandırmanın bir yoludur.  Örneğin, "A.B" modül adı, "A"
adlı bir paketteki "B" adlı bir alt modülü belirtir.  Modül
kullanımının farklı modüllerin yazarlarını birbirlerinin global
değişken isimleri hakkında endişelenmekten kurtarması gibi, noktalı
modül isimlerinin kullanımı da NumPy veya Pillow gibi çok modüllü
paketlerin yazarlarını birbirlerinin modül isimleri hakkında
endişelenmekten kurtarır.

Ses dosyalarının ve ses verilerinin tek tip işlenmesi için bir modül
koleksiyonu ("paket") tasarlamak istediğinizi varsayalım. Birçok
farklı ses dosyası biçimi vardır (genellikle uzantılarıyla tanınır,
örneğin: ".wav", ".aiff", ".au") bu nedenle, çeşitli dosya biçimleri
arasında dönüşüm için büyüyen bir modül koleksiyonu oluşturmanız ve
sürdürmeniz gerekebilir. Ses verileri üzerinde gerçekleştirmek
isteyebileceğiniz birçok farklı işlem de vardır (karıştırma, eko
ekleme, ekolayzır işlevi uygulama, yapay bir stereo efekti oluşturma
gibi) bu nedenle ek olarak, bu işlemleri gerçekleştirmek için hiç
bitmeyen bir modül akışı yazıyor olacaksınız. İşte paketiniz için
olası bir yapı (hiyerarşik bir dosya sistemi cinsinden ifade edilir):

   sound/                          Top-level package
         __init__.py               Initialize the sound package
         formats/                  Subpackage for file format conversions
                 __init__.py
                 wavread.py
                 wavwrite.py
                 aiffread.py
                 aiffwrite.py
                 auread.py
                 auwrite.py
                 ...
         effects/                  Subpackage for sound effects
                 __init__.py
                 echo.py
                 surround.py
                 reverse.py
                 ...
         filters/                  Subpackage for filters
                 __init__.py
                 equalizer.py
                 vocoder.py
                 karaoke.py
                 ...

Paketi içe aktarırken Python, paket alt dizinini arayan "sys.path"
üzerindeki dizinleri arar.

"__init__.py" dosyaları, Python'un dosyayı içeren dizinleri paket
olarak ele almasını sağlamak için gereklidir (nispeten gelişmiş bir
özellik olan *namespace package* kullanılmadığı sürece). Bu, "string"
gibi ortak bir ada sahip dizinlerin, modül arama yolunda daha sonra
ortaya çıkan geçerli modülleri istemeden gizlemesini önler. En basit
durumda, "__init__.py" sadece boş bir dosya olabilir, ancak aynı
zamanda paket için başlatma kodunu çalıştırabilir veya daha sonra
açıklanacak olan "__all__" değişkenini ayarlayabilir.

Paketin kullanıcıları, paketin içindeki ayrı modülleri içe
aktarabilir, örneğin:

   import sound.effects.echo

Bu, "sound.effects.echo" alt modülünü yükler.  Tam adı ile referans
verilmelidir.

   sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

Alt modülü içe aktarmanın alternatif bir yolu:

   from sound.effects import echo

Bu aynı zamanda "echo" alt modülünü yükler ve paket öneki olmadan
kullanılabilir hale getirir, böylece aşağıdaki gibi kullanılabilir:

   echo.echofilter(input, output, delay=0.7, atten=4)

Yine başka bir varyasyon, istenen işlevi veya değişkeni doğrudan içe
aktarmaktır:

   from sound.effects.echo import echofilter

Yine, bu, "echo" alt modülünü yükler, ancak bu, "echofilter()"
fonksiyonunu doğrudan kullanılabilir hale getirir:

   echofilter(input, output, delay=0.7, atten=4)

"from package import item" kullanırken, öğenin paketin bir alt modülü
(veya alt paketi) veya pakette tanımlanmış bir fonksiyon, sınıf veya
değişken gibi başka bir ad olabileceğini unutmayın. "import" ifadesi
önce öğenin pakette tanımlanıp tanımlanmadığını test eder; değilse
modül olduğunu varsayar ve yüklemeye çalışır. Onu bulamazsa, bir
"ImportError" istisnası ortaya çıkar.

Aksine, "import item.subitem.subsubitem" gibi bir sözdizimi
kullanırken, sonuncusu hariç her öğe bir paket olmalıdır; son öğe bir
modül veya paket olabilir, ancak önceki öğede tanımlanan bir sınıf,
fonksiyon veya değişken olamaz.


6.4.1. Bir Paketten * İçe Aktarma
---------------------------------

Şimdi, kullanıcı "from sound.effects import *" yazdığında ne olur?
İdeal olarak, bunun bir şekilde dosya sistemine gitmesi, pakette hangi
alt modüllerin bulunduğunu bulması ve hepsini içe aktarması umulur. Bu
uzun zaman alabilir ve alt modüllerin içe aktarılması, yalnızca alt
modül açıkça içe aktarıldığında gerçekleşmesi gereken istenmeyen yan
etkilere neden olabilir.

Tek çözüm, paket yazarının paketin açık bir dizinini sağlamasıdır.
"import" ifadesi aşağıdaki kuralı kullanır: eğer bir paketin
"__init__.py" kodu "__all__" adlı bir liste tanımlarsa, "from package
import *" ile karşılaşıldığında alınması gereken modül adlarının
listesi olarak alınır. Paketin yeni bir sürümü yayınlandığında bu
listeyi güncel tutmak paket yazarının sorumluluğundadır. Paket
yazarları, paketlerinden * içe aktarmak için bir kullanım görmezlerse,
onu desteklememeye de karar verebilirler. Örneğin,
"sound/effects/__init__.py" dosyası şu kodu içerebilir:

   __all__ = ["echo", "surround", "reverse"]

Bu, "from sound.effects import *" ifadesinin "sound.effects" paketinin
üç adlandırılmış alt modülünü içe aktaracağı anlamına gelir.

Alt modüllerin yerel olarak tanımlanmış isimler tarafından
gölgelenebileceğini unutmayın. Örneğin, "sound/effects/__init__.py"
dosyasına bir "reverse" fonksiyonu eklediyseniz, "from sound.effects
import *" sadece iki alt modül olan "echo" ve "surround``u içe
aktarır, ancak *reverse" alt modülünü içe aktarmaz, çünkü yerel olarak
tanımlanmış "reverse" fonksiyonu tarafından gölgelenir:

   __all__ = [
       "echo",      # refers to the 'echo.py' file
       "surround",  # refers to the 'surround.py' file
       "reverse",   # !!! refers to the 'reverse' function now !!!
   ]

   def reverse(msg: str):  # <-- this name shadows the 'reverse.py' submodule
       return msg[::-1]    #     in the case of a 'from sound.effects import *'

Eğer "__all__" tanımlanmamışsa, "from sound.effects import *" ifadesi
"sound.effects" paketindeki tüm alt modülleri geçerli isim alanına
import etmez; sadece "sound.effects" paketinin import edildiğinden
emin olur (muhtemelen "__init__.py" içindeki herhangi bir başlatma
kodunu çalıştırır) ve sonra pakette tanımlanan isimleri import eder.
Bu, "__init__.py" tarafından tanımlanan (ve alt modülleri açıkça
yüklenen) tüm isimleri içerir.  Ayrıca, önceki "import" deyimleri
tarafından açıkça yüklenmiş olan paketin tüm alt modüllerini de
içerir.  Bu kodu göz önünde bulundurun:

   import sound.effects.echo
   import sound.effects.surround
   from sound.effects import *

Bu örnekte, "echo" ve "surround" modülleri, "from...import" deyimi
çalıştırıldığında "sound.effects" paketinde tanımlandıkları için
geçerli ad alanında içe aktarılır.  (Bu aynı zamanda "__all__"
tanımlandığında da çalışır).

Bazı modüller, "import *" kullandığınızda yalnızca belirli kalıpları
takip eden adları dışa aktarmak üzere tasarlanmış olsa da, üretim
kodunda yine de kötü uygulama olarak kabul edilir.

Unutmayın, "from package import specific_submodule" kullanmanın yanlış
bir tarafı yok! Aslında, içe aktarma modülünün farklı paketlerden aynı
ada sahip alt modülleri kullanması gerekmedikçe, önerilen gösterim
budur.


6.4.2. Paket İçi Referanslar
----------------------------

Paketler alt paketler halinde yapılandırıldığında (örnekteki "sound"
paketinde olduğu gibi), kardeş paketlerin alt modüllerine başvurmak
için mutlak içe aktarımları kullanabilirsiniz.  Örneğin,
"sound.filters.vocoder" modülünün "sound.effects" paketindeki "echo"
modülünü kullanması gerekiyorsa, "from sound.effects import echo"
kullanabilir.

Ayrıca, içe aktarma ifadesinin "from module import name" formuyla
göreli içe aktarmaları(relative import) da yazabilirsiniz. Bu içe
aktarmalar, göreli içe aktarmada(relative import) yer alan mevcut ve
ana paketleri belirtmek için baştaki noktaları kullanır. Örneğin
"surround" modülünden şunları kullanabilirsiniz:

   from . import echo
   from .. import formats
   from ..filters import equalizer

Göreceli içe aktarmaların geçerli modülün adını temel aldığını
unutmayın.  Ana modülün adı her zaman  ""__main__"" olduğundan, bir
Python uygulamasının ana modülü olarak kullanılması amaçlanan modüller
her zaman mutlak içe aktarma kullanmalıdır.


6.4.3. Birden Çok Dizindeki Paketler
------------------------------------

Paketler bir özel özelliği daha destekler, "__path__". Bu, o dosyadaki
kod yürütülmeden önce paketin "__init__.py" dosyasını tutan dizinin
adını içeren bir liste olacak şekilde başlatılır. Bu değişken
değiştirilebilir; bunu yapmak, pakette bulunan modüller ve alt
paketler için gelecekteki aramaları etkiler.

Bu özelliğe sıklıkla ihtiyaç duyulmasa da, bir pakette bulunan modül
dizisini genişletmek için kullanılabilir.

-[ Dipnotlar ]-

[1] Aslında işlev tanımları aynı zamanda 'çalıştırılan' 'ifadelerdir';
    modül düzeyinde bir işlev tanımının çalıştırılması, işlev adını
    modülün genel ad alanına ekler.
