__main__ — Kodmiljö på högsta nivå


I Python används det speciella namnet __main__ för två viktiga konstruktioner:

  1. namnet på programmets toppnivåmiljö, vilket kan kontrolleras med hjälp av uttrycket __name__ == '__main__'; och

  2. filen __main__.py i Python-paket.

Båda dessa mekanismer är relaterade till Python-moduler; hur användare interagerar med dem och hur de interagerar med varandra. De förklaras i detalj nedan. Om du är nybörjare på Python-moduler, se avsnittet om självstudier Moduler för en introduktion.

__name__ == '__main__'

När en Python-modul eller ett Python-paket importeras sätts __name__ till modulens namn. Vanligtvis är detta namnet på själva Python-filen utan tillägget .py:

>>> import configparser
>>> configparser.__name__
'configparser'

Om filen är en del av ett paket kommer __name__ också att inkludera det överordnade paketets sökväg:

>>> from concurrent.futures import process
>>> process.__name__
'concurrent.futures.process'

Men om modulen körs i kodmiljön på högsta nivån sätts dess __name__ till strängen '__main__'.

Vad är ”kodmiljön på högsta nivå”?

__main__ är namnet på den miljö där toppnivåkoden körs. ”Toppnivåkod” är den första användarspecificerade Python-modulen som börjar köras. Den är ”toppnivå” eftersom den importerar alla andra moduler som programmet behöver. Ibland kallas ”toppnivåkoden” för en ingångspunkt till programmet.

Kodmiljön på högsta nivå kan vara:

  • omfattningen av en interaktiv uppmaning:

    >>> __name__
    '__main__'
    
  • den Python-modul som skickas till Python-tolken som ett filargument:

    $ python helloworld.py
    Hallå där i världen!
    
  • den Python-modul eller det Python-paket som skickas till Python-tolken med -m-argumentet:

    $ python -m tarfile
    användning: tarfile.py [-h] [-v] (...)
    
  • Python-kod som läses av Python-tolken från standardinmatningen:

    $ echo "importera detta" | python
    Pythons zen, av Tim Peters
    
    Vackert är bättre än fult.
    Explicit är bättre än implicit.
    ...
    
  • Python-kod som skickas till Python-tolken med argumentet -c:

    $ python -c "importera detta"
    Zen av Python, av Tim Peters
    
    Vackert är bättre än fult.
    Explicit är bättre än implicit.
    ...
    

I alla dessa situationer sätts toppmodulens __name__ till '__main__'.

En modul kan därför upptäcka om den körs i toppnivåmiljön eller inte genom att kontrollera sitt eget __name__, vilket möjliggör ett vanligt idiom för villkorlig exekvering av kod när modulen inte initieras från en importsats:

if __name__ == '__main__':
    # Exekveras när modulen inte initieras från ett import-sats.
    ...

Se även

För en mer detaljerad titt på hur __name__ ställs in i alla situationer, se handledningsavsnittet Moduler.

Idiomatisk användning

Vissa moduler innehåller kod som endast är avsedd för skriptanvändning, t.ex. parsning av kommandoradsargument eller hämtning av data från standardinmatning. Om en sådan modul importeras från en annan modul, t.ex. för att enhetstesta den, skulle skriptkoden oavsiktligt också exekveras.

Det är här som kodblocket if __name__ == '__main__' kommer väl till pass. Kod inom detta block kommer inte att köras om inte modulen exekveras i miljön på högsta nivå.

Om du lägger in så få satser som möjligt i blocket under if __name__ == '__main__' kan du förbättra kodens tydlighet och korrekthet. Oftast kapslar en funktion med namnet main in programmets primära beteende:

# echo.py

import shlex
import sys

def echo(phrase: str) -> None:
   """A dummy wrapper around print."""
   # for demonstration purposes, you can imagine that there is some
   # valuable and reusable logic inside this function
   print(phrase)

def main() -> int:
    """Echo the input arguments to standard output"""
    phrase = shlex.join(sys.argv)
    echo(phrase)
    return 0

if __name__ == '__main__':
    sys.exit(main())  # next section explains the use of sys.exit

Observera att om modulen inte kapslade in koden i funktionen main utan istället lade den direkt i blocket if __name__ == '__main__', skulle variabeln phrase vara global för hela modulen. Detta är felbenäget eftersom andra funktioner inom modulen oavsiktligt kan använda den globala variabeln istället för ett lokalt namn. En main-funktion löser detta problem.

Att använda en main -funktion har den extra fördelen att echo -funktionen i sig isoleras och kan importeras till andra ställen. När echo.py importeras kommer funktionerna echo och main att definieras, men ingen av dem kommer att anropas, eftersom __name__ != '__main__'.

Överväganden om förpackningar

main -funktioner används ofta för att skapa kommandoradsverktyg genom att ange dem som ingångspunkter för konsolskript. När detta görs infogar pip funktionsanropet i ett mallscript, där returvärdet för main skickas till sys.exit(). Till exempel:

sys.exit(main())

Eftersom anropet till main är inkapslat i sys.exit(), förväntas din funktion returnera något värde som kan accepteras som indata till sys.exit(); vanligtvis ett heltal eller None (som returneras implicit om din funktion inte har ett return-svar).

Genom att vi själva proaktivt följer denna konvention kommer vår modul att ha samma beteende när den körs direkt (dvs. python echo.py) som om vi senare paketerar den som en ingångspunkt för konsolskript i ett paket som kan installeras med pip.

