6. Module
*********

Dacă, atunci când lucrați în terminal, părăsiți interpretorul Python-
ului, veți constata, la revenirea la promptul interpretorului, că
toate definițiile scrise în linia de comandă (fie ele definiții de
funcții ori de variabile) s-au pierdut. Din acest motiv, atunci când
vă pregătiți să scrieți un program mai lung de câteva linii de cod, ar
fi mai bine să folosiți un editor de text pentru prepararea acestui
program și apoi să rulați programul folosind fișierul în cauză pe post
de date de intrare în interpretor. O asemenea întreprindere este
numită creare de *script*. Pe măsură ce programul dumneavoastră se
lungește, veți dori să-l împărțiți în mai multe fișiere pentru a-l
întreține mai ușor. De asemeni, veți ajunge în situația de a dori să
întrebuințați o funcție bine scrisă chiar de dumneavoastră în cadrul
unor programe diverse fără să-i copiați, de fiecare dată, codul în
vreunul din programele respective.

Pentru a vă ajuta în această privință, Python-ul dispune de o
modalitate de a introduce definiții într-un fișier și apoi de a le
utiliza fie într-un script fie într-o instanță interactivă a
interpretorului. Un astfel de fișier este numit *modul*; definițiile
dintr-un modul pot fi *importate* atât în alte module cât și în
modulul *main* (modulul principal, adică acea colecție de variabile la
care aveți acces dintr-un script executat la nivelul cel mai înalt
precum și atunci când lucrați în modul calculator -- bucla REPL).

Modulul constituie, așadar, un fișier conținând definiții și
instrucțiuni scrise în Python. Numele fișierului este numele modulului
la care adăugăm sufixul ".py". În interiorul (codului Python al) unui
modul, numele modulului (sub forma unui șir de caractere) ne va fi
accesibil ca valoare a variabilei globale "__name__". Ca să vedem
aceasta, vă rugăm să întrebuințați editorul dumneavoastră favorit de
text pentru a crea fișierul cu numele "fibo.py", situat în directorul
curent și având următorul conținut:

   # 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

Apoi, porniți interpretorul de Python și importați modulul tocmai
scris cu comanda care urmează:

   >>> import fibo

Execuția comenzii nu va adăuga numele funcțiilor definite în "fibo"
direct la *spațiul de nume* curent (vezi Domenii de valabilitate și
spații de nume în Python pentru mai multe detalii); tot ce va face va
fi să adauge numele "fibo" spațiului de nume respectiv. Apelând la
numele modulului, veți putea accesa funcțiile acestuia:

   >>> 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'

Dacă intenționați să folosiți o anumită funcție în mod frecvent,
atunci îi puteți atribui unei variabile locale numele acesteia:

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


6.1. Mai multe despre module
============================

Orice modul poate conține atât instrucțiuni executabile cât și
definiții de funcții. Aceste instrucțiuni sunt folosite la
inițializarea modulului. Adică, ele vor fi executate doar *prima* dată
când numele modulului în cauză va fi întâlnit de către interpretor
într-o instrucțiune de import. [1] (Instrucțiunile vor fi rulate și
atunci când fișierul -- modulul -- va fi executat ca script.)

Fiecare modul are propriul său spațiu de nume privat, care va fi
utilizat ca spațiu de nume global de către toate funcțiile definite în
modulul respectiv. Astfel, autorul unui modul poate întrebuința
variabile globale în codul Python al modulului fără să se teamă de
eventualele conflicte de nume dintre aceste variabile și variabilele
globale ale utilizatorului (modulului). Pe de altă parte, dacă sunteți
siguri pe ceea ce faceți, atunci veți putea întrebuința variabilele
globale ale unui modul cu aceeași notație pe care o utilizați pentru a
vă referi la funcțiile modulului, și anume
"nume_de_modul.nume_de_item".

Modulele pot importa alte module. Se obișnuiește, fără a fi
obligatoriu, să plasăm toate instrucțiunile "import" la începutul
oricărui modul (respectiv, al oricărui script). Numele de module
importate, dacă sunt poziționate la nivelul cel mai de sus al
modulului (adică, în exteriorul oricărui cod de funcție sau de clasă
din modul), vor fi adăugate spațiului de nume global al modulului.

