Waar is __init__.py voor?

Waar dient __init__.py voor in een Python-bronmap?


Antwoord 1, autoriteit 100%

Het was vroeger een verplicht onderdeel van een pakket (oud, pre -3.3 “regulier pakket”, niet nieuwere 3.3+ “namespace pakket”).

Hier is de documentatie.

Python definieert twee soorten pakketten, reguliere pakketten en naamruimtepakketten. Reguliere pakketten zijn traditionele pakketten zoals ze bestonden in Python 3.2 en eerder. Een regulier pakket wordt meestal geïmplementeerd als een map die een bestand __init__.py bevat. Wanneer een normaal pakket wordt geïmporteerd, wordt dit bestand __init__.py impliciet uitgevoerd, en de objecten die het definieert, zijn gebonden aan namen in de naamruimte van het pakket. Het bestand __init__.py kan dezelfde Python-code bevatten die elke andere module kan bevatten, en Python zal enkele extra attributen aan de module toevoegen wanneer deze wordt geïmporteerd.

Maar klik gewoon op de link, deze bevat een voorbeeld, meer informatie en een uitleg van naamruimtepakketten, het soort pakketten zonder __init__.py.


Antwoord 2, autoriteit 57%

Bestanden met de naam __init__.py worden gebruikt om mappen op schijf te markeren als Python-pakketmappen.
Als je de bestanden hebt

mydir/spam/__init__.py
mydir/spam/module.py

en mydir op uw pad is, kunt u de code in module.py importeren als

import spam.module

of

from spam import module

Als u het bestand __init__.py verwijdert, zoekt Python niet langer naar submodules in die map, dus pogingen om de module te importeren zullen mislukken.

Het bestand __init__.py is meestal leeg, maar kan worden gebruikt om geselecteerde delen van het pakket onder een handiger naam te exporteren, gemaksfuncties vast te houden, enz.
Gezien het bovenstaande voorbeeld, kan de inhoud van de init-module worden geopend als

import spam

gebaseerd op dit


Antwoord 3, autoriteit 32%

Naast het labelen van een directory als een Python-pakket en het definiëren van __all__, kunt u met __init__.py elke variabele op pakketniveau definiëren. Dit is vaak handig als een pakket iets definieert dat vaak zal worden geïmporteerd, op een API-achtige manier. Dit patroon bevordert de naleving van de Pythonic “plat is beter dan genest”-filosofie.

Een voorbeeld

Hier is een voorbeeld van een van mijn projecten, waarin ik regelmatig een sessionmaker genaamd Session importeer om met mijn database te communiceren. Ik heb een “database” pakket geschreven met een paar modules:

database/
    __init__.py
    schema.py
    insertions.py
    queries.py

Mijn __init__.py bevat de volgende code:

import os
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
engine = create_engine(os.environ['DATABASE_URL'])
Session = sessionmaker(bind=engine)

Aangezien ik Session hier definieer, kan ik een nieuwe sessie starten met de onderstaande syntaxis. Deze code zou hetzelfde zijn, uitgevoerd binnen of buiten de “database” pakketdirectory.

from database import Session
session = Session()

Natuurlijk is dit een klein gemak — het alternatief zou zijn om Session te definiëren in een nieuw bestand zoals “create_session.py” in mijn databasepakket, en nieuwe sessies te starten met:

p>

from database.create_session import Session
session = Session()

Verder lezen

Er is een behoorlijk interessante reddit-thread over het juiste gebruik van __init__.py hier:

http://www.reddit.com/r/Python/comments/1bbbwk/whats_your_opinion_on_what_to_initinclude

De mening van de meerderheid lijkt te zijn dat __init__.py bestanden erg dun moeten zijn om te voorkomen dat de filosofie “expliciet is beter dan impliciet” wordt geschonden.


Antwoord 4, autoriteit 22%

