Construction and destruction process analysis of Python class methods with s

  • 2020-04-02 14:38:16
  • OfStack

Recently, I learned about the Class section of the Python reference manual and encountered problems with the construction and destructor section of the Class:

1. When is it constructed?
2. When will it be destructed?
3. How to handle member variables?
4. How are Shared member functions accessed in Python?
------------------------
Exploration process:
1. It is found that there is no special construction and destructor in Python, but the initialization and deletion can generally be done with s/s and s/s. This alternative construction and destructor can be used. There is also a creation process with s/s to customize the classes, but this requires some configuration. This is not discussed here.
2. The default of the member functions of the class is equivalent to public, but the default starts at the beginning of the is private variable. Although it is private, we can also access it through certain means, that is, Python does not exist real private variables. Such as:


__priValue = 0 # It will automatically transform into "_ The name of the class __priValue" Member variable of

3. Due to the particularity of Python, the global member variables are Shared, so the instance of the class will not allocate the content space for it, which is similar to static. For specific use, please refer to the following example.

Test 1:


# encoding:utf8 class NewClass(object):
    num_count = 0 # This variable is Shared by all instances, that is, not assigned to each instance separately
    def __init__(self,name):
        self.name = name
        NewClass.num_count += 1
        print name,NewClass.num_count
    def __del__(self):
        NewClass.num_count -= 1
        print "Del",self.name,NewClass.num_count
    def test():
        print "aa" aa = NewClass("Hello")
bb = NewClass("World")
cc = NewClass("aaaa") print "Over"

Debugging and running:


Hello 1
World 2
aaaa 3
Over
DeException l Hello 2
AttributeError: "'NoneType' object has no attribute 'num_count'" in <bound method NewClass.__del__ of <__main__.NewClass object at 0x01AF18D0>> ignored
Exception AttributeError: "'NoneType' object has no attribute 'num_count'" in <bound method NewClass.__del__ of <__main__.NewClass object at 0x01AF1970>> ignored

We found that num_count is global, the value of num_count increases by one for each instance created, all instances are destructed after the program ends, i.e., calling s/s () but an exception is thrown. If you look at the exception as "NoneType," the NewClass is already garbage collected when destructed, so this exception is generated.

But, question? Why is that? According to the experience of C/C++ and other languages, it should not be so! After searching for information, we found:

Python's garbage collection process is different from that of most common languages. Python does garbage collection in dictionary order, not in creation order. So when the system does the recycling, it does it in the order of the class name a-za-z, and we can't control the flow here.

To understand this, let's try the following:


# encoding:utf8 class NewClass(object):
    num_count = 0 # This variable is Shared by all instances, that is, not assigned to each instance separately
    def __init__(self,name):
        self.name = name
        NewClass.num_count += 1
        print name,NewClass.num_count
    def __del__(self):
        NewClass.num_count -= 1
        print "Del",self.name,NewClass.num_count
    def test():
        print "aa" aa = NewClass("Hello")
bb = NewClass("World")
cc = NewClass("aaaa") del aa
del bb
del cc print "Over"

Debugging output:


Hello 1
World 2
aaaa 3
Del Hello 2
Del World 1
Del aaaa 0
Over

OK, everything happens in the order we expected.
But we can't always do it manually, can we? What's the point of doing Python's own garbage collection?

SO, continue looking, we can also access the class itself by self.arbitration class__, and then access its own Shared member variable, self.arbitration class__.num_count, and replace newclass.num_count in the class with self.arbitration class__.num_count to compile and run, as follows:


# encoding:utf8 class NewClass(object):
    num_count = 0 # This variable is Shared by all instances, that is, not assigned to each instance separately
    def __init__(self,name):
        self.name = name
        self.__class__.num_count += 1
        print name,NewClass.num_count
    def __del__(self):
        self.__class__.num_count -= 1
        print "Del",self.name,self.__class__.num_count
    def test():
        print "aa" aa = NewClass("Hello")
bb = NewClass("World")
cc = NewClass("aaaa") print "Over"

Results:


Hello 1
World 2
aaaa 3
Over
Del Hello 2
Del World 1
Del aaaa 0

Perfect! We handled it perfectly!

PS:

A few more questions are mentioned in the book, to be supplemented here (for reference only) :

S/s () is the only method to be executed before the instance is created, and is generally used when defining metaclasses.

Del XXX will not call the method with a voluntary function, but with a reference count ==0, then with a function called with a reference count ==0, then with a function called with a reference count ==0, then with a reference count with a function called with a reference count ==0. In general, s/s will not break the garbage handler.

In the experiment, it was found that the garbage collection automatically called with s/s.


Related articles: