This is an archived version of the course. Please find the latest version of the course on the main webpage.

Chapter 7: Add robot actions!

Refactoring my robot actions

face Josiah Wang

So how did I refactor my functions into robot methods?

The following gives an idea of how I went about doing this. You should just use this as a guide, rather than a definitive solution!

Obvious cases

I started with an easy candidate - the print_robot_greeting() function. It needs the robot’s id and name, so it makes sense to have it as a method. Having robot in the function name is also another giveaway! I renamed the method to greet(), which is shorter and more intuitive. So, instead of someone having to print a robot’s greeting on its behalf, the robot can now do its own greeting! I also had to rename any function calls into method calls, i.e. print_robot_greeting() to robot.greet().

Some functions become mutator methods

Another example I had was step_forward(). My function previously returned a robot object, but now I can turn it into a mutator method that modifies the robot’s position directly, so this method now does not need to return anything.

More example methods

Here are some other methods I came up with, based on my existing functions:

  • robot.turn_right()
  • robot.move_forward_to_wall()
  • robot.is_facing_wall()
  • robot.is_at_target()
  • robot.navigate()

Give methods a name that makes sense!

I also had many functions like print_start_message() and print_step_forward_message(). I renamed them as robot.report_start() and robot.report_step() to make them sound more intuitive.

It is not my responsibility!

I have functions like generate_robot_id(), generate_robot_name() and generate_random_position(). I think it is best NOT to turn these into methods of a Robot instance. Just think - if you were a Robot object, would you give yourself a name and an id? It is probably someone else who will do that. This is just too much burden on the Robot class, especially when it is not its responsibility. So I left these as functions for now. We will continue refactoring in the next lesson with a better solution (spoiler: we can have a RobotInitialiser class to do this for the Robot!)

Utility functions

You might also have some independent, ‘utility’ functions that might not be obvious methods for robots, but is still worth having as part of the Robot class. For example, I have a function generate_direction_string() that converts "n" to "North" etc. It stands on its own, and does not even need to access the robot’s attributes. But some of my robot methods rely on this function.

There are various ways around this problem. For now, I turned this into a ‘hidden’ method, by prefixing it with an underscore, i.e. _generate_direction_string(). This is a convention to indicate that this is not a ‘public’ method accessed by anyone. It is only meant to be used ‘internally’ by the class.

A better design would probably be to create another class called DirectionMapper that handles this task, and your Robot class can use this to generate the string. We’ll leave this for the next lesson though! Just focus on the Robot class for now!

Summary

Hopefully this helps you understand my own thought process. The good tip is to keep your Robot methods simple, i.e. each method should do just one specific thing!

Try completing your refactoring process. If you like, you can look at my own implementation to get some inspiration.

Once you are done, have another look at your code in the main.py file. Does it start to feel even easier to read and understand? Hopefully the answer is yes!