Er zijn 2 hoofdredenen voor __init__.py

  1. Voor het gemak: de andere gebruikers hoeven de exacte locatie van uw functies in uw pakkethiërarchie niet te weten.

    your_package/
      __init__.py
      file1.py
      file2.py
        ...
      fileN.py
    
    # in __init__.py
    from file1 import *
    from file2 import *
    ...
    from fileN import *
    
    # in file1.py
    def add():
        pass
    

    dan kunnen anderen add() aanroepen met

    from your_package import add
    

    zonder bestand1 te kennen, zoals

    from your_package.file1 import add
    
  2. Als je wilt dat iets wordt geïnitialiseerd; bijvoorbeeld loggen (die op het hoogste niveau moet worden geplaatst):

    import logging.config
    logging.config.dictConfig(Your_logging_config)
    

Antwoord 5, autoriteit 8%

Het bestand __init__.py zorgt ervoor dat Python mappen die het bevatten als modules behandelt.

Bovendien is dit het eerste bestand dat in een module wordt geladen, dus je kunt het gebruiken om code uit te voeren die je wilt uitvoeren telkens wanneer een module wordt geladen, of om de submodules te specificeren die moeten worden geëxporteerd.


Antwoord 6, autoriteit 7%

Sinds Python 3.3 is __init__.py niet langer nodig om mappen te definiëren als importeerbare Python-pakketten.

Controleer PEP 420: Impliciete naamruimtepakketten:

Native ondersteuning voor pakketdirectory’s die geen __init__.py markeringsbestanden nodig hebben en die automatisch meerdere padsegmenten kunnen omspannen (geïnspireerd door verschillende benaderingen van derden voor naamruimtepakketten, zoals beschreven in PEP 420)

Dit is de test:

$ mkdir -p /tmp/test_init
$ touch /tmp/test_init/module.py /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
+-- module.py
L-- __init__.py
$ python3
>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module
$ rm -f /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
L-- module.py
$ python3
>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module

referenties:
https://docs.python.org/3 /whatsnew/3.3.html#pep-420-implicit-namespace-packages
https://www.python.org/dev/peps/pep-0420/
Is __init__.py niet vereist voor pakketten in Python 3?


Antwoord 7, autoriteit 5%

Hoewel Python werkt zonder een __init__.py-bestand, moet je er toch een toevoegen.

Het specificeert dat de map moet worden behandeld als een pakket, dus voeg het daarom toe (zelfs als het leeg is).

Er is ook een geval waarin u een __init__.py-bestand daadwerkelijk kunt gebruiken:

Stel je voor dat je de volgende bestandsstructuur had:

main_methods 
    |- methods.py

En methods.py bevatte dit:

def foo():
    return 'foo'

Om foo() te gebruiken heb je een van de volgende dingen nodig:

from main_methods.methods import foo # Call with foo()
from main_methods import methods # Call with methods.foo()
import main_methods.methods # Call with main_methods.methods.foo()

Misschien moet (of wilt) u methods.py binnen main_methods houden (bijvoorbeeld runtimes/dependencies), maar u wilt alleen main_methods.


Als je de naam van methods.py hebt gewijzigd in __init__.py, dan zou je foo() kunnen gebruiken door gewoon main_methods:

import main_methods
print(main_methods.foo()) # Prints 'foo'

Dit werkt omdat __init__.py wordt behandeld als onderdeel van het pakket.


Sommige Python-pakketten doen dit zelfs. Een voorbeeld is met JSON, waarbij import json wordt uitgevoerd importeert feitelijk __init__.py uit het json-pakket (bekijk hier de bestandsstructuur van het pakket):

Broncode: Lib/json/__init__.py


Antwoord 8, autoriteit 3%

In Python is de definitie van pakket heel eenvoudig. Net als Java zijn de hiërarchische structuur en de directorystructuur hetzelfde. Maar je moet __init__.py in een pakket hebben. Ik zal het bestand __init__.py uitleggen met het onderstaande voorbeeld:

package_x/
|--  __init__.py
|--    subPackage_a/
|------  __init__.py
|------  module_m1.py
|--    subPackage_b/
|------  __init__.py
|------  module_n1.py
|------  module_n2.py
|------  module_n3.py

