0

I have been working on a large Python pygame project, and in it I have realized the convenience of calculated properties. I have hit a snag, though; I have a 2 player game where I have a card_group that is shared between the 2 players (it's an online multithreaded game). Whenever I update the card_group, I currently have it as a calculated instance attribute which does x, y, z whenever it is updated. I need that card_group to instead be a CLASS ATTRIBUTE that is shared between the 2 players so that from both players/clients (each on their own connection) they can send/receive/update 1 CLASS ATTRIBUTE instead of 2 P1/P2 INSTANCE ATTRIBUTES. Since the game is very complex and the code has grown quite large (a few thousand lines) I prefer not to have 2 variables when I can simply use 1. It seems more logical to do it this way.

However, I cannot succeed in turning a CLASS ATTRIBUTE into a CALCULATED ATTRIBUTE. I thought it would be Pythonic and simple, but I can't figure out how to do it.

Note: I don't really want to use a method; unless absolutely necessary, I would rather it remain a property/attribute.

I played around with a mock-up version of the code in a test file, but the best I can get it to do is return a property object.

  1. Can I get the value from this property object?

  2. Is it possible to use the @property decorator or the property() method to make a CLASS ATTRIBUTE work just like a CALCULATED INSTANCE ATTRIBUTE?

  3. Is there another way to make a calculated class attribute?

  class Game:

    _card_group = 0

    @property
    def card_group(self):
        return self._card_group

    @card_group.setter
    def card_group(self, val):
        print('Setter')
        self._card_group = val

Game.card_group = 3

print(Game.card_group)

In the example above, when Game.card_group = 3 is executed, it does not call the card_group.setter as I expected, and whenever I print(Game.card_group), it prints out a property object.

Thanks in advance!

  • The design here doesn't make a lot of sense; it's hard to infer, from the description, what the intended purpose of the classes is, and it seems like you're making implicit assumptions like "there is only ever one game being played, and every player is participating in that game, even though I made a class to represent games". That said, the linked duplicate should answer your question. – Karl Knechtel Mar 20 '23 at 20:42
  • You should probably create an *instance* of `Group`, rather than using the class itself as a singleton instance of `type`. – chepner Mar 20 '23 at 20:42
  • @KarlKnechtel It's very simple. There is a class called Game. Each player has a game class instance: P1_game & P2_game. Each one contains data for each player/client that is specific to them. But in rare cases, such as the card_group, this is not specific to each class instance, but is rather universally handled between the two. Therefore to avoid possibilities for errors, I would like to use 1 variable instead of 2; thus using a class attribute instead of an instance attribute. My problem was that I wanted the class attribute to do x, y, z when it was changed, like a calculated property. – Joshua Merrifield Mar 20 '23 at 21:55
  • @KarlKnechtel Yeah, there's only one game being played, with two players/clients. The Game class contains all of the pertinent game data, with 90% of that being specific to each player/client, and the other 10% is shared data (such as the card_group). Thanks for the duplicate I will check it out! I ended up just nixing the calculated property attempt and just did the automated x,y,z somewhere else and converted it to a simple class attribute instead of the instance attribute. – Joshua Merrifield Mar 20 '23 at 21:58
  • @chepner Yes I created 2 instances of the Game class, P1_game and P2_game, but I was trying to avoid updating/handling the card_group data in those terms, but in a safer, less error-prone manner via the 1 Game class attribute. – Joshua Merrifield Mar 20 '23 at 21:59
  • @KarlKnechtel The duplicate you listed does indeed offer a solid solution to the questions I asked! Thanks a lot! You can make class attributes function as calculated properties just like you do with class instance attributes. – Joshua Merrifield Mar 20 '23 at 22:03
  • 1
    "There is a class called Game. Each player has a game class instance: P1_game & P2_game. Each one contains data for each player/client that is specific to them." What **is** a "Game"? What does it represent? If two players are *playing in the same game*, why would they not "have" *the same `Game` instance*? – Karl Knechtel Mar 20 '23 at 22:05
  • "The Game class contains all of the pertinent game data, with 90% of that being specific to each player/client, and the other 10% is shared data (such as the card_group)." Why wouldn't the player-specific data be in the Player instances? – Karl Knechtel Mar 20 '23 at 22:13
  • @KarlKnechtel 1) It's easier to manage 1 set of attrs and 2 class instances than 2 sets of attrs and 1 class instance. I have 100+ attrs for the Game class as it is, so creating a P1 & P2 version of each attr would imply creating/managing another 100+ attrs. All of that code is error-prone. It is safer to do it this way. Its faster & easier to access the attrs as well. 2) Originally, the game was single player, so I had 1 Game class instance. When refactoring to online multiplayer, modifying the class w/ 2x attrs when everything was in place (mostly) for 1 instance seemed unsafe and silly. – Joshua Merrifield Mar 21 '23 at 13:38
  • @KarlKnechtel The player specific data relative to their cards, their name, their score, etc. is stored in player.py & managed/accessed via a Player class: there are 2 instances of that class, P1 & P2. When I said 'player/client' I was speaking about how each player/client had an associated Game class instance which stores the player/client specific Game data, much of which is unserializeable (pygame objects) such as the current display_text, pygame rects, etc. There are en toto ~300 attributes throughout the ~10 game files. They are all organized in a very specific manner for safety. – Joshua Merrifield Mar 21 '23 at 13:46

0 Answers0