Having difficulty understanding Python OOP - python

I'm fairly green to OOP and I was just playing around with it in Python and came across something I can't explain so hopefully you guys will be able to help.
I was playing with the code below:
class Car():
def __init__(self, brand, model, speed):
self.brand = brand
self.model = model
self.speed = speed
def increase_speed(self):
return self.speed + 1
def decrease_speed(self, decrease_by):
return self.speed - decrease_by
car1 = Car("tesla","x",30)
print(car1.brand)
print(car1.speed)
print(car1.increase_speed())
print(car1.speed)
print(car1.decrease_speed(10))
My question is, I am expecting after increasing the speed, car1's speed will be 31 but instead it prints out 30. Why is it that way and how should the code be written for the speed to be 31 instead?

def increase_speed(self):
self.speed += 1
return self.speed
Previously you did not increase your speed, rather you just return a value that is equal to the speed plus 1. Similarly, change your decrease_speed function.

Instead of returning the values, set them on the attributes:
class Car():
def __init__(self, brand, model, speed):
self.brand = brand
self.model = model
self.speed = speed
def increase_speed(self):
self.speed = self.speed + 1
def decrease_speed(self, decrease_by):
self.speed = self.speed - decrease_by
I deliberately don't return the changed speed anymore, as it's good style (at least with methods mainly setting attributes) to either return something or change state:
car1 = Car("tesla","x",30)
print(car1.brand)
print(car1.speed)
car1.increase_speed()
print(car1.speed)
car1.decrease_speed(10)
print(car1.speed)

The method increase_speed is just returning self.speed + 1, if you wish to update the speed you need to self.speed = self.speed + 1 into the method increase speed.

Related

Writing a test in python

Im currently taking a python class and im new in programming. I have written the code below and want to write a code that tests if the ResilientPlayer actually does what it is supposed to. The code is from a chutes and ladders board game where the ResilientPlayer is a "special" type of player that gets a "superpower" in its next move afther falling down a chute. The next round afther he has fallen down a chute, he will add a given or a default number to the die_roll, and I want to test if my code actually does this! Hope someone can help me with this problem :)
class Player:
def __init__(self, board):
self.board = board
self.position = 0
self.n_steps = 0
def move(self):
die_roll = random.randint(1, 6)
self.position = self.get_position() + die_roll
self.board.position_adjustment(self.position)
self.n_steps += 1
def get_position(self):
return self.position
def get_steps(self):
return self.n_steps
class ResilientPlayer(Player):
default_extra_steps = 1
def __init__(self, board, extra_steps=None):
super().__init__(board)
self.extra_steps = extra_steps
if self.extra_steps is None:
self.extra_steps = self.default_extra_steps
def move(self):
if self.get_position() in self.board.chutes.values():
die_roll = random.randint(1, 6)
self.position = self.get_position() + die_roll + self.extra_steps
self.board.position_adjustment(self.position)
self.n_steps += 1
else:
super().move()
def get_position(self):
return self.position
def get_steps(self):
return self.n_steps
The best way to do this is using the unittest class, I do this as following:
import unittest
from .... import ResilientPlayer
class TestResilientPlayer(unittest.TestCase):
def setUp(self):
self.resilient_player = ResilientPlayer(....)
def test_move(self):
# Do stuff
self.assertEqual(1, 1)
if __name__ == '__main__':
unittest.main()
Here, unittest.main() will run all the tests in the file. setUp is run before each test (so you can have multiple tests with the same starting conditions).
This is an incredible useful module and I strongly suggest reading more on it, check the documentation

How can the attributes of one class be accessed in another?

