[Tutor] Object and Attribute Error
Alan Thwaits
basicbare at gmail.com
Sat Mar 28 11:25:38 EDT 2020
Thank you for your reply.
I'll try out your suggestions about re-writing the loop and changing the
val = statement.
The learning journey continues...
Alan
On Fri, Mar 27, 2020 at 8:59 PM Cameron Simpson <cs at cskk.id.au> wrote:
> On 27Mar2020 17:49, Alan Thwaits <basicbare at gmail.com> wrote:
> >Another error message in my game script from Exercise 43 in Zeb Shaw's
> >"Learn Python the Hard Way."
> >
> >The first block of code which the error message references is this:
> >
> >class Engine(object):
> >
> > def __init__(self, scene_map):
> > self.scene_map = scene_map
> >
> > def play(self):
> > current_scene = self.scene_map.opening_scene()
> > last_scene = self.scene_map.next_scene('finished')
> >
> > while current_scene != last_scene:
> > next_scene_name = current_scene.enter()
> > current_scene = self.scene_map.next_scene(next_scene_name)
> >
> > #be sure to print out the last scene
> > current_scene.enter()
> [...]
> > File "C:/Users/Alan/Documents/Python/ex43.py", line 29, in play
> > next_scene_name = current_scene.enter()
> >AttributeError: 'NoneType' object has no attribute 'enter'
> [...]
>
> This indicates that current_scene.enter cannot be accessed because
> current_scene is None.
>
> The reason for this is twofold:
>
> 1: self.scene_map.next_scene(next_scene_name) can return None because it
> does a .get(), which returns None if there is no matching key. If you
> used Map.scenes[scene_name] that would not happen, though you would of
> course get a KeyError on no matching key; at least that would be closer
> to the source of your problem.
>
> 2: your while loop:
>
> while current_scene != last_scene:
> next_scene_name = current_scene.enter()
> current_scene = self.scene_map.next_scene(next_scene_name)
>
> is written on the presumption that self.scene_map.next_scene always
> returns a scene, when in fact it can return None. I would take this to
> indicate that your graph-of-scenes does not in fact flow through to the
> 'finished' scene. That can be as simple as mistyping the name of the
> next scene.
>
> I'd be inclined to write the loop like this:
>
> while current_scene != last_scene:
> next_scene_name = current_scene.enter()
> next_scene = self.scene_map.next_scene(next_scene_name)
> if next_scene is None:
> raise ValueError(
> "current_scene %s: no next scene with name %r"
> % (current_scene, next_scene_name))
> current_scene = next_scene
>
> This provides a nice exception detailing the name of the scene which was
> not found.
>
> BTW, this function:
>
> >class Map(object):
> [...]
> > scenes = {
> [...]
> > def next_scene(self, scene_name):
> > val = Map.scenes.get(scene_name)
> > return val
>
> The class is in an instances attribute search space, so you can write:
>
> val = self.scenes.get(scene_name)
>
> and avoid hardwiring the class name into the method. (This also means
> you can write a subclass with a different next_scene method easily.)
>
> Cheers,
> Cameron Simpson <cs at cskk.id.au>
>
More information about the Tutor
mailing list