Lær Python’s if __name__ == «__main__»: En komplett guide

Forståelse av `if __name__ == «__main__’` i Python

I denne veiledningen skal vi utforske funksjonaliteten og betydningen av `if __name__ == «__main__’` i Python-programmering.

Har du noen gang gått gjennom en Python-kodebase som består av flere moduler? Hvis svaret er ja, har du sannsynligvis støtt på `if __name__ == «__main__’`-betingelsen i en eller flere av modulene. I løpet av de neste minuttene skal vi avdekke hva denne betingelsen innebærer og se på et praktisk eksempel der den kan være svært nyttig.

La oss starte!

Hva betyr `__name__` i Python?

I Python refererer en modul til en `.py`-fil som inneholder definisjoner av funksjoner, kode som skal utføres, og mer. For eksempel, hvis vi har en fil som heter `hello_world.py`, vil vi referere til denne som `hello_world.py`-filen eller `hello_world`-modulen.

Når en Python-modul kjøres, setter Python-tolken verdier for en rekke spesialvariabler, og `__name__` er en av dem. For å forstå betydningen av `__name__`, må man forstå hvordan import fungerer i Python.

📁 Last ned koden for denne delen her.

Gå til mappen `eksempel-1`. Der finner du filen `module1.py`. Variabelen `__name__` eksisterer i navnerommet til den aktive modulen.

Denne modulen skriver ut en tekstlinje, etterfulgt av verdien av variabelen `__name__`.

      # example-1/module1.py
      print("Dette er module1.")
      print(f"Variabelen __name__ i module 1 er: {__name__}.")
    

La oss nå kjøre `module1` fra kommandolinjen.

$ python module1.py

I utdataene ser vi at variabelen `__name__` er satt til `__main__`.

      Dette er module1.
      Variabelen __name__ i module 1 er: __main__.
    

Importere moduler i Python

I tillegg til å kjøre en Python-modul direkte, kan det være ønskelig å bruke funksjoner fra en annen modul i den nåværende. Python tillater dette gjennom import.

Importer gjør det mulig å gjenbruke funksjonaliteten i en annen modul, ved å inkludere den i gjeldende moduls omfang, uten å måtte gjenskape koden.

Filen `module2.py` inneholder følgende. Vi har importert `module1` inn i `module2`.

      # example-1/module2.py

      import module1 # module1 er importert

      print(f"Dette er module2")
      print(f"Variabelen __name__ i module2 er: {__name__}.")
    

Vi kjører `module2.py` og observerer utdataene.

$ python module2.py

I utdataene nedenfor ser vi:

  • `module1` kjøres i bakgrunnen når vi importerer den i `module2`, og den tilhørende utskriften blir vist.
  • Men denne gangen er variabelen `__name__` ikke `__main__`, men `module1`.
  • Siden vi kjørte `module2` direkte, er `__name__`-variabelen tilsvarende `module2` nå `__main__`.
      Utdata:

      Dette er module1.
      Variabelen __name__ i module 1 er: module1.
      Dette er module2
      Variabelen __name__ i module2 er: __main__.
    

💡 Viktig å huske:

– Hvis en modul kjøres direkte, blir variabelen `__name__` satt til `__main__`.

– Hvis en modul importeres i en annen modul, settes dens `__name__` til navnet på modulen.

Eksempel på `if __name__ == «__main__’` i Python

I dette avsnittet skal vi undersøke et praktisk bruksområde for `if __name__ == «__main__’`-betingelsen. Vi definerer en enkel funksjon og deretter skriver vi enhetstester for å forsikre oss om at funksjonen fungerer som forventet.

📁 Last ned koden og følg med.

Koden for denne delen finner du i mappen `eksempel-2`.

`add.py` er en Python-fil som inneholder definisjonen av funksjonen `add_ab()`. Funksjonen `add_ab()` aksepterer to vilkårlige tall og returnerer summen av dem.

      # example-2/add.py

      def add_ab(a,b):
        return a + b
    

Vi bruker Pythons `unittest`-modul for å teste funksjonen `add_ab()`.

Skrive testtilfeller for en Python-funksjon

Se på kodeutdraget nedenfor som inneholder innholdet i `test_add`-modulen.

      # example-2/test_add.py

      import unittest
      from add import add_ab

      class TestAdd(unittest.TestCase):
          def test_add_23(self):
              self.assertEqual(add_ab(2,3), 5)
    
          def test_add_19(self):
              self.assertEqual(add_ab(1,9), 10)
    
          def test_add_1_minus7(self):
              self.assertEqual(add_ab(1,-7), -6)
    

Koden ovenfor gjør følgende:

  • Importerer Pythons innebygde `unittest`-modul.
  • Importerer funksjonen `add_ab()` fra `add`-modulen.
  • Definerer testklassen `TestAdd` og et sett med testtilfeller som metoder inne i testklassen.