Există o variantă a instrucțiunii "import" care realizează importurile
de nume dintr-un modul direct în spațiul de nume al modulului
importator. Iată un exemplu de folosire a ei:

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

Varianta nu va introduce numele modulului din care facem importurile
în spațiul de nume local (așa că, în exemplul anterior, "fibo" nu este
definit).

Dispunem chiar și de o modalitate de a importa toate numele pe care le
definește un modul:

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

Această variantă a instrucțiunii despre care discutăm va importa toate
numele cu excepția celor care încep cu o bară jos ("_"). De cele mai
multe ori, programatorii de Python nu vor apela la această facilitate
a limbajului deoarece ea va introduce un set necunoscut de nume în
spațiul de nume folosit de interpretor, putând astfel masca o serie de
chestiuni deja definite de dumneavoastră.

Să remarcăm, așadar, că obiceiul de a importa "*" fie dintr-un modul
fie dintr-un pachet este descurajat de profesioniști, dat fiind că el
cauzează, în majoritatea situațiilor, apariția unui cod greu de citit.
Cu toate acestea, este permis să îl practicați în sesiunile
interactive de lucru cu interpretorul de Python, ca să aveți mai puțin
de tastat.

Dacă numele unui modul este urmat de "as", atunci numele situat la
dreapta lui "as" va fi legat direct de modulul importat.

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

Procedând astfel, importul modulului se va realiza la fel ca în urma
execuției instrucțiunii "import fibo", singura deosebire fiind aceea
că modulul va fi disponibil sub numele (modificat convenabil) de
"fib".

Efecte similare vor fi obținute dacă procedăm în acest mod și atunci
când folosim versiunea cu "from" a instrucțiunii de import:

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

Notă:

  Din rațiuni de eficiență, orice modul va fi importat o singură dată
  într-o sesiune de lucru cu interpretorul. Așa că, dacă îi aduceți
  modificări modulului, va trebui să reporniți interpretorul -- ori,
  dacă este vorba doar despre un singur modul ce trebuie testat
  interactiv, folosiți "importlib.reload()", precum, de exemplu, în
  "import importlib; importlib.reload(numele_modulului)".


6.1.1. Executând module ca scripturi
------------------------------------

Atunci când rulați un modul Python cu

   python fibo.py <arguments>

codul modulului va fi executat ca și cum modulul ar fi fost importat,
cu excepția faptului că variabila "__name__" va fi setată ca
""__main__"". Ceea ce înseamnă că, dacă ați adăuga următoarele linii
de cod la sfârșitul modulului dumneavoastră:

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

atunci ați face fișierul (modulului) utilizabil atât ca script cât și
ca modul importabil doarece codul în care se parsează conținutul
liniei de comandă va rula numai atunci când modulul se execută ca
fișier "main":

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

În schimb, atunci când modulul este importat, codul nu va fi rulat:

   >>> import fibo
   >>>

Acest procedeu este frecvent întrebuințat fie pentru a-i adăuga
modulului o interfață cu utilizatorul convenabilă fie în scop de
testare (atunci când, la rularea modulului ca script, va fi executată
o suită de teste).


6.1.2. Calea de căutare a modulelor
-----------------------------------

When a module named "spam" is imported, the interpreter first searches
for a built-in module with that name. These module names are listed in
"sys.builtin_module_names". If not found, it then searches for a file
named "spam.py" in a list of directories given by the variable
"sys.path".  "sys.path" is initialized from these locations:

* Directorul care conține scriptul folosit ca dată de intrare la
  interpretor (sau directorul curent dacă nu a fost precizat niciun
  fișier).

* "PYTHONPATH" (o listă cu nume de directoare, având aceeași sintaxă
  ca variabila interpretorului de comenzi -- de la englezescul *shell*
  -- "PATH").

* Locația implicită, depinzând de modalitatea de instalare (incluzând,
  în mod convențional, un director "site-packages", manipulată de
  modulul "site").

Notă:

  În sistemele de fișiere care suportă legături slabe (în englezește,
  ca jargon, *symlink*), directorul care conține scriptul de intrare
  va fi calculat numai după ce este urmată legătura. Cu alte cuvinte,
  directorul care conține legătura slabă **nu** îi va fi adăugat căii
  de căutare a modulelor.

