title: Passing class instance reference to functions called in class definition in Python
body: <p>I'm trying to make a basic card game, and in order to keep track of whose turn it is, I decided on making a game class, each instance of which is a separate game.  Then when the game instance is initialised, it would also initialise the player objects and deck and card objects, and tie them to that game object.  To do this I tried to pass the game object 'self' to the functions that initialise the other objects, so that they could refer back to the game object.</p>
  
  <p>This has not worked.  <strong>Edit: error is NameError: global name 'game' is not defined</strong></p>
  
  <p>Is the idea completely impossible/immoral/the-worst-thing-ever, or is it a perfectly viable way of achieving my aims, but I'm just implementing it incorrectly?</p>
  
  <p>The whole code is at the end, but a cut-down version that hopefully will illustrate the scenario---or at least enough of it to answer the core question---in a less complicated way follows:</p>
  
  <pre><code>from collections import deque
  from random import shuffle
  
  DECK = {"value_range": (1, 6),
      "black_multiple": 2,
      "red_multiple": 2,
      "dead": 12}
  
  class Game:
      """A game instance."""
      def __init__(self, deck=DECK):
          self.deck = Deck(self, **deck)
          self.deck.shuffle()   
  
  class Deck:
      def __init__(self, game, value_range, black_multiple, red_multiple, dead):
          self.deck = deque()
          for value in range(*value_range):
              for i in range(black_multiple):
                  self.deck.append(Card(game, value, "Black"))
              for i in range(red_multiple):
                  self.deck.append(Card(game, value, "Red"))
          for i in range(dead):
              self.deck.append(Card(game))
      def shuffle(self):
          shuffle(self.deck)
      def draw(self):
          return self.deck.popleft()
  </code></pre>
  
  <p>And here is the whole (unfinished) code, for if that's not enough information:</p>
  
  <pre><code>from collections import deque
  from random import shuffle
  
  DECK = {"value_range": (1, 6),
          "black_multiple": 2,
          "red_multiple": 2,
          "dead": 12}
  
  class Game:
      """A game instance."""
      def __init__(self, player_names=["Simon", "Will"], start_cards=2,
                   deck=DECK):
          self.deck = Deck(self, **deck)
          self.deck.shuffle()
          self.players = deque()
          for name in player_names:
              self.players.append(Player(self, name))
          for player in self.players:
              player.draw(start_cards)
      def lose(self, player):
  #        print(player.name + "loses.")
          pass
      def new_turn(self):
          self.players.rotate(-1)
      def get_active(self):
          return self.players[0]
      def get_passive(self):
          return list(self.players)[1:]
  
  class Card:
      """A card instance.
  
      Black cards get an extra method! Dead cards have value and colour False."""
      def __init__(self, game, value=False, colour=False):
          self.value = value
          self.colour = colour
          def get_value(self):
              return self.value
          def get_colour(self):
              return self.colour
          if self.colour == "Black":
              def action(self, target):
                  active = game.get_active()
                  responders = game.get_passive()
                  for responder in responders:
                      if responder.respond(self.value) == False:
                          continue
                      else:
                          if target == active:
                              target = responder
                          else:
                              target = active
                          break
                  target.draw(self.value)
  
  class Player:
      def __init__(self, game, name):
          self.name = name
          self.hand = {}
      def draw(self, value):
          for i in range(value):
              try:
                  draw_card = game.deck.draw()
              except IndexError:
                  game.lose(self)
                  break
              else:
                  self.hand.append(draw_card)
                  continue
      def get_hand(self):
          return self.hand
  
  class Deck:
      def __init__(self, game, value_range, black_multiple, red_multiple, dead):
          self.deck = deque()
          for value in range(*value_range):
              for i in range(black_multiple):
                  self.deck.append(Card(game, value, "Black"))
              for i in range(red_multiple):
                  self.deck.append(Card(game, value, "Red"))
          for i in range(dead):
              self.deck.append(Card(game))
      def shuffle(self):
          shuffle(self.deck)
      def draw(self):
          return self.deck.popleft()
  </code></pre>
  
  <p>Thanks for taking the time to read this!  I've not done much formal coding training/practice before, so I'm trying to muddle my way through learning Python by trial-and-error/PyDocs.</p>