Search code examples
pythonseleniumprocessmultiprocessingterminate

Changing a variable name affects the code behavior


When I run this code, one of the selenium windows is not closed

import multiprocessing

from selenium import webdriver


class Worker:
    def __init__(self):
        self.driver = webdriver.Chrome()

    def run(self):
        self.driver.get('https://www.google.com')


processes = []
for i in range(2):
    worker = Worker()
    process = multiprocessing.Process(target=worker.run)
    process.start()
    processes.append(process)

for any_name in processes:
    any_name.terminate()

But if I change variable name from any_name to worker, then all selenium windows are closed. Why is this happening?

PS version: python 3.7, chromedriver 83, selenium 3.141.0


Solution

  • This is because the browser closing behavior depends on the __del__ method of selenium.webdriver.common.service.Service to make the browser Windows exit, and __del__ will only be called when there are no more references to your WebDriver instances. Here is the implementation of Service.__del__:

        def __del__(self):
            # `subprocess.Popen` doesn't send signal on `__del__`;
            # so we attempt to close the launched process when `__del__`
            # is triggered.
            try:
                self.stop()
            except Exception:
                pass
    

    The stop() method shuts everything down.

    Now, the reason the variable naming matters is that it effects whether or not there are any references to a WebDriver when your program exits. When your first for loop completes, worker is still in-scope, which holds a reference to the second Worker you created, which holds a reference to the WebDriver. That keeps it in scope when your main program completes, which means __del__ is never called, and the browser window doesn't close.

    However, when you re-use worker for the second for loop, it means the reference to the second Worker is no longer held, which means there are no references to WebDriver in-memory, which means __del__ will be called and the window will close. You can confirm this behavior by explicitly adding worker = None outside of the first for loop. With that change, both browser windows always exit, no matter what variable name you use in the second loop.