__init__.py mag leeg zijn, zolang het bestaat. Het geeft aan dat de directory moet worden beschouwd als een pakket. Natuurlijk kan __init__.py ook de juiste inhoud instellen.

Als we een functie toevoegen in module_n1:

def function_X():
    print "function_X in module_n1"
    return

Na het hardlopen:

>>>from package_x.subPackage_b.module_n1 import function_X
>>>function_X()
function_X in module_n1 

Vervolgens volgden we het hiërarchiepakket en noemden module_n1 de functie. We kunnen __init__.py in subPackage_b als volgt gebruiken:

__all__ = ['module_n2', 'module_n3']

Na het hardlopen:

>>>from package_x.subPackage_b import * 
>>>module_n1.function_X()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named module_n1

Daarom is het gebruik van * importeren, modulepakket onderhevig aan __init__.py inhoud.


Antwoord 9, autoriteit 3%

__init__.py behandelt de map waarin deze zich bevindt als een laadbare module.

Voor mensen die liever code lezen, plaats ik hier de opmerking van Two-Bit Alchemist.

$ find /tmp/mydir/
/tmp/mydir/
/tmp/mydir//spam
/tmp/mydir//spam/__init__.py
/tmp/mydir//spam/module.py
$ cd ~
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
>>> module.myfun(3)
9
>>> exit()
$ 
$ rm /tmp/mydir/spam/__init__.py*
$ 
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named spam
>>> 

Antwoord 10, autoriteit 2%

Het vergemakkelijkt het importeren van andere python-bestanden. Als je dit bestand in een map (zeg dingen) plaatst die andere py-bestanden bevat, dan kun je zoiets doen als spullen.ander importeren.

root\
    stuff\
         other.py
    morestuff\
         another.py

Zonder deze __init__.py in de directory-dingen, zou je other.py niet kunnen importeren, omdat Python niet weet waar de broncode voor dingen is en het niet kan herkennen als een pakket .


Antwoord 11

Een __init__.py-bestand maakt importeren eenvoudig. Wanneer een __init__.py aanwezig is in een pakket, kan functie a() als volgt worden geïmporteerd uit bestand b.py:

from b import a

Zonder dit kunt u echter niet rechtstreeks importeren. U moet het systeempad wijzigen:

import sys
sys.path.insert(0, 'path/to/b.py')
from b import a

Antwoord 12

Eén ding dat __init__.py toestaat, is het converteren van een module naar een pakket zonder de API te verbreken of het creëren van externe geneste naamruimten of privémodules*. Dit helpt als ik een naamruimte wil uitbreiden.

Als ik een bestand heb dat util.py bevat

def foo():
    ...

dan krijgen gebruikers toegang tot foo met

from util import foo

Als ik dan hulpprogramma-functies voor database-interactie wil toevoegen en ik wil dat ze hun eigen naamruimte hebben onder util, heb ik een nieuwe directory** nodig en om de API-compatibiliteit te behouden ( zodat from util import foo nog steeds werkt), noem ik het util/. Ik zou util.py naar util/ willen verplaatsen,

util/
  __init__.py
  util.py
  db.py

en in util/__init__.py doen

from util import *

maar dit is overbodig. In plaats van een util/util.py-bestand te hebben, kunnen we de util.py-inhoud gewoon in __init__.py plaatsen en de gebruiker kan nu

from util import foo
from util.db import check_schema

Ik denk dat dit mooi laat zien hoe de __init__.py van een util-pakket op een vergelijkbare manier werkt als een util-module

* hier wordt op gezinspeeld in de andere antwoorden, maar ik wil het hier benadrukken
** afgezien van het gebruik van importgymnastiek. Merk op dat het niet werkt om een ​​nieuw pakket te maken met dezelfde naam als het bestand, zie dit

LEAVE A REPLY

Please enter your comment!
Please enter your name here

four × three =

Other episodes