Python классы и типы - PullRequest
       8

Python классы и типы

0 голосов
/ 03 июня 2018

Я думаю, что неправильно использую концепцию подкласса.Я работаю над хобби-проектом с сетками и клетками.

Что у меня есть, так это реализация класса Cell и его подкласса HexCell, который в основном переопределяет многие атрибуты / методы следующим образом:

class Cell: 

  def __init__(self, row_loc, col_loc):
    self.row = row_loc
    self.col = col_loc
    self.links = set()
    self.neighbors = 4*[None]

  def __repr__(self):
    return f'Cell @({self.row},{self.col})'

  def link(self, other, bidir = True):
    self.links.add(other)
    if bidir: other.links.add(self)

Тогда у меня естьподкласс, который является HexGrid, который следует за подобной структурой с новыми параметрами.

class HexCell(Cell):
  def __init__(self, r_out, th_around):
  # I'm indexing Hex cells around a center cell 
  # instead of by rows and columns; Prefixed hex
  # as they follow the hexagon, and not regular polar coordinates. 
    self.hex_r     = r_out
    self.hex_th    = th_around
    self.neighbors = 6*[None]
    self.links     = set()

  def __repr__(self):
    return f"HexCell @[{self.hex_r}, {self.hex_th}]"

  def bind(self, other, to_dir):
    to_dir = to_dir % 6
    if (self.neighbors[to_dir] is None):
      self.neighbors[to_dir] = other
      other.neighbors[to_dir - 3] = self

    # Hexagonal grids share neighbors. 
    other_1 = other.neighbors[to_dir - 2]
    if (self.neighbors[to_dir - 1] is None) & (other_1 is not None):
      self.bind(other_1, to_dir - 1)
    other_5 = other.neighbors[to_dir - 4]
    if (self.neighbors[to_dir - 5] is None) & (other_5 is not None):
      self.bind(other_5, to_dir - 5)

В этом случае метод self.link(other) является общим, но другие атрибуты изменяются с прямоугольной сетки на гексагональную, как расположение с (row, col) до (hex_r, hex_th), или neighbors как 4-список или 6-список.Таким образом, я хотел бы, чтобы эти атрибуты зависели от другого атрибута типа ячейки и передавались в подкласс.

Ответы [ 2 ]

0 голосов
/ 03 июня 2018

Ваш класс Cell на самом деле является не абстрактной «Cell», а квадратной ячейкой в ​​двумерном пространстве (имеет ровно 4 соседа, имеет позиции «row» и «col»).Такая ячейка не может быть разделена на подклассы шестнадцатеричной ячейкой, потому что шестнадцатеричная ячейка - это просто ячейка другого типа:)

Как вы заметили, единственными общими вещами являются метод link () и атрибут links.Если вы настаиваете на создании подклассов, вы можете создать что-то вроде:

class LinkedObject():
    def __init__(self):
        self.links = set()

    def link(self, other, bidir = True):
        self.links.add(other)
        if bidir: other.links.add(self)

class SquareCell(LinkedObject):
    # "Cell" class here

class HexCell(LinkedObject):
    # HexCell here
0 голосов
/ 03 июня 2018

Правильное использование подклассов должно подчиняться следующему принципу замещения:

Если есть некоторые объекты x_1 типа T_1 и x_2 типа T_2 такие, что issubclass(T_2, T_1) == True, тогда любое свойство, которое применяется к x_1, должно также применяться к x_2.

Другими словами, вы ожидаете, что подклассы будут реализовывать новые поведения, а не изменить существующее поведение.

В вашем примере изменение самой системы координат - это изменение поведения, и поэтому HexCell не должно наследоваться от Cell.

Что выможно создать базовый класс BaseCell, который инкапсулирует общее поведение между Cell и HexCell и наследует его.

class BaseCell:
    def __init__(self):
        self.links = set()
        self.neighbors = []

    def add_neighbor(self, other):
        self.neighbors.append(other)

    def link(self, other, bidirectional=True):
        self.links.add(other)
        if bidirectional:
            other.link(self, bidirectional=False)


class Cell(BaseCell):
    def __init__(self, row_loc, col_loc):
        self.row = row_loc
        self.col = col_loc
        super().__init__()

    def __repr__(self):
        return f'Cell @({self.row},{self.col})'


class HexCell(Cell):
    def __init__(self, r_out, th_around):
        self.hex_r = r_out
        self.hex_th = th_around
        super().__init__()

    def __repr__(self):
        return f"HexCell @[{self.hex_r}, {self.hex_th}]"

    def bind(self, other, to_dir):
        ...
...