So what am I trying to do
Well what I'm doing is trying to create a battling system between your character and an enemy
So wheres it going wrong
Well there are two classes:
class Ally
and
class Enemy
Each class has their own unique attributes of name, health, attack and defense
class Ally
def __init__(self, name, health, attack, defense):
self.name = 'goodguy'
self.health = 100
self.attack = 50
self.defense = 30
class Enemy
def __init__(self, name, health, attack, defense):
self.name = 'badguy'
self.health = 120
self.attack = 40
self.defense = 20
But both class Ally and class Enemy need each others health and defense attributes inorder to do damage
class Ally(object):
def __init__(self, name, health, attack, defense):
self.name = goodguy
self.health = 100
self.attack = 50
self.defense = 30
def fight(self)
(damage moves)
Enemy health = Enemy.health - ((self.attack/Enemy.defense)+2)
def battle_script(self)
while self.health > 0 and Enemy.health > 0:
self.fight()
if Enemy.health <=0:
break
Enemy.fight()
if self.health <=0:
break
if Enemy.health() <= 0:
print ('The ' + Enemy.name + ' was defeated')
if self.health <= 0:
print ("You were defeated")
class Enemy(object):
def __init__(self, name, health, attack, defense):
self.name = badguy
self.health = 120
self.attack = 40
self.defense = 20
def fight(self)
(random damage moves)
Enemy health = Ally.health - ((self.attack/Ally.defense)+2)
Ally.battle_scrip()
So the problem is that I don't know how to pull in their respective attributes, i.e. in the battle script calling in the Enemy.health, I could probably pull it all into one class, but I'd rather keep them separated for when I create more enemies.
first you create instances of your class bob = Ally();evil_frank = Enemy(); ... beyond that I have no idea what you expect to happen here based on the code you are given but im guessing you want something like what follows
def fight(ally,enemy):
while ally.is_alive() and enemy.is_alive():
ally.hp -= enemy.dmg
enemy.hp -= ally.dmg
print "OK FIGHT OVER SOMEONE DIED..."
fight(bob,evil_frank)
So you want a one:many relationship for the Ally:Enemy classes? What I would do, is create a list of enemy class objects that are a member of your Ally class. You could even pass in an argument to your Ally constructor to pick the number of enemies you want.
Should be something like this:
import itertools
class Ally(object):
def __init__(self, enemies):
self.name = goodguy
self.health = 100
self.attack = 50
self.defense = 30
self.enemies = []
for _ in itertools.repeat(None, enemies):
self.enemies.append(Enemy())
...
If you want a Many:Many relationship I would create another class that can be an object for the battle. Lets call this the "Battle" class. You can then do the same trick of having a list of class objects for both your allies and enemies and then have your logic for conducting the battle in the battle class.
class Battle(object):
def __init__(self, allies, enemies):
self.allies = []
self.enemies = []
for _ in itertools.repeat(None, allies):
self.allies.append(Ally())
for _ in itertools.repeat(None, enemies):
self.enemies.append(Enemy())
...

How to use dictionary in Python correctly

Python dictionaries have always confused me.
I have 3 dictionaries:
left_dict = {"N":"W", "W":"S", "S":"E", "E":"N"}
right_dict = {"N":"E", "E":"S", "S":"W", "W":"N"}
turn_dict = {"N":"S", "E":"W", "S":"N", "W":"E"}
I have a class Robot which is initialized as such:
class Robot:
def __init__(self, team, x, y, direction):
self.team = team
self.health = 50
self.x = x
self.y = y
self.direction = direction
In this class I have a method that changes the direction.
def left90(self):
self.direction = left_dict <---- **is this how I would change the direction**
I believe what you are looking for is:
def left90(self):
self.direction = left_dict[self.direction]

Creating turn() method to change horizontal direction