Odată inițializate, programele Python pot modifica "sys.path"-ul.
Directorul care conține scriptul ce este rulat va fi plasat la
începutul căii de căutare, înaintea căii bibliotecii standard. Ceea ce
înseamnă că scripturile din directorul în cauză vor fi încărcate în
locul modulelor cu același nume din directorul bibliotecii standard.
Dacă aceasta nu este intenția dumneavoastră, atunci situația
constituie o eroare serioasă. A se vedea Module standard pentru mai
multe informații.


6.1.3. Fișiere Python "compilate"
---------------------------------

Pentru a accelera încărcarea modulelor, Python-ul salvează în
directorul de *cache* "__pycache__" versiuni compilate ale tuturor
modulelor, cu numele "modulul.*versiunea*.pyc", în care versiunea
conține codificarea formatului pentru fișierul compilat; în general,
ea include numărul de versiune al Python-ului. De exemplu, în ediția
(de la englezescul *release*) 3.3 a CPython-ului, varianta compilată a
lui cutare.py ar fi salvată drept "__pycache__/cutare.cpython-33.pyc".
O atare convenție de nume le permite modulelor compilate ale
diverselor ediții și diferitelor versiuni ale Python-ului să coexiste.

Python-ul compară data modificării fișierelor-sursă cu cea a
versiunilor compilate pentru a stabili dacă acestea din urmă sunt
depășite cronologic și este nevoie să fie recompilate. Procesul de
comparare și recompilare este complet automatizat. În plus, modulele
compilate sunt independente de platforma de calcul, astfel că aceeași
bibliotecă poate fi partajată (de la englezescul *shared*) cu sisteme
de arhitecturi diferite.

Python-ul nu verifică zona de cache în două circumstanțe. În prima,
pentru că el recompilează de fiecare dată, fără a stoca rezultatul
recompilării în directorul de cache, modulul care se încarcă din linia
de comandă. În cea de-a doua situație, el nu verifică zona de cache
atunci când modulul nu dispune de fișier-sursă. Pentru ca Python-ul să
suporte o distribuție fără cod-sursă (adică una doar compilată),
modulul compilat trebuie să fie localizat în directorul-sursă și nu
trebuie să existe în distribuție niciun fișier-sursă al modulului în
cauză.

Ponturi pentru experți:

* Puteți întrebuința opțiunile "-O" sau "-OO" ale unei comenzi Python
  pentru a reduce mărimea unui modul compilat. Opțiunea "-O" elimină
  instrucțiunile de aserțiune (de la englezescul *assert*), iar
  opțiunea "-OO" elimină atât instrucțiunile de aserțiune cât și
  șirurile __doc__. Dat fiind că anumite programe se bazează pe
  existența acestora, ar trebui să utilizați această opțiune numai
  atunci când sunteți sigur pe ceea ce faceți. Modulele "optimizate"
  au eticheta "opt-" și sunt, de obicei, mai mici (decât originalele).
  Edițiile viitoare ale Python-ului pot modifica efectele acestor
  optimizări.

* Niciun program nu va rula mai repede atunci când este citit dintr-un
  fișier ".pyc" decât atunci când este citit dintr-un fișier ".py";
  tot ceea ce este mai rapid în privința fișierelor ".pyc" este viteza
  cu care sunt încărcate.

* Modulul "compileall" le poate crea fișiere .pyc tuturor modulelor
  dintr-un director.

* Mult mai multe detalii despre acest proces al compilării modulelor,
  inclusiv un arbore de decizie util, se găsesc în **PEP 3147**.


6.2. Module standard
====================

Python-ul vine însoțit de o bibliotecă de module standard, descrisă
într-un document separat, Referința bibliotecii Python (denumit
"Referința bibliotecii" de aici înainte). Anumite module sunt
construite ca parte a interpretorului; ele oferă acces la operații
care nu fac parte din corpul (de la englezescul *core*) limbajului dar
sunt, cu toate acestea, incluse în el, fie din rațiuni de eficiență
fie pentru a-i da acces utilizatorului la primitive ale sistemului de
operare precum apelurile (de) sistem. Setul acestor module este
accesibil printr-o opțiune de configurare care depinde, la rândul ei,
de platforma de calcul folosită. De exemplu, modulul "winreg" va fi
disponibil numai pe sistemele de calcul cu Windows. Un modul
particular merită atenția dumneavoastră: "sys", el fiind construit ca
parte a oricărui interpretor de Python. Variabilele "sys.ps1" și
"sys.ps2" au drept valori șirurile de caractere folosite pe post de
promptul primar, respectiv de promptul secundar:

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

