Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python strange multiprocessing with variable name

a simple example:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import multiprocessing

class Klass(object):
    def __init__(self):
        print "Constructor ... %s" % multiprocessing.current_process().name

    def __del__(self):
        print "... Destructor %s" % multiprocessing.current_process().name


if __name__ == '__main__':
    kls = Klass()

run with error when do current_process in __del__:

Constructor ... MainProcess
Exception AttributeError: "'NoneType' object has no attribute 'current_process'" in <bound method Klass.__del__ of <__main__.Klass object at 0x7f5c34e52090>> ignored

if I change a variable name:

als = Klass()

it get the right result:

Constructor ... MainProcess
... Destructor MainProcess

and I tried many variable name, some ok, some error.

Why different instance name, will cause multiprocessing module be None in __del__?

like image 523
Tanky Woo Avatar asked Sep 07 '15 16:09

Tanky Woo


1 Answers

The code raises

AttributeError: "'NoneType' object has no attribute 'current_process'"

if the global variable multiprocessing is deleted before kls gets deleted. In general, the order in which objects are deleted is not predictable. However, per the docs:

Starting with version 1.5, Python guarantees that globals whose name begins with a single underscore are deleted from their module before other globals are deleted; if no other references to such globals exist, this may help in assuring that imported modules are still available at the time when the __del__() method is called.

Therefore, if you name the instance _kls (with an underscore), then you can be assured that its __del__ will be called before multiprocessing is deleted:

import multiprocessing 

class Klass(object):
    def __init__(self):
        print "Constructor ... %s" % multiprocessing.current_process().name

    def __del__(self):
        print "... Destructor %s" % multiprocessing.current_process().name


if __name__ == '__main__':
    _kls = Klass()

yields

Constructor ... MainProcess
... Destructor MainProcess

Other methods of ensuring a del method is called before the module is deleted include

  • using atexit
  • using a context manager
  • saving a reference to the module as an attribute of Klass.
like image 170
unutbu Avatar answered Sep 17 '22 20:09

unutbu