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

I den här guiden kommer du att förstå funktionaliteten och betydelsen av if __name__ == ’__main__’ i Python.

Har du någonsin skummat igenom en Python-kodbas med olika moduler?

Om ja, skulle du förmodligen ha stött på om __name__ == ’__main__’ är villkorad i en eller flera moduler. Under de närmaste minuterna kommer vi att avmystifiera vad ovanstående villkor betyder och titta på ett exempel där det kan vara till hjälp.

Låt oss börja!

Vad är betydelsen av __namn__ i Python?

I Python är en modul en .py-fil som innehåller funktionsdefinitioner, en uppsättning uttryck som ska utvärderas och mer. Till exempel, om vi har en fil som heter hello_world.py, hänvisar vi till denna som hello_world.py-filen eller hello_world-modulen.

När du kör en Python-modul, ställer Python-tolken in värdena för några speciella variabler före exekvering: __name__ är en av dem. Nyckeln till att förstå betydelsen av __namn__ är att förstå hur import fungerar i Python.

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

Gå över till mappen exempel-1. Vi har filen module1.py. Variabeln __name__ finns i namnutrymmet för den aktuella modulen.

Denna modul skriver ut en rad följt av värdet för variabeln __name__.

# example-1/module1.py
print("This is module1.")
print(f"The __name__ variable of module 1 is: {__name__}.")

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

$ python module1.py

I utgången ser vi att variabeln __name__ är satt till __main__.

This is module1.
The __name__ variable of module 1 is: __main__.

Importera moduler i Python

Förutom att köra en Python-modul kan du ibland vilja använda funktionalitet från en annan Python-modul i den aktuella modulen. Python underlättar detta genom import.

Importer låter dig återanvända funktionen hos en annan modul – genom att importera den till den aktuella modulens omfattning – utan att behöva skriva om koden.

Modul2.py-filen innehåller följande. Vi har importerat modul1 inuti. modul2.

# example-1/module2.py

import module1 # module1 is imported

print(f"This is module2")
print(f"The __name__ variable of module2 is: {__name__}.")

Vi kör module2.py och observerar resultatet.

$ python module2.py

I utgången nedan:

  • Vi ser att modul1 körs under huven när vi importerar den inuti modul2, och motsvarande utdata skrivs ut.
  • Men den här gången är variabeln __name__ inte __main__ utan modul1.
  • Eftersom vi körde module2 direkt, är variabeln __name__ som motsvarar modulen nu __main__.
Output

This is module1.
The __name__ variable of module 1 is: module1.
This is module2
The __name__ variable of module2 is: __main__.

💡 Nyckelidé:

– Om en modul körs direkt, är dess variabel __name__ inställd på lika med __main__.

– Om en modul importeras in i en annan modul sätts dess __namn__ till modulens namn.

Exempel på om __name__==’__main__’ i Python

I avsnittet kommer vi att se ett praktiskt användningsfall av villkoret if __name__ == ’__main__’. Vi kommer att definiera en enkel funktion och sedan skriva enhetstester för att kontrollera om funktionen fungerar som förväntat.

📁 Ladda ner koden och följ med.

Koden för detta avsnitt 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 valfria två 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

Titta på kodavsnittet 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 inom testklassen

För att ställa in enhetstester för din kod bör du först definiera en testklass som ärver från unittest.TestCase. Alla testfall ska anges som metoder i klassen och bör börja med test_.

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

Låt oss nu försöka 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 är det så?🤔

Detta beror på att för att köra enhetstesten, bör du köra unittest som huvudmodul medan du kör test_add.py, med kommandot nedan.

$ python -m unittest test_add.py

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

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

OK

Det kommer dock att vara bekvämt att köra testerna när denna modul test_add körs, ja? Låt oss lära oss hur man gör det i nästa avsnitt.

Använder 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)

# Run unittest as the main module
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 sedan koden inuti. unittest.main().

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

$ python test_add.py

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

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

OK

Ovanstående utgång 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 test_add_1_minus7 till 8. Eftersom funktionen returnerar – 6 i det här fallet bör det finnas ett test som misslyckas.

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

Som framgår av utgången nedan får vi .F., av de tre testerna, mönster ett av dem misslyckades (det andra testet), och i spårningen får vi ett AssertionError som säger – 6 != 8.

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

Summering

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

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

  • Python-tolken ställer in variabeln __name__ innan Python-skriptet körs.
  • När du kör en modul direkt är värdet för __name__ __main__.
  • När du importerar en modul i ett annat Python-skript är värdet på __name__ modulnamnet.
  • Du kan använda if __name__ == ’__main__’ för att styra exekvering och vilka delar av modulen som körs under direkta respektive importerade körningar.

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