Confuzed about class variables vs instance variables

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • MooseMiester
    New Member
    • Sep 2007
    • 7

    Confuzed about class variables vs instance variables

    This little program just doesn't do what I think it should and I cannot understand what the problem is.

    I'm running Python 2.4 on Windoze XP.

    It contains an album class, an album collection class, a track class, and a track collection class.

    It seems confused about which instance is which -- when it says Albums.Tracks.C ount() the two instances are unique, but when it says Album.Tracks you get both instances combined. It's as if all accessors in Python are equal, but some accessors are more equal than others :-)

    Here's the code. It is the smallest example I could make to demonstrate this behavior.
    [CODE=python]
    # Making a nested set of objects
    # A track
    class TrackClass:
    def __init__(self, ID, Title):
    self.ID = ID
    self.Title = Title

    # A collection of Tracks
    class TracksClass:
    Items = []
    ItemCount = 0
    def Add(self, ID, Title):
    self.Items.appe nd(TrackClass(I D,Title))
    self.ItemCount += 1
    def Count(self): return self.ItemCount
    def __getitem__(sel f,ordinal): return self.Items[ordinal]

    class AlbumClass:
    def __init__(self,I D,Title):
    self.ID = ID
    self.Title = Title
    self.Tracks = TracksClass()
    # A collection of Albums
    class AlbumsClass:
    Items = []
    ItemCount = 0
    def Add(self,ID,Tit le):
    self.Items.appe nd(AlbumClass(I D,Title))
    self.ItemCount += 1
    def __getitem__(sel f,ordinal): return self.Items[ordinal]
    def Count(self) : return self.ItemCount


    Albums = AlbumsClass()
    Albums.Add(ID = 1, Title = "First Album")
    Albums[0].Tracks.Add(ID = 1, Title = "First Album First Track")
    Albums[0].Tracks.Add(ID = 2, Title = "First Album Second Track")
    Albums.Add(ID = 2, Title = "Second Album")
    Albums[1].Tracks.Add(ID = 3, Title = "Second Album First Track")
    Albums[1].Tracks.Add(ID = 4, Title = "Second Album Second Track")
    Albums[1].Tracks.Add(ID = 5, Title = "Second Album Third Track")

    print "This does not print the expected results"
    for Album in Albums:
    print "Album (%i) %s has %i tracks" % (Album.ID, Album.Title, Album.Tracks.Co unt())
    for Track in Album.Tracks:
    print " Track: (%i) %s" % (Track.ID, Track.Title)
    print ""[/CODE]
    Last edited by bartonc; Sep 27 '07, 07:21 AM. Reason: Added [CODE=python][/CODE] tags.
  • bvdet
    Recognized Expert Specialist
    • Oct 2006
    • 2851

    #2
    Originally posted by MooseMiester
    This little program just doesn't do what I think it should and I cannot understand what the problem is.

    I'm running Python 2.4 on Windoze XP.

    It contains an album class, an album collection class, a track class, and a track collection class.

    It seems confused about which instance is which -- when it says Albums.Tracks.C ount() the two instances are unique, but when it says Album.Tracks you get both instances combined. It's as if all accessors in Python are equal, but some accessors are more equal than others :-)

    Here's the code. It is the smallest example I could make to demonstrate this behavior.
    [code=Python]
    # Making a nested set of objects
    # A track
    class TrackClass:
    def __init__(self, ID, Title):
    self.ID = ID
    self.Title = Title

    # A collection of Tracks
    class TracksClass:
    Items = []
    ItemCount = 0
    def Add(self, ID, Title):
    self.Items.appe nd(TrackClass(I D,Title))
    self.ItemCount += 1
    def Count(self): return self.ItemCount
    def __getitem__(sel f,ordinal): return self.Items[ordinal]

    class AlbumClass:
    def __init__(self,I D,Title):
    self.ID = ID
    self.Title = Title
    self.Tracks = TracksClass()
    # A collection of Albums
    class AlbumsClass:
    Items = []
    ItemCount = 0
    def Add(self,ID,Tit le):
    self.Items.appe nd(AlbumClass(I D,Title))
    self.ItemCount += 1
    def __getitem__(sel f,ordinal): return self.Items[ordinal]
    def Count(self) : return self.ItemCount


    Albums = AlbumsClass()
    Albums.Add(ID = 1, Title = "First Album")
    Albums[0].Tracks.Add(ID = 1, Title = "First Album First Track")
    Albums[0].Tracks.Add(ID = 2, Title = "First Album Second Track")
    Albums.Add(ID = 2, Title = "Second Album")
    Albums[1].Tracks.Add(ID = 3, Title = "Second Album First Track")
    Albums[1].Tracks.Add(ID = 4, Title = "Second Album Second Track")
    Albums[1].Tracks.Add(ID = 5, Title = "Second Album Third Track")
    [/code][code=Python]
    print "This does not print the expected results"
    for Album in Albums:
    print "Album (%i) %s has %i tracks" % (Album.ID, Album.Title, Album.Tracks.Co unt())
    for Track in Album.Tracks:
    print " Track: (%i) %s" % (Track.ID, Track.Title)
    print ""[/code]I added code tags for you. Now we can see your code structure.

    Comment

    • MooseMiester
      New Member
      • Sep 2007
      • 7

      #3
      Well, this looks like a BUG to me -- if someone with a newer version (I'm on 2.4) would run this and let me know what the results are I'd appreciate it.

      The MooseMiester

      Comment

      • bvdet
        Recognized Expert Specialist
        • Oct 2006
        • 2851

        #4
        Originally posted by MooseMiester
        Well, this looks like a BUG to me -- if someone with a newer version (I'm on 2.4) would run this and let me know what the results are I'd appreciate it.

        The MooseMiester
        I see no bug. You need an __init__ method in TracksClass to create an instance. The tracks are accumulating as a class attribute.

        Comment

        • bartonc
          Recognized Expert Expert
          • Sep 2006
          • 6478

          #5
          Here's the deal. When you declare class variables as in:[CODE=python]
          # A collection of Tracks
          class TracksClass:
          Items = []
          ItemCount = 0[/CODE]you create variables shared by all instances.

          Instance variables are always assigned as[CODE=python]self.something = value[/CODE]Preferably, but not necessarily, in __init__().

          Comment

          • MooseMiester
            New Member
            • Sep 2007
            • 7

            #6
            Thanks bartonc

            I would not have guessed that it worked this way in a hundred years, as I expect something called a "class" to exhibit a degree of "encapsulat ion" without me having to explicitly make that happen -- Silly me!!

            What IDE are you using? Coming from C++ C# what's missing the most in Python is a good IDE, like Visual Studio from MickeySoft.

            Thanks Again

            The MooseMiester

            Comment

            • bartonc
              Recognized Expert Expert
              • Sep 2006
              • 6478

              #7
              Originally posted by MooseMiester
              Thanks bartonc

              I would not have guessed that it worked this way in a hundred years, as I expect something called a "class" to exhibit a degree of "encapsulat ion" without me having to explicitly make that happen -- Silly me!!
              I have to disagree with you, here. This is an ideal implementation of the object model: Just as two (or more) objects in the real world may share resources, so, too, may instances of Python objects. Consider two debit cards on an account : Each has its own PIN (instance variable), but using one to withdraw money will effect the balance available to the other.
              What IDE are you using? Coming from C++ C# what's missing the most in Python is a good IDE, like Visual Studio from MickeySoft.

              Thanks Again

              The MooseMiester
              I use Boa Constructor. I find it flexible and stable. And it's free. For other options, check out this review.

              Comment

              Working...