|
Re: Please explain what I've done wrong.: msg#00164python.pygame
[ I'm pretty sure this is off topic for this list, but the response you've had might risk you writing code that's even harder for you to see what's happening ] On Saturday 17 September 2005 20:00, Jason wrote: > I've looked through the code but can't find anything obvious. It's because there isn't a problem with your code, per se, it's more to do with python shutdown. If you put your code, including the test cases, inside a script and run it, the following happens: * The class is created * The instances are created * We hit the end of the script, so python starts to shutdown * The class and instances are __del__eted at shutdown, *in no particular order* * BANG! If deletion is "forced" to happen in the following order - instances, followed by class - by adding the following at the end of your code: Jason = None # invalidate Jason, allow to be deleted Sophie = None # invalidate Sophie, allow to be deleted import time t = time.time() while time.time() - t < 1: pass Then the code works as you expect. The problem you're seeing is the deletion appears to happen in the following order - at least on my machine mirroring your error: * Jason deleted * class deleted * Sophie deleted - BANG! (due to trying to reference something that is no longer really valid) Clearly this means that by the time Sophie is deleted "Person" no longer really exists, and hence can't really be used for anything. (Actually I suspect the actual nitty-gritties under the hood are a little more complex, but the above APPEARS to be resulting behaviour. I'd have to look inside the python code to know for certain) If you change your tests to something slightly more idiomatic, such as: def main(): Jason=Person("Jason") Jason.sayHi() Jason.howMany() Sophie=Person("Sophie") Sophie.sayHi() Sophie.howMany() if __name__ == "__main__": main() Then you find you get the right behaviour. The reason is because the locals in main() are no longer valid the instant the function call exits. I'd advise BTW against trying to access & update a class variable via the alternate suggestion of self.population since you're likely to run into all sorts of bizarre issues that way. A better alternative to self.population is to do self.__class__.population - which would update the class that self belongs to. For example if I modify your example to also have a Frank, who is an employee: class Frank(Person): population = 0 And change all occurances of Person.population to self.__class__.population and all occurances of the string "Person" with self.__class__.__name__, then you get the following behaviour: (Initialising Jason) Hi, my name is Jason I am on the only Person here. (Initialising Sophie) Hi, my name is Sophie We have 2 Persons here. (Initialising Jason) Hi, my name is Frank I am on the only Employee here. Sophie says bye. There are still 1 people left. Jason says bye. I am the last Person Jason says bye. I am the last Employee When the following test harness runs: def main(): Jason=Person("Jason") Jason.sayHi() Jason.howMany() Sophie=Person("Sophie") Sophie.sayHi() Sophie.howMany() Frank=Employee("Frank") Frank.sayHi() Frank.howMany() (Full version of this one included at end) Person.population would hardcode the class to specifically only update the Person population, which is a valid design decision. self.__class__.population means that you're keeping track of how many of each kind of thing exists (number of employees for example vs other people). Again, another equally valid design decision. (Though in the example below this would imply that Employees aren't people, which isn't an idea I'd like employers to take on :-) self.population can mean different things depending on whether you're reading or writing the value, which is not an ideal scenario :-) (If you change all occurances of self.__class__.population below to self.population, you'll see what I mean...) I suppose the bottom line here (if the rest of this email has gone over your head) is that your code was fine, BUT you may want to try running it differently :) If you really want to see why self.population is a bad idea, take the example below and use: class Employee(Person): pass Instead of : class Employee(Person): population = 0 Which again gives you another behaviour (due to, again, how values for names are searched for and updated). Finally, I suspect the best place for this question is actually the python-tutor list - http://mail.python.org/mailman/listinfo/tutor Best Regards, Michael. ----- #!/usr/bin/python class Person: population=0 def __init__(self,name): self.name=name print '(Initialising %s)' % self.name self.__class__.population += 1 def __del__(self): print "%s says bye." % self.name self.__class__.population -= 1 if self.__class__.population == 0: print "I am the last ",self.__class__.__name__ else: print "There are still %d people left." % self.__class__.population def sayHi(self): '''Greeting by the person. That's all it does.''' print "Hi, my name is %s" % self.name def howMany(self): if self.__class__.population==1: print "I am on the only", self.__class__.__name__, " here." else: print ("We have %d "+self.__class__.__name__+"s here.") % self.__class__.population class Employee(Person): population = 0 def main(): Jason=Person("Jason") Jason.sayHi() Jason.howMany() Sophie=Person("Sophie") Sophie.sayHi() Sophie.howMany() Frank=Employee("Frank") Frank.sayHi() Frank.howMany() if __name__ == "__main__": main() |
|
| <Prev in Thread] | Current Thread | [Next in Thread> |
|---|---|---|
| Previous by Date: | Re: Double Buffered display vs Overlays: 00164, Michael Sparks |
|---|---|
| Next by Date: | Re: optimising render code: 00164, altern |
| Previous by Thread: | Please explain what I've done wrong.i: 00164, Jason |
| Next by Thread: | Re: Please explain what I've done wrong.: 00164, Christopher Arndt |
| Indexes: | [Date] [Thread] [Top] [All Lists] |
| News | FAQ | advertise |