I'm not really sure what the problem is you are describing, but maybe you will solve it yourself if I explain a litte bit what the code above does.
Basically, Python syntax is just a nice way to call all those special methods. Writing char.health = 100
is equivalent to char.__setattr__("health", 100)
Likewise, writing current_health = char.health
is equivalent to current_health = char.__getattr__("health")
So, keeping that in mind, look at the constructor (__init__ method) of sGirl. I'm sure, somewhere you define an attribute, eg. self.name = "unnamed"
which Python will translate to
self.__setattr__("name", "unnamed")
This call to __setattr__ will execute the line if name in self.stats:
which Python will translate to if name in self.__getattr__("stats")
Now __getattr__ is called, which also tries to access the stats attribute in the line if name in self.stats:
, triggering yet another call to __getattr__, which also tries to access the stats attribute, triggering yet another call to __getattr__, ...
et voilĂ , infinite recursion.
If however the first line of the constructor defines the stats attribute by accessing the internal dictionary of the instance, self.__dict__, subsequent attribute access via self.stats will work. This works because self.__dict__ is NOT translated to self.__getattr__("__dict__"), but instead just returns the internal dictionary of the instance, which contains its namespace.