0
\$\begingroup\$

Hello everyone!

Here is the thing. So I wanted at first to create Robot class, I want him to move around some board. Maybe 10x10 or something like that, then i wanted to invent a Robot fights class, I want to add class players (becuase i want to play between player 1 and player 2) but here it is what I have so much.

Lets focus on this code because I want it to make it much better then start to create robot fights!

class Robot:

    def __init__(self, name, place, start = (0,0), power = 9):
        self.name = name
        self.start = start
        self.place = place
        self.power = power
        
    def get_name(self):
        return self.name
        
    def get_start(self):
        return self.start
        
    def get_place(self):
        return self.place
        
    def get_power(self):
        return self.power
        

    
    def set_name(self, x):
        if isinstance(x, str):
            self.name = x
        else:
            raise TypeError("must be a string")
    
    def set_start(self, x):
        if isinstance(x, tuple):
            self.start = x
        else:
            raise TypeError("must be a tuple")
    
    def set_place(self, x):
        if isinstance(x, list):
            self.place = x
        else:
            raise TypeError("must be a list")
    
    def set_power(self, x):
        if isinstance(x, int):
            self.power = x
        else:
            raise TypeError("must a int")
    
    
    
    def check_power(self):
        if self.power <= 0:
            raise ValueError("No power")
            
          
    def left(self, value):
        self.check_power()
        
        self.power -= value

        if self.place[0] - value < 0:
            self.place[0] = self.place[0] - value + 8

        else:
            self.place[0] = self.place[0] - value
            
    def up(self, value):
        self.check_power()
        
        self.power -= value

        if self.place[1] + value > 7:
            self.place[1] = self.place[1] + value - 8

        else:
            self.place[1] = self.place[1] + value

        if self.place[1] == 5:
            self.power += 2

    def __str__(self):
        return self.name, self.place, self.power

Also want I want to make better in this one. Well power will be important in the Robot fights, because if some robot from player 1 will be near to robot from player 2 I want them to you know, fight, so the power will be pretty good right there, if they will be near to each other the power will decrease until the robot is destroyed. But lets focus on above code to make it better.

Any tips how to make this SHORTER and more neat, closer to a advanced or just better solution will be definitely on point.

Have a great day!

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Type annotations

Using type annotations will make your program a lot more readable and easier to debug. For example:

def __init__(self, name, place, start = (0,0), power = 9):
    # assignments

becomes

def __init__(self, name: str, place : List[int], start: Tuple[int, int] = (0,0), power: int = 9):
    # assignments

I imported List, Tuple from the typing module from the standard library:

from typing import List, Tuple

Here's some further information on using type annotations.


Getter and Setter

Using getters and setters is rather unpythonic. You can instead modify the getting and setting behaviours by using the @property decorator like this:

def __init__(self, name: str, place : List[int], start: Tuple[int, int] = (0,0), power: int = 9):
    self._name = name

    # further assignments

@property
def name(self):
    return self._name

@name.setter
def name(self, value):
    if isinstance(value, str):
        self._name = value
    else:
        raise TypeError("must be a string")

This will allow you to use the properties without explicitly calling getter and setter methods:

my_robot.name = 'foo'
print(my_robot.name)

This question on StackOverflow contains some more detailed explanations.


Logic

  1. You should also take a look at your setters for place and start. You only check the type of the passed argument value, but do not verify if the elements in the list or tuple are of type int.
  2. You could consider using a custom class Position or similiar for handling the positional logic of the robot. That way you can access the different dimensions by their names instead of indices of place (self.place[0] or self.place[1]). You'll also be able to put further logic (like clipping, etc.) into it.
  3. power and check_power(): Depending on your intended functionality you might want to limit the number of steps that can be taken by a robot to the power that it has left. As it is now, a robot can take any number of steps as long as it has power > 0 left.
  4. You should check the functionality left(value) and up(value) for big values, especially values that are > 2 * board_dimension. I suspect the results might be unintended.
\$\endgroup\$
3
  • \$\begingroup\$ Overall agreed. I would take your "unpythonic accessor functions" further - if there is any kind of non-trivial logic to the get or set, @property is called for, but here it isn't. Just make a "public" variable. \$\endgroup\$
    – Reinderien
    May 12, 2021 at 15:15
  • \$\begingroup\$ Genuine question: How do you then verify / ensure that only values of a certain type are assigned to public attributes, if at all? \$\endgroup\$ May 12, 2021 at 15:31
  • 3
    \$\begingroup\$ The short answer is that you don't. Type verification - typically - is not done at all, since Python uses duck typing. Recent support for static analysis of types is helpful but doesn't apply in runtime. If you do want to apply validation to a value before set, then you would do it as you've shown with @properties or - if you're able to make the class immutable, which has a lot of advantages - then during __init__. \$\endgroup\$
    – Reinderien
    May 12, 2021 at 15:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.