Förstå om __name__ == ’__main__’ i Python

By rik

Förståelse av `if __name__ == ’__main__’` i Python

I den här guiden kommer vi att utforska funktionen och vikten av `if __name__ == ’__main__’` i Python.

Har du någonsin granskat en Python-kodbas som består av olika moduler? Om så är fallet, har du troligen stött på villkoret `if __name__ == ’__main__’` i en eller flera moduler. Under de kommande minuterna kommer vi att avmystifiera innebörden av detta villkor och undersöka ett exempel där det kan vara användbart.

Låt oss sätta igång!

Vad är betydelsen av `__name__` i Python?

I Python representerar en modul en `.py`-fil som innehåller funktionsdefinitioner, en serie satser som ska beräknas, och mer. Till exempel, om vi har en fil som heter `hello_world.py`, kallar vi den för antingen `hello_world.py`-filen eller `hello_world`-modulen.

När du exekverar en Python-modul sätter Python-tolken värden för vissa specifika variabler före körningen: `__name__` är en av dessa. Nyckeln till att förstå betydelsen av `__name__` ligger i hur importfunktionen fungerar i Python.

📁 Ladda ner koden för detta avsnitt här.

Navigera till mappen `exempel-1`. Där finns filen `module1.py`. Variabeln `__name__` existerar i den aktuella modulens namnrymd.

Denna modul skriver ut en rad följt av variabeln `__name__`s värde.

    # example-1/module1.py
    print("Detta är module1.")
    print(f"Variabeln __name__ i module1 är: {__name__}.")
  

Låt oss nu köra `module1` från kommandoraden.

    $ python module1.py
  

I utskriften ser vi att variabeln `__name__` har värdet `__main__`.

    Detta är module1.
    Variabeln __name__ i module1 är: __main__.
  

Importera moduler i Python

Utöver att exekvera en Python-modul kan du ibland vilja använda funktionalitet från en annan Python-modul i den nuvarande modulen. Python underlättar detta genom import.

Import möjliggör återanvändning av funktionaliteten från en annan modul – genom att importera den i den aktuella modulens kontext – utan att behöva skriva om koden.

Filen `module2.py` innehåller följande. Vi har importerat `module1` inuti `module2`.

    # example-1/module2.py

    import module1 # module1 importeras

    print(f"Detta är module2")
    print(f"Variabeln __name__ i module2 är: {__name__}.")
  

Vi kör `module2.py` och analyserar resultatet.

    $ python module2.py
  

I utskriften nedan:

  • Ser vi att `module1` körs när vi importerar den i `module2`, och motsvarande utdata skrivs ut.
  • Den här gången är variabeln `__name__` inte `__main__` utan `module1`.
  • Eftersom vi körde `module2` direkt är variabeln `__name__` relaterad till den modulen, nu `__main__`.
    Utskrift

    Detta är module1.
    Variabeln __name__ i module1 är: module1.
    Detta är module2
    Variabeln __name__ i module2 är: __main__.
    

💡 Nyckelidé:

– Om en modul körs direkt, är dess variabel `__name__` satt till `__main__`.

– Om en modul importeras i en annan modul, sätts dess `__name__` till modulens namn.

Exempel på `if __name__ == ’__main__’` i Python

I det här avsnittet kommer vi att se ett konkret användningsfall för villkoret `if __name__ == ’__main__’`. Vi kommer att definiera en enkel funktion och sedan skriva enhetstester för att säkerställa att funktionen fungerar korrekt.

📁 Ladda ner koden och följ med.

Koden för det här avsnittet finns i mappen `exempel-2`.

Här är `add.py` en Python-fil som innehåller definitionen av funktionen `add_ab()`. Funktionen `add_ab()` tar in två valfria tal och returnerar deras summa.

    # example-2/add.py

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

Vi kommer att använda Pythons `unittest`-modul för att testa funktionen `add_ab()`.

Att skriva testfall för en Python-funktion

Se kodsnutten nedan, som innehåller innehållet i modulen `test_add`.

    # 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)
    

