Search code examples
pythonpointersdata-structuresdynamicmemory-address

Python dynamic structure and memory rellocation


I am encountering this error that I think can be related to memory.

I have a class Page()

class Page:
    index = [None] * 3
    is_word = False     #If this is false, then is not an end word, just a passing index

Pages are used to build a dynamic structure, index is an array of pointers (or addresses) to other pages. Initially this addresses are empty and only when added they will contain the address to another page.

As you can see the index has all values to none when any page is created.

In one part of my code I have this:

self.index[1] = Page() #Create new page
new_page = self.index[1]

After this code is executed the initial page should contain in the array index:

  • None
  • new created page
  • None

And the new_page should should contain in the array index:

  • None
  • None
  • None

The problem is that the new_page instead contains

  • None
  • new created page
  • None

This has no sense, I am not assigning the address of the new page to this position of the index in any line. Debugging I can see that at the moment self.index[1] = Page() #Create new page is executed this new created page already contains that wrong value in the index.

I am not used to python (I am a Java and C programmer), after sometime of my first project with python I was assuming that python handles memory and I don't have to care much about it.

I think the error happens because the original array is empty and I am assigning to it a Page object so probably I am causing a memory problem. This would be handled in C with reallocs but I don't know how to solve this in python, or if maybe this memory allocation is not needed in python and the problem is a different one I am not seeing.

P.D. As requested, full code:

class Page:
    index = [None] * 256  #One for each ascii character
    is_word = False     #If this is false, then is not an end word, just a passing index
    
    
    def insert_word(self, word):
        if(len(word) == 1): #Final condition
            ascii_number_word = ord(word[0])
            page_of_index = self.index[ascii_number_word]
            if(page_of_index == None): #If the index is not present
                page_of_index = self.index[ascii_number_word] = Page()
                page_of_index.is_word = True #Mark page as word  
        else:
            letter = word[0]
            resulting_word = word[1:]
            ascii_number_letter = ord(letter)
            page_of_index = self.index[ascii_number_letter]
            if(page_of_index == None): #index does not exist, then create
                self.index[ascii_number_letter] = Page() #Create new page
                page_of_index = self.index[ascii_number_letter]
            page_of_index.insert_word(resulting_word)

Solution

  • That is because the attributes defined at class level are considered static in Python. Try this:

    class Page:
        def __init__(self):
            self.index = [None] * 3
            self.is_word = False
    
        def create_middle_page(self):
            self.index[1] = Page()
            new_page = self.index[1]
            print(new_page)
        
        def __str__(self):
            return str(self.index)
    
    
    page = Page()
    page.create_middle_page()
    print(page)
    

    Output:

    [None, None, None]
    [None, <__main__.Page object at 0x7f3bc6326fd0>, None]
    

    Give a look at section 9.3.5 here: https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables

    From the above doc:

    class Dog:
    
        kind = 'canine'         # class variable shared by all instances
    
        def __init__(self, name):
            self.name = name    # instance variable unique to each instance