1

I have the following problem, i am an amateur user of Python scripting. I have created the following class

 roof_height = 3.5 #m
 E = 30000*(10^3) #kN/m^2

 class Brace():
     _registry = []


     def __init__(self,name,coord,b,d, h = roof_height):
          print('Brace created.')
          Brace._registry.append(self)
          self.name  = name 
          self.coord = coord              # pass tuple in the form of (x,y)
          self.b     = b                  # //x global
          self.d     = d                  # //y global
          self.h     = h

      def __del__(self):
          print('Destructor called, Brace deleted.')
          Brace._registry.remove(self)


      def properties(self):
          print("properties of " + self.name + " calculated")
          As = self.b*self.d
          Iy = self.b*(self.d**3)*(1/12)
          Iz = (self.b**3)*(self.d)*(1/12)
          self.Iy =  Iy
          self.Iz =  Iz
          self.As =  As

    def stiffness(self):
        print("stiffnesses of " + self.name + " calculated")
        Kx = 12*E*self.Iy/self.h
        Ky = 12*E*self.Iz/self.h

        self.Kx = Kx
        self.Ky = Ky

I have created the _registry general property of the class so I can iterate through the objects, which works fine. The problems that I am facing are the following: 1. When I am creating an object the print out

 'Brace created'

is displayed, but when I am deleting it the message

 'Destructor called, Brace deleted.'

is not displayed while the object is deleted, also the _registry list remains the same without deleting the object. The length of the list obviously remains the same.

  1. How can I avoid creating the same instance twice with the same name, I mean how can I check for duplicate instances (same object name and attribute values) Do I have to write a code for it or is there a builtin function that I can use?
Zoran Pandovski
  • 2,312
  • 14
  • 24
iovo
  • 21
  • 3
  • 5
    "when i am deleting it" - how are you deleting the instance? Can you include this bit of your code? – asongtoruin Jun 28 '18 at 08:09
  • It's a bit unclear to me what you expect the `remove()` to do. Do you expect it to remove `self` (in this case, the `Brace` object) from the list ***and*** delete the object from memory, or do you expect it to just remove it from the list? – rst-2cv Jun 28 '18 at 08:10
  • Check https://stackoverflow.com/questions/35488705/is-relying-on-del-for-cleanup-in-python-unreliable and consider creating the methods required for a context manager. – cdarke Jun 28 '18 at 08:11
  • @asongtoruin for example `brace1 = Brace('K1',(3,2),0.5,1.5)` for creating the object and `del brace1` for deleting it. @ResetACK Yes i want to delete the object and remove it from the list. @cdarke thanks will do. – iovo Jun 28 '18 at 08:11
  • 3
    `__del__` is probably not what you think it is - it is invoked by the garbage collector – wiesion Jun 28 '18 at 08:14
  • `del x` simply deletes the *reference*. The `__del__` method of an object gets called when the reference count of an object becomes 0 – juanpa.arrivillaga Jun 28 '18 at 08:29

1 Answers1

3

1: __del__() might not be getting called for a number of reasons to do with garbage collection. From the documentation:

Note del x doesn’t directly call x.__del__() — the former decrements the reference count for x by one, and the latter is only called when x‘s reference count reaches zero. Some common situations that may prevent the reference count of an object from going to zero include: circular references between objects (e.g., a doubly-linked list or a tree data structure with parent and child pointers); a reference to the object on the stack frame of a function that caught an exception (the traceback stored in sys.exc_info()[2] keeps the stack frame alive); or a reference to the object on the stack frame that raised an unhandled exception in interactive mode (the traceback stored in sys.last_traceback keeps the stack frame alive). The first situation can only be remedied by explicitly breaking the cycles; the second can be resolved by freeing the reference to the traceback object when it is no longer useful, and the third can be resolved by storing None in sys.last_traceback. Circular references which are garbage are detected and cleaned up when the cyclic garbage collector is enabled (it’s on by default). Refer to the documentation for the gc module for more information about this topic.

Rather than relying on the built-in memory management functionality, perhaps you could implement a bespoke function for freeing up resources once an object is no longer needed?

2: To avoid having two instances with the same name, use the factory pattern.

user234461
  • 1,133
  • 12
  • 29
  • Thank you all for your replies. You helped me understand the problem with the circular references and the garbage_collector of python. Through your references i also found this [link](https://eli.thegreenplace.net/2009/06/12/safely-using-destructors-in-python) which helped understand it a little better. For now i decided to remove the registry list and create a list with the objects that i want outside the class. In that way there are no references left and the destructor is called when the reference closes. I – iovo Jun 28 '18 at 08:58