Ovanstående kod gör följande:

  • Importerar Pythons inbyggda `unittest`-modul.
  • Importerar funktionen `add_ab()` från `add`-modulen.
  • Definierar testklassen `TestAdd` och en uppsättning testfall som metoder i testklassen.

För att konfigurera enhetstester för din kod, bör du först definiera en testklass som ärver från `unittest.TestCase`. Alla testfall ska definieras som metoder inom klassen och bör börja med `test_`.

Obs: Om du inte namnger metoderna som `test_`, kommer du att upptäcka att motsvarande tester inte identifieras och därför inte körs.

Låt oss nu prova att köra `test_add`-modulen från terminalen.

        $ python test_add.py
    

Du kommer att se att det inte finns någon utdata och att inget av testerna har körts.

Varför det? 🤔

Detta beror på att för att köra enhetstesterna bör du köra `unittest` som huvudmodul när du kör `test_add.py`, med kommandot nedan.

        $ python -m unittest test_add.py
    

När vi kör ovanstående utökade kommando ser vi att alla tre testerna har körts framgångsrikt.

        Utskrift
        ...
        ----------------------------------------------------------------------
        Ran 3 tests in 0.000s

        OK
    

Det vore dock mer praktiskt att köra testerna när modulen `test_add` körs, eller hur? Låt oss lära oss hur man gör det i nästa avsnitt.

Använda `if __name__ == ’__main__’` för att köra `unittest` som huvudmodul

Om du vill köra alla enhetstester när modulen körs direkt kan du lägga till villkoret.

    # 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)

    # Kör unittest som huvudmodul
    if __name__ == '__main__':
            unittest.main()
    

Villkoret i ovanstående kodavsnitt säger till Python-tolken: Om den här modulen körs direkt, kör då koden inuti. `unittest.main()`.

Du kan köra `test_add`-modulen efter att ha lagt till ovanstående två rader kod.

        $ python test_add.py
    

▶️ Genom att köra `test_add`-modulen direkt körs alla tre tester vi har definierat.

    Utskrift
    ...
    ----------------------------------------------------------------------
    Ran 3 tests in 0.000s

    OK
    

Ovanstående utdata `OK` indikerar att alla tester kördes framgångsrikt. De tre prickarna `…` indikerar att tre tester kördes och alla godkändes.

Låt oss nu ändra det förväntade returvärdet i `test_add_1_minus7` till `8`. Eftersom funktionen returnerar `-6` i det här fallet bör ett test misslyckas.

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

Som visas i utskriften nedan får vi `.F.`, av de tre testerna misslyckades ett av dem (det andra testet), och i spårningen får vi ett `AssertionError` som säger `-6 != 8`.

    Utskrift
    .F.
    ======================================================================
    FAIL: test_add_1_minus7 (__main__.TestAdd)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "test_add.py", line 12, in test_add_1_minus7
        self.assertEqual(add_ab(1,-7), 8)
    AssertionError: -6 != 8

    ----------------------------------------------------------------------
    Ran 3 tests in 0.021s

    FAILED (failures=1)
    

En viktig sak att notera är att testerna inte nödvändigtvis körs i samma ordning som de anges i testklassen. I exemplet ovan definieras `test_add_1_minus7` som den tredje metoden i testklassen, men motsvarande test kördes som andra.

Sammanfattning

Jag hoppas att den här guiden har hjälpt dig att förstå hur villkoret `if __name__ == ’__main__’` fungerar i Python.

Här är en snabb sammanfattning av de viktigaste insikterna:

  • Python-tolken sätter variabeln `__name__` innan ett Python-skript körs.
  • När du kör en modul direkt är värdet för `__name__` lika med `__main__`.
  • När du importerar en modul i ett annat Python-skript är värdet för `__name__` modulens namn.
  • Du kan använda `if __name__ == ’__main__’` för att kontrollera exekveringen och vilka delar av modulen som körs under direkta respektive importerade körningar.

Kolla in den här djupgående guiden om Python-set. Lycka till med studierna! 🎉