ihsancemil ihsancemil - 3 months ago 7x
Python Question

sum two different class attributes

Lets say I have 2 class and I want to add the second classes attributes to first class I can make like that:

class first:
def __init__(self):
self.value_one = 2
self.value_two = 5
self.value_third = 7 #second class don't have that attribute

def sum_class(self, cls):
for attribute in cls.__dict__:
x = getattr(cls, attribute)
y = getattr(self, attribute)
setattr(self, attribute, x+y)

class second:
def __init__(self):
self.value_one = 3
self.value_two = 1

But it doesn't look pythonic is there any better way to do it?

My Classes will have more than 10 attributes so I don't want to add one by one that could be easy but massy code like:

def sum(self, cls):
self.value_one += cls.value_one
self.value_two += cls.value_two

Also my third class may have:

class ClassB:
def __init__(self):
self.value_one = 2
self.value_third = 3

I also want to able to add this class into my first class


The only class that have a behvaiour similar to what you are looking for is the Counter class:

>>> c = Counter()
>>> c['a'] = 1.0
>>> c + Counter('a')
Counter({'a': 2.0})

So you could store these "attributes" inside a Counter and use __getattr__ to use normal attribute access:

from collections import Counter

class ClassWithCounter:
    def __init__(self, **kwargs):
        self.counter = Counter(kwargs)

    def __getattr__(self, attr):
        # this allows to use the syntax: first().value_one
            return self.counter[attr]
        except KeyError:
            raise AttributeError(attr)

class first(ClasswithCounter):
    def __init__(self):
        super(first, self).__init__(value_one=2, value_two=5, value_third=7)

    def sum_class(self, cls):
        self.counter += cls.counter

class second(ClassWithCounter):
    def __init__(self):
        super(second, self).__init__(value_one=3, value_two=1)

Note however that the purpose of Counter is just to count things, so there may be some situations where it gives you strange results.

If that is the case you can simply implement your own dictionary-like class and use it in place of Counter.

Also a suggestion: given that you are writing this for a game, you should consider whether this kind of update is good or not. Because in this way the original "base values" for the player gets lost.

I personally would keep the "base values" separate and keep track of the "modifiers" to such values (e.g. bonuses or maluses provided by items, or temporary effects). This apporach allows you to implement things like "the damage of this spell isn't affected by bonus armor" (so you just use the base value when computing the damage). Your current approach makes this more cumbersome.