A very simple problem, yet I need some assistance. I have created a class that has some default values. After that an instance takes the values based on an input. If one of the properties is "null" how can I assign the default value to it?
class Dragon:
dragons=[]
def __init__(self,dragon_type,name,health=2000,attack=450,fly_speed=120):
self.dragon_type=dragon_type
self.name=name
self.health=health
self.attack=attack
self.fly_speed=fly_speed
Dragon.dragons.append(self)
num=int(input())
for n in range(num):
entry=input().split() #fire Azzaaxx null 480 null
dragon_type,name,health,attack,fly_speed=entry[0],entry[1],entry[2],entry[3],entry[4]
if health=="null":
health=... #2000
else:
health=int(health)
if attack=="null":
attack=... #450
else:
attack=int(attack)
if fly_speed=="null":
fly_speed=... #120
else:
fly_speed=int(fly_speed)
obj=Dragon(dragon_type,name,health,attack,fly_speed)
Is this approach acceptable or this should be defined differently?
Thank you in advance!
Change the class definition so that None values are converted to the default.
class Dragon:
dragons=[]
def __init__(self,dragon_type,name,health=None,attack=None,fly_speed=None):
self.dragon_type=dragon_type
self.name=name
self.health=health if health is not None else 2000
self.attack=attack if attack is not None else 450
self.fly_speed=fly_speed if fly_speed is not None else 120
Dragon.dragons.append(self)
Then you can set the variables in the caller to None if the user enters null, and the __init__() method will do the right thing, so you don't have to repeat the default values.
Build up a dictionary of non-null values to use as keyword arguments.
args = {}
if health != "null":
args['health'] = int(health)
if attack != "null":
args['attack'] = int(attack)
if fly_speed != "null":
args['fly_speed'] = int(fly_speed)
obj = Dragon(dragon_type, name, **args)
However, this is a good opportunity to move the handling of "missing" values to a class method. __init__ should require values; the class method will provide defaults when its own input is lacking.
class Dragon:
dragons = []
def __init__(self, dragon_type, name, health: int, attack: int, fly_speed: int):
self.dragon_type = dragon_type
self.name = name
self.health = health
self.attack = attack
self.fly_speed = fly_speed
Dragon.dragons.append(self)
#classmethod
def from_input(cls):
entry = input().split()
health = int(entry[2]) if entry[2] != "null" else 2000
attack = int(entry[3]) if entry[3] != "null" else 450
speed = int(entry[4]) if entry[4] != "null" else 120
return cls(entry[0], entry[1], health, attack, speed)
num = int(input())
for n in range(num):
obj = Dragon.from_input()
Related
I am creating a python activity and I am wondering how setting the parameter of my method as a data type work
my code is:
class Food:
def __init__(self, weight: int, energy_add: int, happiness_add: int):
self.weight = weight # in kg
self.energy_add = energy_add
self.happiness_add = happiness_add
class Student:
def __init__(self, student_number: int, name: str, weight: float):
self.student_number = student_number
self.name = name
self.weight = weight # in kg
def eat(self,food = Food(int, int, int)):
self.weight = food.weight
class EEE111Student(Student):
energy_level = 50
happiness_level = 50
def eat(self,food = Food(int, int, int)):
print(self.weight)
self.weight += food.weight
print(food.weight)
print(self.weight)
if __name__ == "__main__":
num_students = int(input("Enter the number of students: "))
students = []
for idx in range(num_students):
# TODO: create new_student here
new_student = EEE111Student(student_number=idx, name=f"Student{idx}", weight=(50 + (0.5 * (idx -1))) )
students.append(new_student)
food_choises = {
"papaya" : Food(weight=0.10, energy_add=10, happiness_add=5),
"corn": Food(weight=0.20, energy_add=5, happiness_add=6),
}
students[0].eat(food = food_choises["papaya"])
students[0].eat(food = food_choises["corn"])
I am grateful that it works because i tried setting the parameter for EEE111's eat method as :
def eat(self,food = Food(Food.weight, Food.energy_add, Food.happiness_add)):
print(self.weight)
self.weight += food.weight
print(food.weight)
print(self.weight)
I am wondering if this might be a basic structure for a python code
You're never calling eat() without an parameter, so you don't need a default Food value being passed.
Instead, you can just define the type
def eat(self, food: Food)
I'm trying to implement special behavior, so that values in self and self.aux_gate are always the same. I tried doing this by implementing __setattr__(), but in doing this, I've ran in many problems regarding __dict__.
From what I could gather, it seems like whenever self.__setattr__() is called normally, it adds a key-value pair to self.__dict__, corresponding to the arguments self.__setattr__() is given.
However, the self.__setattr__() I've written seems to create extra self.__dict__ entries, I've seen self.__dict__["conditional"],self.__dict__["current_Position"], and self.__dict__["current_Track"]. I don't see how those values have made their way into self.__dict__.
Here is the class, I've copied and pasted it's superclass below
class SWAP_Gate(Quantum_Gate):
def __init__(self, cost, conditional, current_Track, current_Position, rectangle = None, aux_gate = None):
if aux_gate is None:
self.aux_gate = SWAP_Gate(cost,conditional,current_Track,current_Position, aux_gate = self)
else:
self.aux_gate = aux_gate
self.cost = cost
self.__SWAPconditional = conditional
self.__SWAPcurrent_Track = current_Track
self.__SWAPcurrent_Position = current_Position
if rectangle is None:
self.rectangle = pg.Rect(430, 0, 1480, 150)
else:
self.rectangle = rectangle
def __setattr__(self, name, value):
super(SWAP_Gate, self).__setattr__(name, value)
if name == "conditional":
self.aux_gate.conditional = value
#I've deleted some code on this line that jsut made the whole post a lot harder to read, it's not relevant to my problem
elif name == "current_Position":
self.current_Position = value
self.aux_gate.current_Position = value
elif name == "aux_gate":
self.__dict__["aux_gate"] == value
else:
self.__dict__[name] == value
def __getattr__(self, name):
if name == "conditional":
return self.__SWAPconditional
elif name == "current_Track":
return self.__SWAPcurrent_Track
elif name == "current_Position":
return self.__SWAPcurrent_Position
class Quantum_Gate():
def __init__(self, cost, conditional, current_Track, current_Position, rectangle = None):
self.cost = cost
self.conditional = conditional
self.current_Track = current_Track
self.current_Position = current_Position
if rectangle is None:
self.rectangle = pg.Rect(0, 0, 100, 100)
else:
self.rectangle = rectangle```
The main thing I see is that the first statement in your __setattr__ function is
super(SWAP_Gate, self).__setattr__(name, value)
This statement will cause the default setattr behavior to occur in addition to any other code you have in __setattr__, so seeing "current_Track" in __dict__ is expected anytime current_Track is set (unless a super class to SWAP_Gate prevents the default behavior of setattr) .
If you don't want that default behavior to occur, then remove the super() statement at the top of __setattr__ and replace the self.__dict__ statement with it in the final else statement:
def __setattr__(self, name, value):
# Removed super() statement from here
if name == "conditional":
self.aux_gate.conditional = value
elif name == "current_Track":
if self.current_Track:
#...
elif name == "aux_gate":
self.__dict__["aux_gate"] == value
else:
#replaced self.__dict__[name]=value with super() statement:
super(SWAP_Gate, self).__setattr__(name, value)
I have two classes (Student and Course). I'm trying to write a method for the Course class that will remove a given student from a course. However, there's a problem when I run
self.students.remove(student) in the method. The error tells me that student is not in the students list. Printing the students list I don't actually see the values, but instead I see a reference to it:
print(self.students)
> [<data.Student object at 0x7fc9980334f0>, <data.Student object at 0x7fc998033580>, <data.Student object at 0x7fc9980428b0>, <data.Student object at 0x7fc998042a00>]
However, if I select a specific student at an index then I'm able to see the actual data.
print(self.students[0])
> 2020411:King,Maha
Why is this happening when trying to print the students attribute?
Code if needed:
from copy import deepcopy
class Student:
def __init__(self, sid, last, first):
self.sid = sid
self.last = last
self.first = first
def __str__(self):
return '{}:{},{}'.format(self.sid, self.last, self.first)
def __repr__(self):
return '{}:{},{}'.format(self.sid, self.last, self.first)
class Course:
def __init__(self, crn, students):
self.crn = crn
self.students = deepcopy(students)
def key(self):
return self.crn
def is_empty(self):
return len(self.students) == 0
def get_student(self, student_key):
for student in self.students:
if student.key() == student_key:
return deepcopy(student)
return None
def __contains__(self, student):
for i in self.students:
if student.key() == i.key():
return True
break
return False
def register(self, student):
if student not in self:
self.students.append(deepcopy(student))
return
def drop(self, student):
s = None
if student in self:
s = deepcopy(student)
self.students.remove(student)
return s
student1 = Student(2020411, 'King', 'Maha')
student2 = Student(2019399, 'Hess', 'Alvin')
student3 = Student(2020301, 'Chin', 'Yu')
student4 = Student(2019111, 'Hay', 'Ria')
student_list = [student1, student2, student3]
course1 = Course('CP104', student_list)
removed_student = course1.drop(student2)
The issue with deepcopy() is that it creates an entirely new object that has the same attributes as the original one, yet they are not equal. For list.remove(), this compares the reference to check if the actual object exists. In your case, you are trying to remove an object that is not in the list.
Instead of removing it, if you want to return the student, use list.pop().
def drop(self, student):
for i, s in enumerate(self.students):
if s.sid == student.sid :
return self.students.pop(i)
As a side note, it will be easier to do operations if Course.students is a dictionary such that:
self.students = {
`sid1`: student1,
`sid2`: student2,
# etc
}
EDIT: Alternatively, implement __eq__() in Student so that list.remove() will work.
def __eq__(self, other):
return self.sid == other.sid and self.first == other.first and self.last == other.last
I am using eval to run a generated string to append the newly created EggOrder instance to the list of the correct instance of the DailyOrders class. The day provided by EggOrder is used to used to append to the correct instance. This relies on eval and the variable name of the DailyOrders instance and so it would be great to get this removed. I know there must be a better way.
class DailyOrders:
PRICE_PER_DOZEN = 6.5
def __init__(self, day):
self.orders = []
self.day = day
def total_eggs(self):
total_eggs = 0
for order in self.orders:
total_eggs += order.eggs
return total_eggs
def show_report(self):
if self.total_eggs() < 0:
print("No Orders")
else:
print(f"Summary:\nTotal Eggs Ordered: {self.total_eggs()}")
print(f"Average Eggs Per Customer: {self.total_eggs() / len(self.orders):.0f}\n*********")
class EggOrder():
def __init__(self, eggs=0, name="", day=""):
if not name:
self.new_order()
else:
self.name = name
self.eggs = eggs
self.day = day
eval(f"{self.day.lower()}.orders.append(self)")
def new_order(self):
self.name = string_checker("Name: ")
self.eggs = num_checker("Number of Eggs: ")
self.day = string_checker("Date: ")
def get_dozens(self):
if self.eggs % 12 != 0:
dozens = int(math.ceil(self.eggs / 12))
else:
dozens = self.eggs / 12
return dozens
def show_order(self):
print(f"{self.name} ordered {self.eggs} eggs. The price is ${self.get_dozens() * DailyOrders.PRICE_PER_DOZEN}.")
if __name__ == "__main__":
friday = DailyOrders("Friday")
friday_order = EggOrder(12, "Someone", "Friday")
friday_order.show_order()
friday.show_report()
saturday = DailyOrders("Saturday")
saturday_order = EggOrder(19, "Something", "Saturday")
saturday_order = EggOrder(27, "Alex Stiles", "Saturday")
saturday.show_report()
DailyOrders isn't actually a superclass (it was in a earlier version), it acts like one and I suspect the answer might have some inheritance.
I am a new user to python and am trying to update a class I have that is called Player(self, name, position) through a new class call API(object). In the class API(), I have the CRUD approach in creating a player, retrieving a player, updating a player, and lastly, deleting a player. I am struggling with the method in my update and delete function.
For update, I am calling self.retrieve_player[name] since it is a method that already reads the existing players from the initialized dictionary (found in the init file of class API.
Also, the main() function at the bottom is instantiating these methods by creating an instance of the object, calling API and the specified methods. e.g.:
c = API()
c.create_player('Buster Posey', 'Catcher')
c.retrieve_player('james')
c.update_player('Buster Posey', 'Firstbaseman')
The code I am struggling with is outputting an updated object that I created:
def update_player(self, name, position):
updated_player = self.retrieve_player(name)
updates = self.create_player(name, position)
updated_player = updates
return updates
print('updated now!')
def delete_player(self, name, position):
del_player = self.retrieve_player[name]
if name in del_player:
del self._team[key]
For update_player, I was playing with concept since the mentality for updating variables is something like:
a = "apple"
b = "orange"
x = a
x = b #now apple is replaced with the value orange
e.g.:
I created the player (Buster Posey, Catcher) in c.create_player. I want to update this player to reflect his new position, e.g. (Buster Posey, FirstBaseman) through the method update_player.
Afterwards, I want to delete the player altogether by using the method delete_player.
Right now, when I use the current method that is defined for update_player, I get the created_player and the updated_player... python prints:
Buster Posey, Catcher
Buster Posey, FirstBaseman
instead of ONLY printing Buster Posey, FirstBaseman.
More code:
class Player(object):
def __init__(self, name, position):
self._name = name
self._position = position
class API(object):
playercount = 0
managercount = 0
def __init__(self):
self._team = {} #acts like a db
self._index = 0
API.playercount += 1
API.managercount += 1
##This is the CRUD method for the entity Player
def create_player(self, name, position):
new_player = Player(name, position)
self._team[self._index] = new_player
self._index += 1
print(name, position)
def retrieve_player(self, name): # need to iterate through the dictionary
for person in self._team.itervalues():
if person._name == name:
return person
print(name)
elif person._name != name:
print('Sorry, this gent does not exist.')
Tweaked your code, I think this is what you were looking for.
class Player(object):
def __init__(self, name, position):
self._name = name
self._position = position
def __repr__(self):
return "%s --> %s" % (self._name, self._position)
class API(object):
playercount = 0
managercount = 0
def __init__(self):
self._team = {} #acts like a db
self._index = 0
API.playercount += 1
API.managercount += 1
##This is the CRUD method for the entity Player
def create_player(self, name, position):
new_player = Player(name, position)
self._team[self._index] = new_player
self._index += 1
print(name, position)
def retrieve_player(self, name): # need to iterate through the dictionary
for index, person in self._team.items():
if person._name == name:
print('Found this guy.. : ' + str(name))
return person
print('No team member with name : ' + str(name))
def update_player(self, name, position):
# predicting that you are trying to update position
updated_player = self.retrieve_player(name)
if updated_player:
temp_pos = updated_player._position
updated_player._position = position
print('updated %s position from %s to %s' %( name, str(temp_pos), str(position)))
return updated_player
else:
print('No team member with name : ' + str(name))
def delete_player(self, name, position):
for index, person in self._team.items():
print(index, person._name)
if person._name == name and person._position == position:
self._team[index] = None
del person
print('Deleted team member : ' + str(name))
return 1
print('No team member with name : ' + str(name))
team = API()
team.create_player('A', 'Catcher')
team.create_player('B', 'FirstBatsman')
print(team._team)
player = team.retrieve_player('A')
print(player._name)
team.delete_player('B', 'FirstBatsman')
print(team._team)
Thanks to gsb-eng for helping me clarify the process. My issue was in attempting to change the name when I meant change the position, which requires calling the retrieve_player, I needed to iterate through the dictionary, than implementing a new position variable and value for the formerly created player.
This made it easier to clarify the delete_player method, which needed to iterate through the dictionary again and use the built-in function del.
Lastly, I forgot to use str() when printing variables.
CODE:
def update_player(self, name, position): # call retrieve () player than update
#update position of player since name doesn't change
updated_player = self.retrieve_player(name)
if updated_player:
temp_pos = updated_player._position
updated_player._position = position
print('Updated %s position from %s to %s' %( name, str(temp_pos), str(position)))
return updated_player
else:
print('No team member with name : ' + str(name))
def delete_player(self, name, position):
for index, person in self._team.items():
print(index, person._name)
if person._name == name and person._position == position:
self._team[index] = None
del person
print('Deleted team member : ' + str(name))
return 1
print('No team member with name : ' + str(name))