initializing class with certain names causes runtime errors

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Mark2012
    New Member
    • Apr 2010
    • 5

    initializing class with certain names causes runtime errors

    Hello, I am new to programming with python. I am using the tutorial, "Byte of Python" and am on p. 82. I have come across something very unusual by accident and I was wondering if anybody here could figure it out. In the program attached, if I use "wanless.sayHI( )" which is my name,python gives an error message........ .Exception AttributeError: "'NoneType' object has no attribute 'population'" in <bound method Person.__del__ of <__main__.Perso n instance at 0xb76056ec>> ignored..... Any of the commented out groups of code do the same. I was looking for a bad indent or missing ' or anything for about an hour. Once I figured it out I thought is was so funny I had to send it to someone who knows python just to see what you think of it. I used both "Idle using Python2.6.2", and gedit 2.26.1, to create the program and I get the same results with either one. I use Ubuntu 9.04 the original program is from the book "Byte of Python" p.82 2003-2005 edition

    result of program as is

    Code:
    (Initializing Swaroop)
    Hi, my name is Swaroop.
    I am the only person here.
    (Initializing less)
    Hi, my name is less.
    We have 2 persons here.
    (Initializing wanles)
    Hi, my name is wanles.
    We have 3 persons here.
    Hi, my name is Swaroop.
    We have 3 persons here.
    wanles says bye.
    There are still 2 people left.
    less says bye.
    There are still 1 people left.
    Swaroop says bye.
    I am the last one.
    result of code with block 1 uncommented

    Code:
    (Initializing Swaroop)
    Hi, my name is Swaroop.
    I am the only person here.
    (Initializing wanless)
    Hi, my name is wanless.
    We have 2 persons here.
    (Initializing less)
    Hi, my name is less.
    We have 3 persons here.
    (Initializing wanles)
    Hi, my name is wanles.
    We have 4 persons here.
    Hi, my name is Swaroop.
    We have 4 persons here.
    wanles says bye.
    There are still 3 people left.
    less says bye.
    There are still 2 people left.
    Swaroop says bye.
    There are still 1 people left.
    wanless says bye.
    Exception AttributeError: "'NoneType' object has no attribute 'population'" in <bound method Person.__del__ of <__main__.Person instance at 0xb766f48c>> ignored
    the code is exactly the same as the book down to line 35


    Code:
    #!/usr/bin/python
    # Filename: objvar.py
    #          Mark Wanless
    
    class Person:
            '''Represents a person.'''
            population = 0
            def __init__(self, name):
                    '''Initializes the person's data.'''
                    self.name = name
                    print '(Initializing %s)' % self.name
                    # When this person is created, he/she
                    # adds to the population
                    Person.population += 1
            def __del__(self):
                    '''I am dying.'''
                    print '%s says bye.' % self.name
                    Person.population -= 1
                    if Person.population == 0:
                             print 'I am the last one.'
                    else:
                             print 'There are still %d people left.' % Person.population
            def sayHi(self):
                    '''Greeting by the person.
                    Really, that's all it does.'''
                    print 'Hi, my name is %s.' % self.name
            def howMany(self):
                    '''Prints the current population.'''
                    if Person.population == 1:
                             print 'I am the only person here.'
                    else:
                             print 'We have %d persons here.' % Person.population
    swaroop = Person('Swaroop')
    swaroop.sayHi()
    swaroop.howMany()
    
    less = Person('less') ### no problem
    less.sayHi()
    less.howMany()
    
    wanles = Person('wanles')### no problem
    wanles.sayHi()
    wanles.howMany()
    
    ############when I uncommment any of these below
    ############I get the error message
    
    
        ########     block 1     ##############
    
    #wanless = Person('wanless')
    #wanless.sayHi()
    #wanless.howMany()
    
        ########     block 1     #############
    
    
    
    #les = Person('les')
    #les.sayHi()
    #les.howMany()
    
    
    #wanle = Person('wanle')
    #wanle.sayHi()
    #wanle.howMany()
    
    swaroop.sayHi()
    swaroop.howMany()
    Last edited by Mark2012; Apr 21 '10, 10:15 AM. Reason: no longer need attached txt
  • Glenton
    Recognized Expert Contributor
    • Nov 2008
    • 391

    #2
    What the heck?!? What's going on here? I don't get it!

    Comment

    • woooee
      New Member
      • Mar 2008
      • 43

      #3
      It has to do with the __del__ function trying to print Person.populati on after it has been garbage collected. I do not know why this is, but perhaps has to do with reducing the counter in __del__ (as the class is destroyed) when the program exits.

      Edit: If you remove the class instances yourself, then it runs correctly
      Code:
          ## add this code at the end
          ## "de-stantiate" (just kidding)
          swaroop = None
          less = None
          wanles = None
          wanless = None
          les = None

      Comment

      • Mark2012
        New Member
        • Apr 2010
        • 5

        #4
        Originally posted by Glenton
        What the heck?!? What's going on here? I don't get it!
        Thanks for answering. I was thinking as a newbie there was something I just don't know about.

        Comment

        • Mark2012
          New Member
          • Apr 2010
          • 5

          #5
          Originally posted by woooee
          It has to do with the __del__ function trying to print Person.populati on after it has been garbage collected. I do not know why this is, but perhaps has to do with reducing the counter in __del__ (as the class is destroyed) when the program exits.

          Edit: If you remove the class instances yourself, then it runs correctly
          Code:
              ## add this code at the end
              ## "de-stantiate" (just kidding)
              swaroop = None
              less = None
              wanles = None
              wanless = None
              les = None
          Yes it does work now. With the added code all names work. Just thought it was funny, I spent hours looking for my mistake and it was something else.

          Comment

          • Glenton
            Recognized Expert Contributor
            • Nov 2008
            • 391

            #6
            What I find odd is that I can add instances like this:
            Code:
            p=[]
            for i in range(10):
                p.append(Person('wanles'+str(i)))
            and it works fine, but if you add this:
            Code:
            wanles11=p.append(Person('wanles11'))
            and it breaks.

            So you can have many instances and it works, provided they are packaged up in a list, but not more than 3 single instances.

            Surely the garbage collection cannot be so over-zealous that it deletes itself before it's finished with the class variables?

            I might even read the docs!

            Comment

            • woooee
              New Member
              • Mar 2008
              • 43

              #7
              Originally posted by Glenton
              What I find odd is that I can add instances like this:
              Code:
              p=[]
              for i in range(10):
                  p.append(Person('wanles'+str(i)))
              and it works fine, but if you add this:
              Code:
              wanles11=p.append(Person('wanles11'))
              and it breaks.

              So you can have many instances and it works, provided they are packaged up in a list, but not more than 3 single instances.

              Surely the garbage collection cannot be so over-zealous that it deletes itself before it's finished with the class variables?

              I might even read the docs!
              If you comment all lines that reference Person.populati on in __del__, it works also, at least as much as I have played with it.

              Comment

              • Glenton
                Recognized Expert Contributor
                • Nov 2008
                • 391

                #8
                Originally posted by woooee
                If you comment all lines that reference Person.populati on in __del__, it works also, at least as much as I have played with it.
                Oh sure @woooee, I'm pretty confident that you're right that it's a case of the Person class being garbage collected, such that the class variable isn't available. But what's weird is
                (1) that the class is gc before the instances are fully deleted, and
                (2) that it sometimes does it and sometimes doesn't.

                I just can't figure out the systematics of it. Of course __del__ is something that should be used sparingly anyway. But why?!?

                Comment

                • Mark2012
                  New Member
                  • Apr 2010
                  • 5

                  #9
                  If it is in garbage collection it is just not 3 names or more that sets it off.
                  I've tried it with Swaroop, and just one other name.
                  With the " = None " statements left out,
                  Wanless and les do not work. anless and less do work.
                  Also when I run the ones that do not work in Idle, the runtime errors are different from when I run it from the command line. So is that just a difference in the environments or part of the mystery?

                  Comment

                  • Glenton
                    Recognized Expert Contributor
                    • Nov 2008
                    • 391

                    #10
                    So it seems that garbage collection is an interesting and moody beast. It counts the number of references to a given object and when that reaches zero it does the garbage collection. Exactly how it does this is a bit beyond me, but it seems that when it finishes the number of references for all the variables goes to zero, and the garbage collection begins. The order of the garbage collection is not well-defined, so if you happen to delete Population before deleting all the objects, or Person before deleting the objects, then you're going to run into problems.

                    For this reason, errors are only raised as exceptions - that's why the code still manages to finish. There's a realisation that it doesn't really matter anymore. This is why explicitly (or implicitly) deleting the instances first makes it work.

                    Comment

                    Working...