1

Here's my problem: I want 2 single objects to reference and update one another's attributes.

So, I tried doing this (I'm building chess):

 # white.py
 class White(object):
 ...
      def move_white_piece(self):
           from black import Black
           black_object = Black()
           # ...

The reason I'm importing inside the function is that without doing it, a circular dependency occurs (i.e White does not know about Black yet since White was declared first). This fixes the AttributeError (the class is now defined). However, this brings up a new issue where now I'm using a new object (therefore not current attributes) inside the function every time. I need to use a single object throughout my entire program. Is this possible?

I have never had this problem in C++ because of forward declarations and prototypes.

Wick_
  • 33
  • 2
  • 5
  • As a side note: `Black` is the name of a class. You then instantiate an instance of that class and assign it to a variable named `Black`, thus redefining what `Black` means. That will be the last object of class `Black` you will be creating as a result. Do you get my point? Class names are usually upper case and variable names usually begin with lower case. Had you followed that convention you would have avoided *that* problem. – Booboo Apr 26 '20 at 19:26
  • Yep, changed to address the confusion. – Wick_ Apr 26 '20 at 19:31
  • See my answer; I only create one black piece for the entire program run. – Booboo Apr 26 '20 at 19:56

1 Answers1

1

I am not so sure it's always bad to have two objects that reference one another. Be that as it may, what I find unusual is that you are creating an instance to the black piece in a method called move_white_piece. Surely this is method that is to be called repeatedly. Do you plan on creating a new black piece every time white has to make a move? That makes little sense to me. What makes more sense is the following:

from black import Black

class White:

    def __init__(self):
        self.black_piece = Black() # create black piece when we are created
        black_piece.set_white_piece(self) # give black piece a reference to ourself

    def move_white_piece(self):
        # whatever

and then class Black:

class Black:

     def set_white_piece(self, white_piece):
         self.white_piece = white_piece

An alternate style:

class White:

    def __init__(self):
        self.black_piece = Black(self) # create black piece when we are created

    def move_white_piece(self):
        pass

class Black:
    def __init__(self, white_piece):
        self.white_piece = white_piece

It's a matter of taste and/or requirements.

But hold on, because there is more:

Unless you have a very special reason for doing so, there shouldn't be a separate class Black and White if the rules and strategies for both colored pieces are exactly the same, for example as in a standard game of chess. Of course, one color has to make the first move and from that point on the pieces alternate moves. But as long as you are implementing a game for which the rules and strategies for black and white are the same, black and white should just be two instances of the same class.

Booboo
  • 38,656
  • 3
  • 37
  • 60
  • Just added clarification for why i'm importing inside function. Other answers have said that this is the way to deal with mutual imports i.e https://stackoverflow.com/questions/1250103/attributeerror-module-object-has-no-attribute – Wick_ Apr 26 '20 at 20:06
  • My issue is not where you are importing; it's with your *creating* a new piece for every move: `black_object = Black()`. And there is no reason why that import cannot be moved to the top of the file, is there? – Booboo Apr 26 '20 at 20:37
  • The problem is that these are only 2 classes in the overall program. My main folder of code contains a `common.py` file which contains all my imports and class declarations. So, at the top of `white.py` and all my other classes, I would have the line `from common import *`. So, as you can imagine, a circular import occurs since I am importing and declaring the Black class first in `common.py`. To fix this, I simply import inside my function again so the class becomes defined, but the multiple object problem then becomes a problem. – Wick_ Apr 26 '20 at 20:56
  • No, I can't imagine. Class `White` needs to see a definition of Black before it can execute `self.black_piece = Black()`. But class `Black ` does not need to see any definition of `White` to be able to compile what I have shown in my answer. Python is *not* C++. – Booboo Apr 26 '20 at 22:08
  • Thanks so much for this answer, I will be trying this and see if it works. Just as a quick thing: in the alternate style, did you mean to put the parenthesis in `class Black()`:? Or did you mean `class Black:` ? – Wick_ Apr 27 '20 at 00:05
  • No, I meant `class Black:`. – Booboo Apr 27 '20 at 00:18