2011-01-27 4 views
4

У меня есть следующий код:Python: лучший способ вызова методов из другого класса?

class Player: 
    def __init__(self, username, trip, model): 
     self.username = username 
     self.trip = trip 
     self.hp = 100 


    #### For player moving location/room #### 
    def Move(self, dest): 
     if dest == self.loc: 
      return True 

     # Check destination room is accessible from current room 
     for room in aGame['rooms']: 
      if room['ref'] == self.loc: 
       for acsroom in room['acs']: 
        if acsroom == dest: 
         self.loc = dest 
         return True 
     return False 

агама является массивом, который определен вне этого класса так что этот код не работает. Поскольку, вероятно, будет много других функций этого класса, которые, возможно, используют агаме массив, я должен сделать это:

class Player: 
    def __init__(self, username, trip, model, aGame): 
     self.username = username 
     self.trip = trip 
     self.hp = 100 
     self.aGame = aGame    

    #### For player moving location/room #### 
    def Move(self, dest): 
     if dest == self.loc: 
      return True 

     # Check destination room is accessible from current room 
     for room in self.aGame['rooms']: 
      if room['ref'] == self.loc: 
       for acsroom in room['acs']: 
        if acsroom == dest: 
         self.loc = dest 
         return True 
     return False 

Или было бы лучше сделать это:

class Player: 
    def __init__(self, username, trip, model): 
     self.username = username 
     self.trip = trip 
     self.hp = 100   

    #### For player moving location/room #### 
    def Move(self, dest, aGame): 
     if dest == self.loc: 
      return True 

     # Check destination room is accessible from current room 
     for room in aGame['rooms']: 
      if room['ref'] == self.loc: 
       for acsroom in room['acs']: 
        if acsroom == dest: 
         self.loc = dest 
         return True 
     return False 

Или должен ли я сделать aGame глобальной переменной (если да, то как, обратите внимание, что этот класс находится в другом файле)?

Поскольку aGame - это массив, который используется повсеместно, не представляется правильным делать копии его внутри каждого класса. Возможно, я ошибаюсь, я медленно изучаю ООП, поэтому спасибо за любую помощь.

+3

Вы фактически не копируете * словарь 'aGame' в каждый класс - аргументы передаются« по ссылке ». – miku

ответ

3

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

Решающей особенностью является то, что вы захотите использовать один и тот же экземпляр Player для более чем одного значения aGame. Если будет только одно значение, то я либо передал бы его конструктору (ваш вариант 2), либо использовал идею gnibbler о том, чтобы сделать его переменной класса. Я бы предпочел передать его конструктору для удобства тестирования.

Если вы хотите, чтобы один и тот же экземпляр Player использовался с несколькими значениями aGame, тогда вариант 3, вероятно, является самым чистым способом достижения этого.

+0

Спасибо :) Будет несколько экземпляров Player, но одна версия aGame. aGame - это dict с значениями, загруженными из файла, поэтому необходимость повторного загрузки этих значений из файла будет неэффективной. Думаю, мне придется использовать опцию 2 для установки aGame в класс с self. и надеюсь, что мне не придется обновлять aGame dict по какой-либо причине позже в приложении. – Tommo

+0

@Tommo, если вы передаете один и тот же экземпляр ко всем экземплярам, ​​любые изменения, которые вы ему сделаете, будут видны из каждого экземпляра. Python не копирует словарь, он просто создает новую ссылку на него. Кроме того, если вы читаете файл, вам может понадобиться использовать идею Уолтера Мундта с помощью метода класса для заполнения массива. – aaronasterling

0

Только первый выбор будет работать. Во втором примере for room in self.aGame['rooms'] приведет к ошибке, потому что нигде нет привязки к себе. Он будет работать, если он был for room in aGame['rooms'], но тогда вам придется излишне передавать aGame каждый раз, когда вы вызываете move().

Вы также можете сделать его глобальной переменной, но лучше всего, чтобы каждый игрок держал экземпляр aGame. Если вам нужно изменить aGame и иметь несколько игроков, вы должны определить его как глобальную переменную.

Кроме того, просто nitpicking, но aGame не является массивом, это словарь. Язык Python даже не имеет массивов (хотя некоторые расширения имеют).

+0

Извините, я забыл удалить «я». потому что во втором примере в метод была передана переменная aGame. – Tommo

+0

Если я добавил aGame в класс Player, разве это не просто копирование текущей aGame и ее применение к экземпляру Player? Итак, если aGame изменяется после инициализации класса, то player1.aGame будет другим? – Tommo

+0

@Tommo, ладно, ну тогда мой ответ все еще стоит. Зачем передавать 'aGame' каждый раз, когда вы вызываете' move() ', когда каждый' Player' может просто иметь экземпляр? Первое решение имеет больше смысла и требует меньше работы с вашей стороны. Если вам нужно изменить aGame и иметь несколько игроков, вы должны определить его как глобальную переменную. –

0

aGame одинаково для каждого экземпляра? Тогда вы можете сделать это атрибут класса либо как этот

class Player: 
    aGame={'rooms':...} 
    ... 

или

Class Player: 
    ... 

Player.aGame={'rooms':...} 

В классе, вы можете получить доступ к нему через self.aGame

0

Я хотел бы использовать небольшое изменение на a в глобальном масштабе:

# in game.py or whatever 
class Game(object): 
    instance = {} # this is your aGame array 

# in player.py or whatever: 
from game import Game 

class Player(object): 
    # ... 
    def Move(self, dest): 
     # ... 
     for room in Game.instance['rooms']: 
      # ... 

В качестве альтернативы, вы можете сделать игру надлежащей класса, назначьте Game.instance = Game (...) где-то во время фазы инициализации и получите больше реального синглтон-паттерна.

+0

В чем преимущество этой свертки? – aaronasterling

+0

Ну, я предполагаю, что глобальное должно остаться в отдельном модуле. В этом случае он удаляет зависимость, которую глобальное значение имеет во время импорта. Без класса контейнера игровому модулю придется выполнять «из игры import aGame». Если, скажем, код инициализации должен был присваиваться глобальному «aGame» после загрузки модуля плеера, значение aGame модуля игрока больше не было бы правильным. В этой версии это не проблема. Во-вторых, это делает переход на то, чтобы класс игры для игрового государства был более очевидным, и я думаю, что это, вероятно, хорошо. –

Смежные вопросы