0

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

ihsancemil
  • 432
  • 5
  • 16
  • Possible duplicate of [How would I access variables from one class to another?](http://stackoverflow.com/questions/19993795/how-would-i-access-variables-from-one-class-to-another) – user2925795 Jun 27 '16 at 11:47
  • The simple solution is to have a common base class that provides those two attributes and have `first` as a subclass that adds a new attribute. Basically make `second` a parent class of `first` and move the `sum_class` method to `second`. Without a more concrete example it's not clear whether this solution makes sense or not. – Bakuriu Jun 27 '16 at 11:52
  • @user2925795 I actualy looking for like kind of classA.__dict__ + classB.__dict__ it is different then you send. It just sums some attributes I want to add all – ihsancemil Jun 27 '16 at 11:54
  • @Bakuriu I'm building rpg kind of game and this will be my player class and item class so I will add them more then one times – ihsancemil Jun 27 '16 at 11:55
  • There are no class attributes here, but only instance attributes. Unless you give an example on how you want to use that, this question is *unclear*. – Serge Ballesta Jun 27 '16 at 11:57
  • @ihsancemil Okay, so you have a `Player` class that contains all possible attributes (like strength, hp, armor etc.) and the other classes are things like items that provide *some* of the attributes (e.g. helmet: +5 armor, +3 hp, sword: +5 attack etc.) And you want to update the attributes of the player using these items? – Bakuriu Jun 27 '16 at 12:05

2 Answers2

1

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
        try:
            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.

Bakuriu
  • 98,325
  • 22
  • 197
  • 231
-1

you can make it shorter by using:

def sum_class(self, cls):
    [setattr(self, attr, getattr(cls, attr) + getattr(self, attr)) for attr in cls.__dict__]

Edit 1:

It was unclear what you wanted, but after you sad in comments you want something like classA.__dict__ + classB.__dict_, maybe you can use this:

class sum_class:
    def __init__(self, class_1, class_2):
        self.sum = class_1.__class__()
        self.class_2 = class_2
        for attr in self.class_2.__dict__:
            if attr in self.sum.__dict__:
                setattr(self.sum, attr, getattr(self.class_2, attr) + getattr(self.sum, attr))
            else:
                setattr(self.sum, attr, getattr(self.class_2, attr))

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 __add__(self, cls):
        return sum_class(self, cls).sum

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

    def __add__(self, cls):
        return sum_class(self, cls).sum

when classes are defined like that then you can use it like this:

>>> f = first()
>>> s = second()
>>> x = f + s
>>> x.value_one
5
>>> x.value_two
6
>>> x.value_third
7
ands
  • 1,926
  • 16
  • 27