.kill() is not sufficient to remove it from memory in your case because you're keeping it in spellSprites. In your else clause, you also need to remove it from spellSprites. Keep in mind that you're iterating over this list at that point, so you can't directly remove it from the list until execution is outside the loop. An easy (and inefficient) way to do clean up would be to do this after your loop:
self.spellSprites = [spell for spell in self.spellSprites if spell.alive]
This is creating a new list every frame. It also assumes there's a property on your sprite indicating its living/dead status. If there isn't one, you can just set it yourself after calling .kill(). This also assumes that you haven't created any references to this object's spellSprites instance somewhere else. If that's the case, then you'd end up with some very strange results. Hint: It's probably a design flaw if you're keeping references to spellSprites anywhere else besides in the object itself anyway. I'd refactor to no longer keep references to members outside of the object instance that owns those members.
I do see that under a circumstance that you are emptying that list. If you're still holding references to sprites and you know they've been removed from spellSprites and theSpell has fallen out of scope, you may have created a circular reference somewhere. Python uses reference counting to keep track of when to remove items from memory. As a test, perform a garbage collection (gc.collect()) after your loop and see if that sprite is still in memory. If running the garbage collection makes the difference then you probably have created a circular reference to the sprite somewhere. Python's garbage collector is smart enough to find and collect circular references, but it only runs periodically.