|
|
|
Return to Code Snippets
by loblão » Wed Jul 11, 2012 12:01 pm
Hello! Here's a very simple tip: how to easily "destroy" a level.
A sample program that loads 2 models:
- Code: Select all
(...) self.man = loader.loadModel("models/man") self.man.setScale(2) self.man.setPos(0,0,0) self.man.reparentTo(self.render) self.dog = loader.loadModel("models/dog") self.dog.setScale(.2) self.dog.setPos(0,4,0) self.dog.reparentTo(self.render) (...) run()
Then, to remove both the dog and the man: - Code: Select all
self.man.destroy() self.dog.destroy()
In this example, we have only 2 things to remove, but it could be 30 or 40! There's nothing worse then writing 40 lines of code like that. But... There's a very simple way to avoid breaking your fingers: In the top of code, write: - Code: Select all
from panda3d.core import NodePath def ModelSet(name="set1"): return NodePath(name)
So, in the middle: - Code: Select all
#when defining main class class ABC(ShowBase): def __init__(self): (...) self.set1 = Level("set1") self.set1.reparentTo(self.render) (...) #now loading the man and the dog: self.man = loader.loadModel("models/man") self.man.setScale(2) self.man.setPos(0,0,0) self.man.reparentTo([b]self.set1[/b]) self.dog = loader.loadModel("models/dog") self.dog.setScale(.2) self.dog.setPos(0,4,0) self.dog.reparentTo([b]self.set1[/b]) #they're reparented to the level! #so, to remove them: self.set1.removeNode() #I need only 1 line to remove 2 (or 40) models at once! (PS: it might also work with actors, but I haven't tried it on yet.)
That's all! Good luck EDIT: 1. In the code, "Level" is wrong. It would be "ModelSet", sorry. 2. People are complaining that removeNode won't free memory. New code to solve it: - Code: Select all
def destroy(self): for m in self.set1.getChildren(): m.destroy() self.set1.removeNode()
Last edited by loblão on Thu Sep 27, 2012 3:32 pm, edited 1 time in total.
-
loblão
-
- Posts: 4
- Joined: Sat Jun 02, 2012 11:26 am
- Location: Brasil
-
by kurohyou » Wed Jul 11, 2012 10:08 pm
Hi! Nice tip  Just a few queries:
I assume "Level(.." is meant to be "ModelSet(" in your last code block?
Also, do we use "destroy" or "removeNode" for removing node paths?
-
kurohyou
-
- Posts: 209
- Joined: Tue Jun 29, 2010 9:59 pm
-
by rdb » Sat Jul 14, 2012 1:21 am
The dog model and man model won't be destroyed, they will still be in memory.
You need to do self.dog = None and self.man = None before they can be garbage collected.
It is probably a good idea to wrap these members of your level into a class, so that you can simply get rid of the entire class when you have no more need for the level, and all of its members will automatically go out of scope too.
-
rdb
-
- Posts: 8565
- Joined: Mon Dec 04, 2006 5:58 am
- Location: Netherlands
-
by Bradamante » Thu Jul 19, 2012 11:31 am
Hm I did not know that you have to do
- Code: Select all
x = None
to really get rid of things. In a related note: is it possible to use Python's WeakKeyDictionary (or is it WeakValueDictionary?) for that? Let's say you hold references to NodePaths in there, and doing removeNode() then would delete them without the None thing? Pseudocode: - Code: Select all
from weakref import WeakKeyDictionary # WeakValueDictionary?
model1 = loader.loadModel("path/model") model2 = ... model3 = ...
my_wkd = {"1":model1, "2":model2, "3":model3}
def delete_scene(): for model in my_wkd.itervaluerefs(): model.removeNode()
In the past I had trouble using WKD or WVD. Usually something about Python unable to assign values/keys to strings or ints.
Still I find the idea promising to use WKD/WVD to hold references to objects to start garbage collection with only one removeNode() command.
iMac (2009), Mac OS X.8.1 - MacBookPro (2007), Mac OS X.8.2
@ YouTube
-

