【问题标题】:Yet another "X object has no attribute Y" error又一个“X 对象没有属性 Y”错误
【发布时间】:2014-11-27 22:30:41
【问题描述】:

我通过“Learn Python the Hard Way”学习 Python 已经三周了——因为我对编程并不陌生,所以通过本书的前半部分,我能够快速进步,直到我开始使用类和对象进入 OOP 部分。现在我遇到了很多麻烦;虽然我认为我已经理解了这些对象概念背后的想法,但我的代码显然有一些隐晦的错误(我使用的是 Python 2.7.6,它似乎是 kubuntu 14.04 中 gcc 4.8.2 的一部分,保持最新)。

我正在做练习 43,尝试从作者的骨架类定义开始创建一个冒险游戏。我在第一个游戏设计中做得很好(使用 Python,就像我多年前使用 Basic 完成相同任务的方式一样),但我已经花了大约 10 个控制台小时试图解决 OOP 游戏中的最新错误;我已经阅读了几十个搜索过的解决方案(这里和其他地方),但没有找到任何确切适用的内容。我已经尽可能地减少了代码,但我仍然看到同样的错误(我将在代码之后粘贴——警告,这仍然是将近 100 行):

# Python the Hard Way -- Exercise 43: Basic Object-Oriented Analysis and Design

# received as skeleton code, try to make it into a playable game
# my comment: Much harder than designing from scratch!  Author's
# design method (or that appropriate for OOP) differs greatly from
# what I'm used to.

from sys import exit

class UserEntry (object):

  def __init__(self):
    pass

  def get_input (self):

    # initialize variable for trimmed command list
    short_list = []

    # accept input, break at spaces, and reverse for parsing
    command = raw_input ('> ')
    command_list = command.split (' ')
    command_list.reverse ()

    # parse command here
    for i in reversed (xrange (len(command_list))):
      if ((command_list [i] in a_game.act.keys()) or 
          (command_list [i] in a_game.obj.keys())):
        short_list.append (command_list.pop())
      else:
        command_list.pop()
    # return parsed_command
    if len(short_list) == 1 and short_list[0] in a_game.act.keys():
      short_list.append (' ')
    return short_list

class Scene (object):

  def enter(self):
    pass

class Engine (object):

  def __init__(self, scene_map):
    self.scene_map = scene_map
    self.act = {
      'inventory'   :self.inventory,
      'look'        :self.look,
        }

    self.obj = {
      'blaster' :'',
      'corridor':'',
      'gothon'  :'',
      }

  def inventory(self):
    pass

  def look (self):
    pass
  def opening_scene(self):
    # introduce the "plot"
    print "Game intro",

  def play(self):

    entry = UserEntry()
    self.opening_scene()
    a_map.this_scene.enter()

class CentralCorridor(Scene):

  def enter(self):
    print "Central Corridor"

class Map(object):

  def __init__(self, start_scene):
    scenes = {
    'central corridor': CentralCorridor,
      }

    this_scene = scenes[start_scene]()
    print this_scene

a_map = Map('central corridor')
a_game = Engine(a_map)
a_game.play()

当我尝试运行它时,我得到以下信息:

$ python ex43bug.py
<__main__.CentralCorridor object at 0x7f13383c8c10>
Game intro
Traceback (most recent call last):
  File "ex43bug.py", line 89, in <module>
    a_game.play()
  File "ex43bug.py", line 70, in play
    a_map.this_scene.enter()
AttributeError: 'Map' object has no attribute 'this_scene'

很明显,有些东西阻止了this_scene 对其他类/方法可见;我只是不明白它是什么。我没有缩进问题(我可以看到),我没有循环导入(事实上,我只导入了一个模块,用于 exit 命令)。第一个打印行由print this_scene 在实例a_map 内生成;我应该得到Game intro,然后是Central corridor,首先是Engine.opening_scene,然后是CentralCorridor.enter,但我从来没有得到后者,尽管显然成功地实例化了CentralCorridor

我很困惑。为什么a_map.this_scene 除了在Map.__init__ 内之外的任何地方都可见?

【问题讨论】:

    标签: python class oop methods instantiation


    【解决方案1】:

    this_scene 只是Map.__init__ 中的本地名称:

    def __init__(self, start_scene):
        scenes = {
            'central corridor': CentralCorridor,
        }
    
        this_scene = scenes[start_scene]()
        print this_scene
    

    您需要将其分配给self 上的属性:

    def __init__(self, start_scene):
        scenes = {
            'central corridor': CentralCorridor,
        }
    
        self.this_scene = scenes[start_scene]()
    

    【讨论】:

    • 我已经尝试了所有合理的变化来使this_scene 更加全球化,只导致不同的错误。做出改变会给$ python ex43bug.py Traceback (most recent call last): File "ex43bug.py", line 87, in &lt;module&gt; a_map = Map('central corridor') File "ex43bug.py", line 85, in __init__ print this_scene NameError: global name 'this_scene' is not defined -- 'doh!一旦我更正了以下打印语句以匹配表格,这似乎有效。让我在完整的程序中试一试。
    • 删除打印行或使用print self.this_scene
    • 是的,这似乎已经纠正了这个错误。让我回到完整的程序,看看是否能让我在需要它的类 Engine 中使用 a_map.this_scene
    • 是的,这似乎使该方法在应有的地方可用。我发誓我至少尝试过两次,但我一定同时有其他问题。
    • 后期跟进 - 舔了它但很好。我已经能够使用来自EngineMap 实例以及Scene 派生类实例的属性,在其他类实例中可以互换,一旦我找到了重新连接@987654333 的方法@ 到预先存在的实例而不是重新实例化(通过每次我创建 Scene 实例时将实例标签放入列表中),这主要是填补空白的问题。我应该在几天内完成这个(我在工作日只有一两个小时的时间来处理它)。
    猜你喜欢
    • 2012-07-19
    • 1970-01-01
    • 1970-01-01
    • 2017-02-24
    • 1970-01-01
    • 2018-05-21
    • 2014-05-14
    • 2016-04-07
    • 1970-01-01
    相关资源
    最近更新 更多