Aceste două variabile sunt definite doar dacă interpretorul lucrează
în modul interactiv.

Variabila "sys.path" este o listă formată din șiruri de caractere care
determină calea de căutare a modulelor. Este inițializată cu o cale de
acces implicită preluată din variabila de mediu "PYTHONPATH", ori
dintr-o altă cale de acces prestabilită atunci când "PYTHONPATH" nu a
fost setată. O puteți modifica folosind operațiile tipice cu liste:

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


6.3. Funcția "dir()"
====================

Funcția predefinită "dir()" este întrebuințată la aflarea numelor pe
care le definește un anumit modul. Ea returnează o listă sortată de
șiruri de caractere:

   >>> 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']

Utilizată fără argumente, "dir()" va lista numele definite în sesiunea
curentă:

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

Remarcați faptul că ea listează toate tipurile de nume: pe cele de
variabile, pe cele de module, de funcții șamd.

"dir()" nu listează nici numele funcțiilor predefinite (în englezește,
ca jargon, *built-in*) și nici pe cele ale variabilelor predefinite.
Dacă vă interesează lista acestora, atunci aflați că ele sunt definite
în modulul standard "builtins":

   >>> 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. Pachete
============

Packages are a way of structuring Python's module namespace by using
"dotted module names".  For example, the module name "A.B" designates
a submodule named "B" in a package named "A".  Just like the use of
modules saves the authors of different modules from having to worry
about each other's global variable names, the use of dotted module
names saves the authors of multi-module packages like NumPy or Pillow
from having to worry about each other's module names.

Să presupunem că doriți să proiectați o colecție de module (adică, un
"pachet") dedicate manipulării sistematice a fișierelor de sunet și a
datelor audio. Deoarece există numeroase formate de fișier de sunet
(recunoscute, de obicei, după extensiile lor, cum ar fi: ".wav",
".aiff", ".au"), veți avea de construit și de întreținut o colecție
crescândă de module care să se ocupe cu conversia între diversele
formate de fișier. De asemeni, există felurite operații pe care veți
dori să le aplicați unor date audio (precum mixaje, adăugarea de
ecouri, aplicarea unor funcții de egalizare, crearea unor efecte
stereo artificiale), astfel că, pe lângă cele de dinainte, veți scrie
în permanență noi module pentru aceste operații. Iată o structură
posibilă a pachetului dumneavoastră (exprimată în stilul unui sistem
ierarhic de fișiere -- în englezește, ca jargon, *filesystem*):

   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
                 ...

Atunci când importăm un pachet, Python-ul va căuta subdirectorul
pachetului în lista de directoare din "sys.path".

The "__init__.py" files are required to make Python treat directories
containing the file as packages.  This prevents directories with a
common name, such as "string", from unintentionally hiding valid
modules that occur later on the module search path. In the simplest
case, "__init__.py" can just be an empty file, but it can also execute
initialization code for the package or set the "__all__" variable,
described later.

Utilizatorii unui pachet pot importa module individuale din acesta, ca
de exemplu:

   import sound.effects.echo

This loads the submodule "sound.effects.echo".  It must be referenced
with its full name.

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

Alt fel de a importa submodulul anterior este dat de:

   from sound.effects import echo

This also loads the submodule "echo", and makes it available without
its package prefix, so it can be used as follows:

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

Încă o variație a modului de a importa este să importăm direct fie
funcția fie variabila dorită:

   from sound.effects.echo import echofilter

Again, this loads the submodule "echo", but this makes its function
"echofilter()" directly available:

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

Să remarcăm că, atunci când executăm instrucțiunea "from pachet import
element", elementul poate fi sau un submodul (ori un subpachet) al
pachetului sau orice alt nume definit în pachet, adică o funcție, o
clasă ori o variabilă. Instrucțiunea "import" testează mai întâi dacă
elementul este definit în pachet; dacă nu, atunci va presupune că
elementul este numele unui modul și va încerca să-l încarce. În cazul
în care presupusul modul nu va fi găsit, va fi ridicată o excepție
"ImportError".

