我是面向对象编程(和Python)的新手。为什么下面的代码是一个糟糕的对象设计?有什么好的设计不会导致这里的循环导入? 我希望这些类能够进行通信,但是在第二个内部使用第一个,反之亦然会导致 NameError: name 'Board' is not Defined。 或者这是 python 的问题并且使用不同的导入会有所帮助?
import numpy as np
class Coordinates:
def __init__(self, col: int, row: int):
self.__col = col
self.__row = row
def get_col(self):
return self.__col
def get_row(self):
return self.__row
def c_on_board(self, board: Board):
existing = board.get_all_existing()
return [self.__col, self.__row] in existing
class Board:
def __init__(self, mat: np.matrix):
self.__mat = mat
def get_value(self, c: Coordinates):
return self.__mat[c.get_col()][c.get_row()]
def get_all_existing(self):
A = np.array(self.__mat)
existing = np.argwhere(A != np.nan)
return existing
我尝试为这两个类创建单独的 .py 文件,并使用
from classes.board import Board
等导入它们,但问题仍然存在,只是这次它引发 ImportError:无法从部分初始化的模块 'classes.Board 导入名称 'Board' '(很可能是由于循环导入)
您看到的问题是您已将
Coordinates
类与 Board
类紧密耦合。 在编程中,我们希望避免耦合,因为对一个类的更改必须考虑到与其耦合的所有其他类。
当每个类独立于其他类时,管理代码(尤其是大型代码库)会容易得多。 让我们问一个问题“为什么坐标需要了解 Board”? 事实并非如此! 坐标仅包含行和列。 这就是它需要做的全部。
相反,我们可以将坐标是否有效的检查移至 Board 类。 如果坐标无效,您将引发错误以让用户知道发生了什么。
import numpy as np
class Coordinates:
def __init__(self, col: int, row: int):
self._col = col
self._row = row
def get_col(self):
return self._col
def get_row(self):
return self._row
class Board:
def __init__(self, mat: np.matrix):
self._mat = mat
def get_value(self, c: Coordinates):
if not self._coord_is_in_board(c):
raise ValueError('Coordinate is not within the Board boundaries')
return self._mat[c.get_col()][c.get_row()]
def get_all_existing(self):
return np.argwhere(self._mat != np.nan)
def _coord_is_in_board(self, c: Coordinates) -> False:
n_rows, n_cols = self._mat.shape
row_valid = (0 <= c.get_row() < n_rows)
col_valid = (0 <= c.get_col() < n_cols)
return row_valid and col_valid