I'm working on a class that includes a turn() method that's supposed to change the direction horizontally. The bug is moving left or right on a horizontal line.
Here's my code, I know it's wrong but I can't figure out how to change horizontal direction
class Bug:
def __init__(self, position):
self.__name = ''
self.__position = 0
self.__direction = 180
**def turn(self):
if(self.__direction == 180):
self.__direction = self.__direction - 180
else:
self.__direction = self.__direction + 180**
def move(self):
self.__position = self.__position + 1
def getPosition(self):
return self.__position
Would someone mind pointing me in the right direction? I know it's super simple but I hit a block and can't figure it out!
Edit: I apologize for not being more clear! The move() method is just supposed to move the bug one unit in it's current direction. I also made an edit and removed self.__direction, as there are only supposed to be 2 instance variables, not 3. So basically all I need to fix is the turn() method, making my bug change direction (left or right on the horizontal line).
I can only guess what you are trying to achieve, and I suppose that in the move method the actual direction should be taken into consideration:
#! /usr/bin/python3.2
class Bug:
def __init__(self, position):
self.__name = ''
self.__position = position
self.__direction = 1
def turn(self):
self.__direction = -self.__direction
def move(self):
self.__position = self.__position + self.__direction
def getPosition(self):
return self.__position
b = Bug (100)
for _ in range(5):
b.move()
print(b.getPosition())
b.turn()
for _ in range(5):
b.move()
print(b.getPosition())
This outputs:
101
102
103
104
105
104
103
102
101
100

Fixing class method loop

I've encountered a problem with my class file and I can't seem to find a fix around it. I was hoping someone could point me to the right direction.
Here's my code:
class Car:
def __init__(self, year_model, make, speed):
self.__year_model = year_model
self.__make = make
self.__speed = 0
def set_year_model(self, year_model):
self.__year_model = year_model
def set_make(self, make):
self.__make = make
def get_year_model(self):
return self.__year_model
def get_make(self):
return self.__make
def accelerate(self):
self.__speed + 5
return self.__speed
def decelerate(self):
self.__speed - 5
return self.__speed
def get_speed(self):
return self.__speed
Essentially, I want the speed attribute set to 0, and have 3 methods (accelerate, decelerate, and get_speed) which add and subtract 5 to the speed attribute and eventually return the speed attribute so it can be printed.
I would guess there's a problem with my formatting but I can't seem to find the correct arrangement that would fix the class.
The real program is suppose to loop the accelerate method 5 times, but the class method is supposed to handle the sequential addition and return the final speed.
import car
user_year = 1995
user_make = "toyota"
user_speed = 0
user_car = car.Car(user_year, user_make, user_speed)
for count in range(1,6):
user_car.accelerate()
print user_car.get_speed()
I know this code is very weak, but it's all makeshift to help make my problem clearer.
So hopefully it's not too confusing and I can get an answer.
self._speed + 5 computes the current speed plus 5. But you're not actually storing the computed value anywhere. You want to use self._speed = self._speed + 5, or the more commonly used form, self._speed += 5.
The problem is, of course, the "+=" and "-=" portions that are missing, but I'd go a step further and suggest that if you're writing new python code, you become familiar with new style classes. In a new style class, your code could be written as follows:
class Car(object):
def __init__(self, year_model, make, speed):
self.year_model = year_model
self.make = make
self.speed = 0
def __set_year_model(self, year_model):
self.__year_model = year_model
def __set_make(self, make):
self.__make = make
def __set_speed(self, speed):
self.__speed = speed
def __get_year_model(self):
return self.__year_model
def __get_make(self):
return self.__make
def accelerate(self):
self.speed += 5
def decelerate(self):
self.speed -= 5
def __get_speed(self):
return self.__speed
speed = property(fget=__get_speed,fset=__set_speed,fdoc="Set or Retrieve the current speed of this instance of the Car object")
make = property(fget=__get_make,fset=__set_make,fdoc="Set or Retrieve the make of this instance of the Car object")
year_model = property(fget=__get_year_model,fset=__set_year_model,fdoc="Set or Retrieve the Year and Model of this instance of the Car object")
In addition, the code changes in the main file:
import car
user_year = 1995
user_make = "toyota"
user_speed = 0
user_car = car.Car(user_year, user_make, user_speed)
for count in range(1,6):
user_car.accelerate()
print user_car.speed

Categories