În schimb, atunci când facem uz de o sintaxă de felul "import
element.sub_element.sub_sub_element", fiecare (sub)element, cu
excepția ultimului, trebuie să fie nume de pachet; ultimul element
poate fi sau nume de modul sau nume de pachet însă nu și numele
vreunei clase, funcții ori variabile definite în elementul precedent.


6.4.1. Importând * dintr-un pachet
----------------------------------

Ce se întâmplă însă atunci când utilizatorul folosește instrucțiunea
"from sunet.efecte import *"? În mod ideal, putem spera că
interpretorul se duce la sistemul de fișiere, găsește toate
(sub)modulele prezente în pachet și le importă. O atare activitate
este de așteptat să dureze mult iar importul de sub-module poate avea
și efecte secundare nedorite pe care nu le-am produce dacă importul
unui sub-modul oarecare ar fi realizat în mod explicit.

Singurul mod în care putem evita situațiile neplăcute este ca autorul
pachetului să ofere un index explicit al acestuia. Instrucțiunea
"import" folosește următoarea convenție: atunci când codul-sursă al
fișierului "__init__.py" dintr-un pachet definește o variabilă de tip
listă numită "__all__", valoarea acestei variabile va fi folosită
drept lista numelor de module ce vor trebui importate atunci când
interpretorul va avea de executat instrucțiunea "from pachet import
*". Actualizarea listei de nume, cu ocazia lansării unei noi versiuni
a pachetului, rămâne numai la latitudinea autorului acestuia. Autorii
de pachete pot decide chiar și să nu întrebuințeze această facilitate
atunci când nu consideră că ar fi de vreun folos să se importe * din
pachetele lor. Ca exemplu, să presupunem că fișierul
"sunet/efecte/__init__.py" ar conține următoarea linie de cod:

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

This would mean that "from sound.effects import *" would import the
three named submodules of the "sound.effects" package.

If "__all__" is not defined, the statement "from sound.effects import
*" does *not* import all submodules from the package "sound.effects"
into the current namespace; it only ensures that the package
"sound.effects" has been imported (possibly running any initialization
code in "__init__.py") and then imports whatever names are defined in
the package.  This includes any names defined (and submodules
explicitly loaded) by "__init__.py".  It also includes any submodules
of the package that were explicitly loaded by previous "import"
statements.  Consider this code:

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

In this example, the "echo" and "surround" modules are imported in the
current namespace because they are defined in the "sound.effects"
package when the "from...import" statement is executed.  (This also
works when "__all__" is defined.)

Cu toate că anumite module au fost proiectate să nu exporte decât
acele nume care respectă șabloane precise atunci când dumneavoastră
veți folosi instrucțiunea "import *" în raport de ele, întrebuințarea
acestei instrucțiuni în codul destinat producției se socotește a fi o
practică greșită.

Țineți minte, nu este nimic în neregulă dacă utilizați instrucțiunea
"from pachet import submodulul_cutare"! De fapt, aceasta constituie
chiar formularea recomandată a oricărei instrucțiuni de import, cu
excepția situației în care modulul importator are de folosit submodule
omonime din pachete diferite.


6.4.2. Referințe intra-pachet
-----------------------------

When packages are structured into subpackages (as with the "sound"
package in the example), you can use absolute imports to refer to
submodules of siblings packages.  For example, if the module
"sound.filters.vocoder" needs to use the "echo" module in the
"sound.effects" package, it can use "from sound.effects import echo".

You can also write relative imports, with the "from module import
name" form of import statement.  These imports use leading dots to
indicate the current and parent packages involved in the relative
import.  From the "surround" module for example, you might use:

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

Note that relative imports are based on the name of the current
module.  Since the name of the main module is always ""__main__"",
modules intended for use as the main module of a Python application
must always use absolute imports.


6.4.3. Pachete situate în mai multe directoare
----------------------------------------------

Packages support one more special attribute, "__path__".  This is
initialized to be a list containing the name of the directory holding
the package's "__init__.py" before the code in that file is executed.
This variable can be modified; doing so affects future searches for
modules and subpackages contained in the package.

Deși este o caracteristică de care avem nevoie rar, o putem folosi cu
succes la lărgirea setului de module conținute într-un pachet.

-[ Note de subsol ]-

[1] De fapt, și definițiile de funcții sunt 'instrucțiuni' care se
    'execută'; execuția unei definiții de funcție de la nivel de modul
    va adăuga numele acestei funcții la spațiul de nume global al
    modulului respectiv.
