Gregory
Gregory

Reputation: 4279

Why is attribute being inherited across classes in Python?

I'm apparently having some trouble learning how to use classes correctly. I expect the following code to loop through a set of files (it does), adding elements to a set as it goes (it does), and starting the set over when it moves to a new file (it does not). The way I've hacked at the code below, I would expect it to return an empty set each time for file.terminals, because I believe that each set is the unique attribute of a new instance of the class SrcFile. Apparently, I am mistaken. What actually happens is that the set of terminals created by the first file persists (and is added to) for all subsequent files in the list, although other attributes (e.g. file.name, file.seqlength()) change appropriately with the files. Can someone please explain why it works this way and how I can create the behavior that I'm expecting? Thanks in advance for your patience with a beginning programmer's ignorance.

class SrcFile:
   terminals = set([])
   def __init__(self, which):
      self.name = which
   def seqlength(self):
      with open(self.name) as file:
         linecounter = 0
         for line in file:
            linecounter += 1
            if linecounter == 3:
               return int(line.split()[0])
               break

class Record(SrcFile):
   def terminal(self):
      record = self.name
   def terminal(self):
      record = self.name
      return record.split()[0]

for f in files:
   file = SrcFile(f)
   print(file.name, file.seqlength(), file.terminals)

   with open(f) as f:
      recordline = re.compile(r"^([A-Z]{5})\s{3}")
      for line in f:
         if recordline.match(line):
            record = Record(line)
            if record.terminal() in file.terminals:
               pass
            else:
               file.terminals.add(record.terminal())

Upvotes: 3

Views: 367

Answers (2)

Blender
Blender

Reputation: 298552

You are defining terminals within the class declaration, not within the __init__ function that's executed for every new instance of the class.

Basically, terminals is initialized for the whole class, not for each instance of the class:

>>> SrcFile.terminals
set([])

Notice I ran SrcFile.terminals, not SrcFile().terminals, which means that SrcFile is a reference to the class, not an instance of the class.

You put variables like that inside of the __init__ function to make them instance-specific:

class SrcFile(object):
  def __init__(self, which):
    self.name = which
    self.terminals = set([])

Upvotes: 4

ThiefMaster
ThiefMaster

Reputation: 318778

By defining terminals = set([]) in the class itself it is created once when the class is defined an not when an instance is created.

To avoid this, remove it and add the following to your __init__ method:

self.terminals = set()

Upvotes: 3

Related Questions