Use of if __name__=='__main__'. Why is the class not instantiated?

Asked

Viewed 943 times

1

There is little time that I am using Python and there are some things that I still get confused, my doubt is in this code:

import unittest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

class PythonOrgSearch(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.Firefox()

    def test_search_in_python_org(self):
        driver = self.driver
        driver.get("http://www.python.org")
        self.assertIn("Python", driver.title)
        elem = driver.find_element_by_name("q")
        elem.send_keys("pycon")
        elem.send_keys(Keys.RETURN)
        assert "No results found." not in driver.page_source


    def tearDown(self):
        self.driver.close()

if __name__ == "__main__":
    unittest.main()

Why in the "if __name__ == "__main__":" he did not urge the class PythonOrgSearch and why when placing the command "unittest.main()" he executed the actions of the class Pythonorgsearch? This way does not get more confused? Can anyone explain why he did it this way?

  • 1

    O "if name == "main":" is not in the class "Pythonorgsearch"

  • 2

    This has more to do with how the framework unittest is used than with code Python pure

  • 1

    Agree with @Jeffersonquesado, try to change the class arguments to Object

  • I understood that it is because of the framework, but I’m still having the same problem, if I find a code this way I won’t know that unittest.main() will run the Pythonorgsearch class, how can I identify it, without having to run the code.

  • 1

    Knowing the code is the only way. The library unittest does things that seem magical even, not following much the philosophy of "explicit is better than implicit".

2 answers

3


Split: Your block class with the class declaration creates the class yes - does not create a class instance. In Python this would be done using the class name as if it were a function call: PythonOrgSearch(). (Without needing the keyword new as in Java and Javascript).

What happens to the class unittest.TestCase is special in the sense that the programmer does not need to instantiate the subclasses: when calling the function unittest.main(), the code there takes care of using introspection to find the subclasses of TestCase and run the tests contained in them. In practice, they are barely used as "classes", except for the fact that you can create attributes in the setup which will be available for the "test methods".

That is: this code file declares the class and that is it. What makes the tests run when it is called unittest.main is the code itself that is there (in Python itself, just open the file and see - despite having many layers of extras to handle exceptions, etc...). And this is done because it was an interesting way that they thought at the time to trigger the execution of a group of tests - there’s nothing special in the language about that. Without that code inside the unittest.main() that file just wouldn’t do anything.

Already the line that seems special if __name__ == "__main__": is a widely used Python Pattern based on the special variable __name__: the language itself arrow this variable to be equal to the file name .py running, except for when that file is the main running program. (That’s: you called python arquivo.py. ) In this case, the value of this variable is "__main__" (and not "file"). So what is this if makes is to define a block of code that will only run if the current file is called as the main Python program, but not when it is imported into another file, with the command import.

The standard way of writing tests puts in this block the call of unittet.main, which does what I described above. Apart from some special things in logging, and treating exceptions, do what that unittest.main does is nothing out of this world - and, a simplified form can be made in very few lines. A module unittest minimum could be:

class TestCase(object):
    def setUp(self):
        pass
    def tearDown(self):
        pass


def main():
   errors = []
   passed = 0
   failed = 0
   for cls in TestCase.__subclasses__():
       # acima teria que ser um pouco mais
       # sofisticado: o metodo __sublasses__
       # só  devolve as subclasses imediatas (mas não as  'netas')
       for attribute in cls.__dict__:
           if not attribute.startswith("test_"):
               continue
           if not callable cls.__dict__[attribute]:
               continue
           # A linha abaixo cria a instancia da classe em si.
           # Uma instância para cada método de teste:
           instance = cls()
           instance.setUp()
           try:
               # Execut o método de teste
               getattr(instance, attribute)()
           except Exception as err:
               message = "F"
               failed += 1
               erros.append(str(err))
           else:
               message = "."
               passed += 1
           finally:
               instance.tearDown() 
           print(message, end=" ", flush=True)

     print(f"\n\nFinished. Total tests: {failed + passed}, passed: {passed}, failed: {failed}")

2

I see that you already have an answer with a good theoretical explanation, so I will answer without worrying about the functioning of Testecase, based on the comments, I will try to induce the author of the question to understand the meaning of if __name__ == __main__

Let’s create a script called foo.py

import bar
print ('Nome do modulo no arquivo foo.py:',__name__)

And another called bar.py

print ('Nome do modulo no arquivo bar.py:',__name__)

We run foo.py see the result:

$ python foo.py
Nome do módulo, no arquivo bar.py:  bar
Nome do modulo no arquivo foo.py: __main__

See that on the call to foo o __name__ of the module in the script that was called is __main__, as a bar was called 'indirect', its name is the name of the script itself, but if you call it individually, see the result:

$ python bar.py 
Nome do módulo, no arquivo bar.py:  __main__

Now let’s change the files so that bar calling foo, thus:

foo py.

print ('Nome do modulo no arquivo foo.py:',__name__)

bar py.

import foo
print ('Nome do módulo, no arquivo bar.py ', __name__)

See now the result when we run foo:

$ python foo.py 
Nome do modulo no arquivo foo.py: __main__

The name of foo here is __main__, because this being called as the main module, now see when we call bar.

$ python bar.py 
Nome do modulo no arquivo foo.py: foo
Nome do módulo, no arquivo bar.py  __main__

When we call it a bar, he is now, __main__ and what he calls foo, this becomes, say secondary and loses the name __main__

  • When using the from bar import baz, would also print the Nome do módulo, no arquivo bar.py bar?

  • 1

    @Jeffersonquesado, if I understand your question, the answer is Yes. See q in the first example, just having imported bar, the exit was the print of bar first (resulting from import) and the print of foo. The exit of bar would not be displayed if the command was inside the if __name__=='__main__:, but I didn’t want to do it exactly to force the reasoning.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.