Var särskilt försiktig med att returnera strängar från din main -funktion. sys.exit() tolkar ett strängargument som ett felmeddelande, så ditt program får en avslutningskod på 1, vilket indikerar fel, och strängen skrivs till sys.stderr. Exemplet echo.py från tidigare visar hur man använder konventionen sys.exit(main()).

Se även

Användarhandbok för Python Packaging innehåller en samling handledningar och referenser om hur man distribuerar och installerar Python-paket med moderna verktyg.

__main__.py i Python-paket

Om du inte är bekant med Python-paket, se avsnitt Paket i handledningen. Vanligtvis används filen __main__.py för att tillhandahålla ett kommandoradsgränssnitt för ett paket. Tänk på följande hypotetiska paket, ”bandclass”:

bandklass
  ├── __init__.py
  ├── __main__.py
  └── student.py

__main__.py kommer att exekveras när själva paketet anropas direkt från kommandoraden med hjälp av flaggan -m. Till exempel

$ python -m bandklass

Detta kommando kommer att få __main__.py att köras. Hur du använder den här mekanismen beror på hur paketet du skriver ser ut, men i det här hypotetiska fallet kan det vara vettigt att låta läraren söka efter elever:

# bandclass/__main__.py

import sys
from .student import search_students

student_name = sys.argv[1] if len(sys.argv) >= 2 else ''
print(f'Found student: {search_students(student_name)}')

Observera att from .student import search_students är ett exempel på en relativ import. Denna importstil kan användas när man refererar till moduler inom ett paket. Mer information finns i Referenser inom förpackningen i avsnittet Moduler i självstudien.

Idiomatisk användning

Innehållet i __main__.py är vanligtvis inte avgränsat med ett if __name__ == '__main__'-block. Istället hålls dessa filer korta och importerar funktioner som ska köras från andra moduler. Dessa andra moduler kan sedan enkelt enhetstestas och är ordentligt återanvändbara.

Om det används kommer ett if __name__ == '__main__' -block fortfarande att fungera som förväntat för en __main__.py -fil i ett paket, eftersom dess __name__ -attribut kommer att inkludera paketets sökväg om det importeras:

>>> import asyncio.__main__
>>> asyncio.__main__.__name__
'asyncio.__main__'

Detta fungerar dock inte för filer med namnet __main__.py i rotkatalogen i en .zip -fil. För att upprätthålla konsekvensen är det därför bättre att använda en minimal __main__.py utan en __name__ -kontroll.

Se även

Se venv för ett exempel på ett paket med en minimal __main__.py i standardbiblioteket. Den innehåller inte ett if __name__ == '__main__' -block. Du kan anropa den med python -m venv [directory].

Se runpy för mer information om -m-flaggan till tolkens körbara fil.

Se zipapp för hur man kör program som paketerats som .zip-filer. I det här fallet letar Python efter en fil med namnet __main__.py i arkivets rotkatalog.

import __main__

Oavsett vilken modul ett Python-program startades med, kan andra moduler som körs inom samma program importera toppnivåmiljöns scope (namespace) genom att importera modulen __main__. Detta innebär inte import av filen __main__.py utan snarare av den modul som fått det speciella namnet '__main__'.

Här är ett exempel på en modul som använder namnrymden __main__:

# namely.py

import __main__

def did_user_define_their_name():
    return 'my_name' in dir(__main__)

def print_user_name():
    if not did_user_define_their_name():
        raise ValueError('Define the variable `my_name`!')

    print(__main__.my_name)

Exempel på användning av denna modul kan vara följande:

# start.py

import sys

from namely import print_user_name

# my_name = "Dinsdale"

def main():
    try:
        print_user_name()
    except ValueError as ve:
        return str(ve)

if __name__ == "__main__":
    sys.exit(main())

Om vi nu startade vårt program skulle resultatet se ut så här:

$ python start.py
Definiera variabeln `my_name`!

Programmets utgångskod skulle vara 1, vilket indikerar ett fel. Om du avkommenterar raden med my_name = "Dinsdale" åtgärdas programmet och nu avslutas det med statuskod 0, vilket indikerar framgång:

$ python start.py
Dinsdale

Observera att import av __main__ inte orsakar några problem med att oavsiktligt köra toppnivåkod avsedd för skriptanvändning som finns i blocket if __name__ == "__main__" i modulen start. Varför fungerar detta?

Python infogar en tom modul __main__ i sys.modules när tolken startas och fyller den genom att köra kod på högsta nivå. I vårt exempel är detta modulen start som körs rad för rad och importerar namely. I sin tur importerar namely __main__ (som egentligen är start). Det är en importcykel! Lyckligtvis, eftersom den delvis ifyllda modulen __main__ finns i sys.modules, skickar Python den till namely. Se Särskilda överväganden för __main__ i referensen för importsystemet för mer information om hur detta fungerar.

Python REPL är ett annat exempel på en ”toppnivåmiljö”, så allt som definieras i REPL blir en del av __main__ scope:

>>> import namely
>>> namely.did_user_define_their_name()
False
>>> namely.print_user_name()
Traceback (most recent call last):
...
ValueError: Define the variable `my_name`!
>>> my_name = 'Jabberwocky'
>>> namely.did_user_define_their_name()
True
>>> namely.print_user_name()
Jabberwocky

Scope __main__ används i implementeringen av pdb och rlcompleter.