[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