0

I want to fill a list within a class but I do not find a way to pass it from the calling module to the class and/or back again. Here is the calling module:

from NamesClass import Names
global TABLE, Names_db
TABLE = []
Names_db = []
RDATAPATH = "C:/users/richo/documents/python/Name Data/yob.txt"
L = Names.LoadTable(RDATAPATH)
print(L, len(Names_db))

The print returns 1888 0. The two numbers should be the same. Here is the class code:

class Names:
    def __init__(self):
        pass
    def LoadTable(rdatapath):
        """ load and sort a list from the text file
            return the length of the list """
        global TABLE, Names_db
        TABLE = []
        Names_db = []
        first_time = True
        with open(rdatapath) as f:
         for line_of_text in f:
             line_of_text = line_of_text.strip()
             aname = line_of_text.split(',')
             TABLE.append(aname[1]+','+aname[0]+','+aname[2]+','+aname[3]) #name, year, sex, occurences
        TABLE.sort() #sort by name
        for i, a_record in enumerate(TABLE):
            record = a_record.split(',')
            if first_time:
                previous_name = record[0]
                previous_sex = record[2]
                sum = 0
                first_time = False
            if previous_name != record[0]:
                Names_db.append(str(i)+previous_name+previous_sex+str(sum))
                sum = 0
                first_time = True
            previous_name = record[0]
            previous_sex = record[2]
            sum += int(record[3])
        return(len(Names_db))
ktzr
  • 1,625
  • 1
  • 11
  • 25
  • Possible duplicate of [Global Variable from a different file Python](https://stackoverflow.com/questions/3400525/global-variable-from-a-different-file-python) – ktzr May 12 '18 at 22:54
  • Since I don't have "yob.txt" on my computer, would you be so kind as to provide example data. – figbeam May 12 '18 at 23:08

3 Answers3

1

You can pass a list around between modules and make changes to it and those changes will be reflected everywhere. It's only assigning a new value from scratch using = that's a problem. So you can do:

TABLE = []
Names_db = []
Names.LoadTable(RDATAPATH, TABLE, Names_db)
print(len(Names_db))

And in the class:

def LoadTable(rdatapath, table, names_db):

Then just use table and names_db when appending and sorting. You don't need to return anything.

Alex Hall
  • 34,833
  • 5
  • 57
  • 89
0

First off -- you can make the code more robust by passing the table in as an argument to Names.LoadTable. That function can add names to the table without creating it fresh. Here's the cut-down version

TABLE = []

class ModifiesTables:
     
    @classmethod
    fill_table(cls, incoming_table):
        # real logic would go here
        for n in range(100):
            incoming_table.append(n)


 ModifiesTables.fill_table(TABLE)
 print(TABLE)
 #  [0,1,2.....]

you will undoubtedly be told that globals are a bad idea, and they are. However if you create the table outside the function -- for example the way I did it above - it will be accessible to functions defined in the same scope without extra work. The example above could also look like this:

  TABLE = []

  def fill_table():
      for n in range(100):
          TABLE.append(n)

However this only works in the same scope, and your example makes it look like you are declaring the 'global' table in one file and the class in another. In that case the first example is better practice because the relationship is clear, rather than implicit (and you don't need to worry if, for example, you decided to move things into different files).

Although Python has a global keyword, you only need it if you are assigning to the global, instead of just using it. So this works:

   TABLE = []

   def works():
       TABLE.append("I work")  #using, not assigning

but this does not

   def does_not_work():
       TABLE = []  # this declares a local with the same name, the original is ignored

in that case you would need the global:

   def works_but_use_sparingly():
       global TABLE
       TABLE = [] # this will replace TABLE with a new list

The official explanation of this behavior is:

In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a value anywhere within the function’s body, it’s assumed to be a local unless explicitly declared as global.

Though a bit surprising at first, a moment’s consideration explains this. On one hand, requiring global for assigned variables provides a bar against unintended side-effects. On the other hand, if global was required for all global references, you’d be using global all the time. You’d have to declare as global every reference to a built-in function or to a component of an imported module. This clutter would defeat the usefulness of the global declaration for identifying side-effects.

Lots more in this question.

Community
  • 1
  • 1
theodox
  • 12,028
  • 3
  • 23
  • 36
0

Thank you. I am teaching myself and doing this as a hobby. I have a working version, written inline, and classes were not needed but I wanted to learn how to use them. Your answers give me what I need to proceed. Thank you for taking the time. I wish I had your knowledge.

Next, I am going to learn how to use Django to get my program on the web and I am already confused but I'll not bother anyone with my questions for now.