0

I have an issue with this mini game that i made which i am trying to add to a server.

I am trying to print a function from an instance of a Character but i'm not sure how to pass the proper function in. This is what i have:

class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
  Class Character():
    name = ""
    age = 0

  Class Human(Character):
    locationX = 0
    locationY = 0
    def help(self):
      self.request.send("Q to Quit")

  class Boy(Character, Human):
    def __init__(self, name):
      self.name = name
      age = 10

  def handle(self):
    p1 = self.Boy("Jim")

    self.request.send(":")
    command = self.request.recv(1024).strip()
    if command == "help":
      p1.help()

My error is:

    File "/usr/lib/python2.7/SocketServer.py", line 649, in __init__
      self.handle()
    File "rpg.py", line 281, in handle
      p1.help()
    File "rpg.py", line 23, in help
      self.request.send("Q to Quit")
    AttributeError: Boy instance has no attribute 'request'

Can someone explain why this is wrong?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
12vi6
  • 50
  • 8

1 Answers1

0

You've chosen to have your classes Character &c embedded within class ThreadedTCPRequestHandler -- but embedded is very different from derived from. The embedded classes have no special access to the self of the class in which they're embedded!

So you need to enrich e.g Character with an __init__ that takes the handler instance creating it:

  class Character():
      def __init__(self, handler):
          self.name = ""
          self.age = 0
          self.handler = handler

(I've also taken the opportunity to make name and age instance variables, which makes more sense, and change indents to standard 4 characters vs the 2 you used:-).

Subclasses must then call the base class's __init__ appropriately:

  class Boy(Character, Human):
      def __init__(self, name, handler):
          Character.__init__(self, handler)
          self.name = name
          self.age = 10

and the creation of new instances must also go along:

  def handle(self):
      p1 = self.Boy("Jim", handler=self)
      # etc etc

(the handler= part here is just for clarity and readability, not strictly needed for functionality:-).

The overall architecture is now peculiar (embedded classes are rarely used in Python) but at least it will work!-)

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • Wow, thank you! That makes more sense. 1 more question, if embedded classes are rarely used, how would one go about creating the same thing but without it embedded? Would i have to have everything outside ThreadedHandler? Just asking for future reference. – 12vi6 Mar 07 '15 at 02:44
  • 1
    You'd move all the now-embedded `class` statements outside of the `class ThreadedHandler` statement and lose the `self.` in `p1 = self.Boy("Jim", self)`. Having the classes "outside" makes it far easier to write unit tests for your code -- and copious unit tests are more than a "best practice", they're the **only** practice you should *ever* consider!-) – Alex Martelli Mar 07 '15 at 02:49