Bradamante
-
- Posts: 303
- Joined: Tue Nov 25, 2008 10:58 am
- Location: Leipzig, Germany
by Hollower » Thu Jul 19, 2012 6:10 pm
Bradamante wrote:Hm I did not know that you have to do - Code: Select all
x = None
to really get rid of things. In a related note: is it possible to use Python's WeakKeyDictionary (or is it WeakValueDictionary?) for that? Let's say you hold references to NodePaths in there, and doing removeNode() then would delete them without the None thing? Pseudocode: - Code: Select all
from weakref import WeakKeyDictionary # WeakValueDictionary?
model1 = loader.loadModel("path/model") model2 = ... model3 = ...
my_wkd = {"1":model1, "2":model2, "3":model3}
def delete_scene(): for model in my_wkd.itervaluerefs(): model.removeNode()
No, it is when the original is deleted that the weak ref disappears, not the other way around. Perhaps this? - Code: Select all
my_wkd = WeakValueDictionary()
my_wkd["unique_name"] = render.attachNewNode( loader.loadModel("path/model") )
Now the scenegraph is holding the only true reference. Removal from the scenegraph should auto-remove the dictionary entry. - Code: Select all
my_wkd["unique_name"].removeNode()
# test assert "unique_name" not in my_wkd
I think. I can't test this out right now but that seems right. You could just as easily use a conventional dictionary, group nodes together into lists, or as members of a class, etc. As long as ALL access is done the same way (ie. though the dictionary lookup), without assigning any outside references, then it's just one extra line to remove the entry after you remove the node. You see with the above weak dictionary there is still nothing stopping you from doing... - Code: Select all
model1 = my_wkd["unique_name"]
...at which point you'd have gone back to with the original problem. model1 is a true reference and will keep the object alive even if the dictionary entry is explicitely removed. This concept is called "ownership semantics" and is an important part of encapsulation in object-oriented programming. It's about defining what part of your program "owns" the object(s) in question. The owner shouldn't let any other part of the program get it's hands on a true reference; all outside access goes through the owner and the owner handles the final destruction. Without adhering to this principle it can become very hard to keep track of where and what all of your living references are. In the past I had trouble using WKD or WVD. Usually something about Python unable to assign values/keys to strings or ints.
Dictionary keys must be immutable. I don't know if that's what you're referring to.
-
Hollower
-
- Posts: 64
- Joined: Sat Dec 11, 2010 1:18 am
by Bradamante » Sun Aug 19, 2012 8:39 am
Well, in my project I do that, using the Singleton-via-module-import technique:
- Code: Select all
# shared.py from Env import Environment
env = Environment()
# game.py import shared
shared.env.do_stuff()
How would one delete this Singleton?
In the Environment class I could go and delete all attributes by hand. Problem is that there are a lot of attributes going around as you said bundeling them in a class seems like the right idea.
rdb wrote:It is probably a good idea to wrap these members of your level into a class, so that you can simply get rid of the entire class when you have no more need for the level, and all of its members will automatically go out of scope too.
iMac (2009), Mac OS X.8.1 - MacBookPro (2007), Mac OS X.8.2
@ YouTube
-

Bradamante
-
- Posts: 303
- Joined: Tue Nov 25, 2008 10:58 am
- Location: Leipzig, Germany
by rdb » Sun Aug 19, 2012 11:02 am
What about "shared.env = None" ?
-
rdb
-
- Posts: 8565
- Joined: Mon Dec 04, 2006 5:58 am
- Location: Netherlands
-
by teedee » Sun Aug 19, 2012 2:51 pm
You can also use the del function instead of setting things to None. For example del(myvar)
-
teedee
-
- Posts: 782
- Joined: Tue May 12, 2009 11:33 pm
- Location: Kepler-22b
-
by ynjh_jo » Sun Aug 19, 2012 9:50 pm
shared.env.__dict__.clear()
del(shared.env)
-

ynjh_jo
-
- Posts: 1795
- Joined: Tue Apr 18, 2006 12:41 am
- Location: Malang, Indonesia
-
by rdb » Mon Aug 20, 2012 2:18 am
That makes no difference. Setting an instance to None is the cleanest way to reduce the reference count of a class instance and all its members. Clearing the class' dictionary explicitly won't make a difference at all.
There is no added benefit to using "del", it just makes it more confusing. (because "del" sounds like you're deleting the instance, whereas in reality you're just reducing its reference count).
-
rdb
-
- Posts: 8565
- Joined: Mon Dec 04, 2006 5:58 am
- Location: Netherlands
-
Return to Code Snippets
Who is online
Users browsing this forum: No registered users and 0 guests
| | |