Python 类 和类型
Python classes and types
我想我误用了 subclass 的概念。我正在使用 Grids and Cells 开展一个业余爱好项目。
我所拥有的是 Cell
class 及其子 class HexCell
的实现,它基本上重新定义了许多 attributes/methods所以:
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)
然后我有一个 subclass,即 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 列表。因此,我希望这些属性依赖于另一个单元格类型属性并向下传输到 subclass。
subclassing的正确使用需要遵守以下替换原则:
If there are some objects x_1
of type T_1
and x_2
of type T_2
such that issubclass(T_2, T_1) == True
, then any property that applies to x_1
must also apply for x_2
.
换句话说,您希望 subclassing 实施新行为,而不是改变现有行为。
在你的例子中,坐标系的改变本身就是行为的改变,因此HexCell
不应该继承自Cell
。
你可以做的是创建一个基础 class 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):
...
你的单元格class其实不是抽象的"Cell",而是二维space中的方形单元格(恰好有4个邻居,有"row"和"col" 位置)。这样的单元格不能被十六进制单元格子class,因为十六进制单元格只是一种不同类型的单元格:)
如您所见,唯一常见的是 link() 方法和 links 属性。如果你坚持使用 subclassing,你可以创建如下内容:
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
我想我误用了 subclass 的概念。我正在使用 Grids and Cells 开展一个业余爱好项目。
我所拥有的是 Cell
class 及其子 class HexCell
的实现,它基本上重新定义了许多 attributes/methods所以:
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)
然后我有一个 subclass,即 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 列表。因此,我希望这些属性依赖于另一个单元格类型属性并向下传输到 subclass。
subclassing的正确使用需要遵守以下替换原则:
If there are some objects
x_1
of typeT_1
andx_2
of typeT_2
such thatissubclass(T_2, T_1) == True
, then any property that applies tox_1
must also apply forx_2
.
换句话说,您希望 subclassing 实施新行为,而不是改变现有行为。
在你的例子中,坐标系的改变本身就是行为的改变,因此HexCell
不应该继承自Cell
。
你可以做的是创建一个基础 class 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):
...
你的单元格class其实不是抽象的"Cell",而是二维space中的方形单元格(恰好有4个邻居,有"row"和"col" 位置)。这样的单元格不能被十六进制单元格子class,因为十六进制单元格只是一种不同类型的单元格:)
如您所见,唯一常见的是 link() 方法和 links 属性。如果你坚持使用 subclassing,你可以创建如下内容:
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