Yeah, there’s plenty of room for philosophical discussion about the proper balance of global vs. local objects.
I agree that Panda–actually, ShowBase, a very small subset of Panda, but one that everyone has to use–egregiously pollutes the Python builtin dictionary, and rather poorly overuses globals in general. I’d really like to fix this one day.
But that’s part of a different discussion. As to whether the Task Manager should be global or local, it’s a little more subtle.
There are tradeoffs between local and global objects. On the one hand, keeping objects local means limiting the size of the system that modifies these objects, and in turn limiting the breadth of knowledge you have to have in order to fully understand the system. A very good thing. On the other hand, making certain objects global makes communication between different parts of the system easier.
In any application framework, there are some structures which really are better suited to be globals. For instance, the memory heap management is usually (though not always) best handled as a single global heap, instead of lots of little individual heaps for each section of the code. The biggest reason for this is technical: the computer hardware presents a single continuous range of memory addresses to the process, and having lots of little heaps that grow and shrink independently would require constantly juggling memory addresses, or special OS-level support to virtualize the memory addresses within user space.
I think the scene graph is also best expressed as a global, because there is after all one scene that is ultimately rendered. (That’s not to say that I think “render” should be a Python builtin, because I don’t. But that’s a different question.) You could have each part of your code operate on its own little segment of the scene graph, and then try to integrate them all together later, but you’d run into problems when they try to create objects that interact with each other.
Similarly, there are sometimes tasks from different systems that must interact with each other, or that at least must be precisely ordered with respect to each other. For instance, the collision traversal normally has to be performed immediately before the igloop task. But sometimes you need to add a new task between the two, or a specialty task immediately before collisions, or immediately after igloop, or wherever.
To the extent that all of your tasks really are isolated and independent, you can effectively manage each of them on their own TaskManager. But in a complex system, tasks don’t often remain isolated and independent.
But, yeah, this really is a philosophical matter; and if you feel you’d be better off with several local TaskManagers instead of a global one, by all means go for it.
Note that as of Panda 1.6.x, the TaskManager is actually implemented in C++, and thus has a fairly lightweight runtime overhead.