For å sette opp enhetstester for koden din, bør du først definere en testklasse som arver fra `unittest.TestCase`. Alle testtilfeller skal spesifiseres som metoder i klassen og bør begynne med `test_`.

Merk: Hvis metodene dine ikke er navngitt som `test_`, vil de tilhørende testene ikke bli oppdaget og derfor ikke utføres.

La oss nå prøve å kjøre `test_add`-modulen fra terminalen.

$ python test_add.py

Du vil observere at det ikke er noen utdata, og at ingen av testene har blitt utført.

Hvorfor er det slik? 🤔

Dette skyldes at for å kjøre enhetstestene, må du kjøre `unittest` som hovedmodulen mens du utfører `test_add.py`, ved å bruke kommandoen nedenfor.

$ python -m unittest test_add.py

Når vi kjører kommandoen over, ser vi at alle de tre testene har blitt utført uten feil.

      Utdata:
      ...
      ----------------------------------------------------------------------
      Kjørte 3 tester på 0.000s

      OK
    

Det ville imidlertid vært mer praktisk om vi kunne kjøre testene når `test_add`-modulen kjøres, ikke sant? La oss finne ut hvordan vi kan oppnå dette i neste avsnitt.

Bruke `if __name__ == «__main__’` for å kjøre `unittest` som hovedmodul

Hvis du ønsker å kjøre alle enhetstestene når modulen kjøres direkte, kan du inkludere den betingede.

      # example-2/test_add.py

      import unittest
      from add import add_ab

      class TestAdd(unittest.TestCase):
          def test_add_23(self):
              self.assertEqual(add_ab(2,3), 5)
    
          def test_add_19(self):
              self.assertEqual(add_ab(1,9), 10)
    
          def test_add_1_minus7(self):
              self.assertEqual(add_ab(1,-7), -6)

      # Kjør unittest som hovedmodul
      if __name__ == '__main__':
          unittest.main()
    

Betingelsen i kodebiten ovenfor forteller Python-tolken at dersom denne modulen kjøres direkte, skal koden inne i blokken utføres, dvs. `unittest.main()`.

Du kan nå kjøre `test_add`-modulen etter å ha lagt til de to foregående kodelinjene.

$ python test_add.py

▶️ Når du kjører `test_add`-modulen direkte nå, vil alle de tre testene vi definerte utføres.

      Utdata:
      ...
      ----------------------------------------------------------------------
      Kjørte 3 tester på 0.000s

      OK
    

Utdataet over viser `OK`, som indikerer at alle testene har blitt kjørt uten feil. De tre prikkene `…` indikerer at tre tester har blitt kjørt, og at alle har bestått.

La oss nå endre den forventede returverdien for `test_add_1_minus7` til `8`. Siden funksjonen returnerer `-6` i dette tilfellet, bør dette resultere i en feilet test.

      def test_add_1_minus7(self):
          self.assertEqual(add_ab(1,-7), 8)
    

Som vist i utdataet nedenfor, får vi `.F.`, av de tre testene, mislyktes en av dem (den andre testen), og i tilbakesporingen får vi en `AssertionError` som sier `-6 != 8`.

      Utdata:
      .F.
      ======================================================================
      FEIL: test_add_1_minus7 (__main__.TestAdd)
      ----------------------------------------------------------------------
      Tilbakesporing (mest nylig kalt sist):
      Fil "test_add.py", linje 12, i test_add_1_minus7
        self.assertEqual(add_ab(1,-7), 8)
      AssertionError: -6 != 8

      ----------------------------------------------------------------------
      Kjørte 3 tester på 0.021s

      FEIL (feil=1)
    

Det er viktig å merke seg at testene ikke nødvendigvis kjøres i den rekkefølgen de er definert i testklassen. I eksemplet over er `test_add_1_minus7` definert som den tredje metoden i testklassen, men den tilhørende testen ble kjørt som nummer to.

Oppsummering

Jeg håper denne veiledningen har hjulpet deg med å forstå hvordan `if __name__ == «__main__’`-betingelsen fungerer i Python.

Her er en rask oppsummering av de viktigste punktene:

  • Python-tolken setter variabelen `__name__` før et Python-skript kjøres.
  • Når du kjører en modul direkte, er verdien av `__name__` satt til `__main__`.
  • Når du importerer en modul i et annet Python-skript, er verdien av `__name__` lik modulnavnet.
  • Du kan bruke `if __name__ == «__main__’` for å kontrollere hvilke deler av modulen som kjøres under henholdsvis direkte og importerte utførelser.

Som neste steg kan du sjekke ut denne dybdeveiledningen om Python-sett. Lykke til med læringen! 🎉