self
приведет к тому, что переменная будет отнесена к экземпляру класса, а не к самому классу. Я не знаю, имели ли вы это в виду или нет, но об этом, безусловно, стоит подумать.
Переменные в области видимости класса можно разделить на две категории: переменные класса и экземпляра. Переменные класса определяются в начале определения класса, вне любого метода. Если переменная постоянна для всех экземпляров или используется только в методах класса/статических, она должна быть переменной класса. Часто такие переменные являются настоящими константами, хотя во многих случаях это не так. Переменные экземпляра обычно определяются в __init__
, но во многих случаях их следует определять в другом месте. При этом, если у вас нет веской причины не делать этого, определите переменные экземпляра в __init__
, так как это сохранит ваш код (и класс) организованным. Вполне допустимо давать им значения-заполнители (например, None
), если вы знаете, что переменная важна для состояния экземпляра, но ее значение не определено до тех пор, пока не будет вызван определенный метод.
Вот хороший пример:
class BaseGame:
"""Base class for all game classes."""
_ORIGINAL_BOARD = {(0,0): 1, (2,0): 1, (4,0): 1, (6,0): 1, (8,0): 1,
(1,2): 1, (3,2): 1, (5,2): 1, (7,2): 1, (2,4): 1,
(4,4): 1, (6,4): 1, (3,6): 1, (5,6): 1, (4,8): 0}
_POSSIBLE_MOVES = {(0,0): ((4,0),(2,4)),
(2,0): ((4,0),(2,4)),
(4,0): ((-4,0),(4,0),(2,4),(-2,4)),
(6,0): ((-4,0),(-2,4)),
(8,0): ((-4,0),(-2,4)),
(1,2): ((4,0),(2,4)),
(3,2): ((4,0),(2,4)),
(5,2): ((-4,0),(-2,4)),
(7,2): ((-4,0),(-2,4)),
(2,4): ((4,0),(2,4),(-2,-4),(2,-4)),
(4,4): ((-2,-4,),(2,-4)),
(6,4): ((-4,0),(-2,4),(-2,-4),(2,-4)),
(3,6): ((-2,-4),(2,-4)),
(5,6): ((-2,-4),(2,-4)),
(4,8): ((-2,-4),(2,-4))}
started = False
def __call__(self):
"""Call self as function."""
self.started = True
self.board = __class__._ORIGINAL_BOARD.copy()
self.peg_count = 14
self.moves = []
@staticmethod
def _endpoint(peg, move):
"""Finds the endpoint of a move vector."""
endpoint = tuple(map(add, peg, move))
return endpoint
@staticmethod
def _midpoint(peg, move):
"""Finds the midpoint of a move vector."""
move = tuple(i//2 for i in move)
midpoint = tuple(map(add, peg, move))
return midpoint
def _is_legal(self, peg, move):
"""Determines if a move is legal or not."""
endpoint = self._endpoint(peg, move)
midpoint = self._midpoint(peg, move)
try:
if not self.board[midpoint] or self.board[endpoint]:
return False
else:
return True
except KeyError:
return False
def find_legal_moves(self):
"""Finds all moves that are currently legal.
Returns a dictionary whose keys are the locations of holes with
pegs in them and whose values are movement vectors that the pegs
can legally move along.
"""
pegs = [peg for peg in self.board if self.board[peg]]
legal_moves = {}
for peg in pegs:
peg_moves = []
for move in __class__._POSSIBLE_MOVES[peg]:
if self._is_legal(peg, move):
peg_moves.append(move)
if len(peg_moves):
legal_moves[peg] = peg_moves
return legal_moves
def move(self, peg, move):
"""Makes a move."""
self.board[peg] = 0
self.board[self._midpoint(peg, move)] = 0
self.board[self._endpoint(peg, move)] = 1
self.peg_count -= 1
self.moves.append((peg, move))
def undo(self):
"""Undoes a move."""
peg, move = self.moves.pop()
self.board[peg] = 1
self.board[self._midpoint(peg, move)] = 1
self.board[self._endpoint(peg, move)] = 0
self.peg_count += 1
def restart(self):
"""Restarts the game."""
self.board = __class__._ORIGINAL_BOARD.copy()
self.peg_count = 14
self.moves.clear()
_ORIGINAL_BOARD
и _POSSIBLE_MOVES
— настоящие константы. Хотя started
не является константой, поскольку ее значение зависит от того, был ли вызван метод __call__
или нет, его значение по умолчанию, False
, является постоянным для всех экземпляров, поэтому я объявил его как переменную класса. Обратите внимание, что в __call__
(не беспокойтесь о том, почему я использовал __call__
вместо __init__
) я переопределил его как переменную экземпляра, так как __call__
запускает игру, и поэтому при его вызове состояние экземпляра изменился с класса по умолчанию «не запущен» на «запущен».
Также обратите внимание, что другие методы, помимо __call__
, регулярно изменяют значение переменных экземпляра, но они изначально не определены в указанных методах, поскольку для этого нет веских причин.
person
Isaac Saffold
schedule
23.06.2017
self.train
, потому что действительно не ссылаюсь на эти переменные вне метода. Я должен быть в состоянии сократить код, чтобы теперь он имел больше смысла. - person James   schedule 23.06.2017