Does this look like a good way to use a class? - python

I have a class, and a Python script that calls functions from the class.
The class is called User_Input_Test. The script is called input_test.py.
input_test.py will request input from the user by using one of the class functions/methods: get_user_input(self). It is then supposed to print out whatever the user entered, through the use of the second function/method called show_output(self).
It generates an error:
User_Input_Test.show_output()\
File "/Users/michel/Python_Projects/User_Input_Test.py", line 49, in show_output\
""")
AttributeError: type object 'User_Input_Test' has no attribute 'brand'
It looks like show_output(self) is not able to see the data pulled in from the user via get_user_input(self).
Would you say that is the correct interpretation of the error? And most importantly: Is there a solution for this, or am I trying to use a class for something it was never designed for?
user_input.py:
from User_Input_Test import User_Input_Test
import time
#User_Input_Test.__init__(self, name, brand, engine, doors, fuel_type, aircon, weight, mpg, tax)
print("This little application collects data about your car")
print("Please fill out the following questionnaire:")
uname = input("What is your first name?:")
User_Input_Test.get_user_input()
print(f"{uname}, these are your car's attributes: ")
time.sleep(2)
User_Input_Test.show_output()
User_Input_Test.py
class User_Input_Test:
"""
Small Class that asks the user for their car attributes and can print them out
Attributes:
brand(string)
engine(string)
....
"""
def __init__(self, brand, engine, doors, fuel_type, aircon, weight, mpg, tax):
self.brand = brand
self.engine = engine
self.doors = doors
self.fuel_type = fuel_type
self.aircon = aircon
self.weight = weight
self.mpg = mpg
self.tax = tax
#classmethod
def get_user_input(self):
while 1:
try:
brand = input("What is the Brand & Model of your car? (e.g. 'Mercedes Benz, E-Class'): ")
engine = input("Engine Cylinders and Displacement (e.g. '4 Cylinders, 2.1 Liters'): ")
doors = input("How many doors does it have?: ")
fuel_type = input("What fuel does it use? (e.g. Petrol, Diesel, LPG): ")
aircon = input("Does it have Airconditioning? (Yes/No): ")
weight = input("How much does it weight in KG? (e.g. 1800kg): ")
mpg = input("What is the fuel consumption in Imperial MPG? (e.g. 38mpg): ")
tax = input("How much does the UK Roadtax cost per year? (e.g. £20): ")
return self(brand,engine,doors,fuel_type,aircon,weight,mpg,tax)
except:
print('Invalid input!')
continue
def show_output(self):
print(f"""
==========================================================================
Brand Name:....................... {self.brand}
Engine:........................... {self.engine}
Number of Doors:.................. {self.doors}
Fuel Type used by the engine:..... {self.fuel_type}
Does it have Aircon?:............. {self.aircon}
Fuel consumption in Imperial MPG:. {self.mpg}
Cost of Road Tax per Year:........ {self.tax}
==========================================================================
""")

User_Input_Test.show_output() tries to call show_output on the class itself; you need to call it on the instance returned by User_Input_Test.get_user_input().
from User_Input_Test import User_Input_Test
import time
print("This little application collects data about your car")
print("Please fill out the following questionnaire:")
uname = input("What is your first name?:")
car = User_Input_Test.get_user_input()
print(f"{uname}, these are your car's attributes: ")
time.sleep(2)
car.show_output()
Note: check out PEP 8, the Python style guide, notably the naming conventions for modules and classes. In this case, I would name the module car and the class Car for more clarity and better style. Also, the argument to a classmethod is usually named cls, as self is conventionally reserved for the instance in normal methods.

Related

How to make the use user input to create an instance of a class?

I'm making a text-based adventure game in python and would like the user to choose a race and create an instance of a race class based on their choice. For example, if the player chose a Lizardman race from this code:
def character_creation():
print("You have four choices, choose wisely")
races = ['Lizard', 'Bookshelf', 'Genie', 'Werepus']
while True:
for i, j in enumerate(races):
print(f"[{i + 1}]", j)
choice = int(input('Pick a race:'))
if choice <= len(races):
print('You are a ', races[choice])
return races[choice]
else:
continue
How would I get my code to make a race object?
character = Race('Lizardman', 'Regrowth', 20)
Each race is created by Race(Name, Passive, HP) and each race has its own passive and hp associated with it. As in, I don't want to ask the user for the passive and the HP, just the race name.
You can use classmethod here.
class Race:
def __init__(name: str, passive: str, hp: int):
self.name = name
self.passive = passive
self.hp = hp
#classmethod
def from_race_name(cls, name):
race_attributes = {'Lizardman':{'passive': 'Regrowth',
'hp': 20,
.....}
return cls(name,
race_attributes[name]['passive'],
race_attributes[name]['hp'])
This will create an instance of the class based on only name of the race. To use it call it with the class name:
liz = Race.from_race_name('Lizardman')
This will create an instance of lizardman which will automatically be assigned 'regrowth' passive and 20 hp.
Also, if you want to create a 'unique' lizardman you can still do it manually:
admiral_akbar = Race(name='Lizardman', passive='panic', hp=999)
If you want the user to only choose the race name and have everything else on default you can set the default values in the class parameters.
Here's an example:
class Race():
def __init__(self, Name: str, Passive: str = "Regrowth", HP: int = 20): # Set default values here
self.Name = Name
self.Passive = Passive
self.HP = HP
def Main():
race_name = input("Pick a race: ")
character = Race(race_name)
print(character.Name, character.Passive, character.HP)
if __name__ == "__main__":
Main()
Output if user enters 'Lizardman':
Lizardman Regrowth 20
You can still overwrite and change the the Passive and the HP as so:
character = Race(Name = race_name, Passive = "Something", HP = 100)

How do I make a class instance using user input?

I am making a text based adventure game in python. Once the game begins, I would like to create an instance of a class called "Character" which is the player's character object. I would like the user to be able to choose the race of the character they want to play. So far I have:
class Race:
def __init__(self, name, passive, hp):
self.name = name
self.passive = passive
self.hp = hp
and
class Lizard(Race):
def __init__(self, name, passive, hp):
super().__init__(name, passive, hp)
self.name = 'Lizardman'
self.passive = 'Regrowth'
self.hp = 20
def regrowth(self):
if 0 < self.hp <= 18:
self.hp += 2
and
def race_select():
races = ['Lizard']
while True:
for i, j in enumerate(races):
print(f"[{i + 1}]", j)
choice = int(input('Pick a race:'))
if choice <= len(races):
print('You are a ', races[choice - 1])
return races[choice - 1]
else:
continue
If I understand correctly, if I wanted the race to be a Lizard, I would still have to do
character = Lizard('Lizardman', 'Regrowth', 20)
Is there an easy way to let the user choose the race and the object to be created accordingly? Thanks
A simple solution would be to map a name to a class using a dictionary. As a simple example:
race_map = {"lizard": Lizard,
"human": Human} # I'm adding a theoretical other class as an example
choice = input('Pick a race:')
race_initializer = race_map.get(choice, None) # Get the chosen class, or None if input is bad
if race_initializer is None:
# They entered bad input that doesn't correspond to a race
else:
new_creature = race_initializer(their_name, their_passive, their_hp)
new_creature is now the new object of the chosen class.
You may want to standardize the input using choice.lower() to ensure that capitalization doesn't matter when they enter their choice.
I changed it to allow for specifying a race by a string name instead of a number. If you wanted a number, you could keep your list, but apply the same idea. Something like:
race_list = races = [('Lizard', Lizard), ('human', Human)]
choice = int(input('Pick a race:'))
try:
race_initializer = race_list[choice][1] # 1 because the class object is the second in the tuple
new_creature = race_initializer(their_name, their_passive, their_hp)
except IndexError:
# Bad input
I included the name in the race_list so that you can loop over the list and print out index->name associations for the user to pick from.
You may also want to use a more robust structure than a plain tuple to store name->initializer mappings, but it works well in simple cases.

Python 3: vehicle inventory using class

I am having trouble getting my Python program to work for my class assignment. I have written what I think is the correct code but I still get errors like:
*NameError: name 'self' is not defined* Here is the Assignment:
Create a final program that meets the requirements outlined below.
Create an automobile class that will be used by a dealership as a vehicle inventory program. The following attributes should be present in your automobile class:
private string make
private string model
private string color
private int year
private int mileage
Your program should have appropriate methods such as:
constructor
add a new vehicle
remove a vehicle
update vehicle attributes
At the end of your program, it should allow the user to output all vehicle inventory to a text file.
Below is my code and any help is appreciated:
class Automobile:
def __init__(self, make, model, color, year, mileage):
self.make = make
self.model = model
self.color = color
self.year = year
self.mileage = mileage
def add_vehicle(self):
auto = Automobile()
vehicle_file = open('vehicle.txt', 'a')
make = input("Enter make: ")
model = input("Enter model: ")
color = input("Enter color: ")
year = input("Enter year: ")
mileage = input("Enter mileage: ")
vehicles = Automobile(make, model, color, year, mileage)
vehicle_list = [vehicles.make, vehicles.model, vehicles.color, vehicles.year, vehicles.mileage]
for i in vehicle_list:
vehicle_file.write("%s\t" % item)
vehicle_file.write("\n")
vehicle_file.close()
print("Your record has been succesfully added to the inventory")
def delete_vehicle(self):
del_rec = input("Enter record to delete: ")
with open("vehicle.txt","r+") as f:
new_f = f.readlines()
f.seek(0)
for line in new_f:
if del_rec not in line:
f.write(line)
f.truncate()
print("Succesfully deleted record from inventory")
def set_make(self, make):
self.make = make
def get_make(self):
return self.make
def set_model(self, model):
self.model = model
def get_model(self):
return self.model
def set_color(self, color):
self.color = color
def get_color(self):
return self.color
def set_year(self, year):
self.year = year
def get_year(self):
return self.year
def set_mileage(self, mileage):
self.mileage = mileage
def get_mileage(self):
return self.mileage
def main():
menu = {}
menu['1']="Add Vehicle."
menu['2']="Delete Vehicle."
menu['3']="Find Vehicle"
menu['4']="Exit"
user=True
while user:
print ("""
1.Add a Vehicle
2.Delete a Vehicle
3.View Inventory
4.Exit/Quit
""")
ans=input("What would you like to do? ")
if ans=="1":
Automobile.add_vehicle
elif ans=="2":
Automobile.delete_vehicle(self)
elif ans=="3":
print(Automobile.vehicles)
elif ans=="4":
print("\n Goodbye")
break
elif ans !="":
print("\n Invaild Entry")
if __name__ == "__main__":
main()
Assuming you are importing this module you have created and using it in main, it works fine for me. The only thing you need to change is to change i to item in your for loop, and remove the self in delete vehicle all the way at the bottom. This removed all of the errors for me from your class. Also Please do note that if you are supposed to be using private and protected variables you need to add for ex: __self.Make. Your variables are currently not private or protected. by adding the _ or __ modifier you make the variables private or protected. I'm guessing you have a vague idea of what private and protected do, but that's why you need the getter and setters. give that a shot and see if it helps! also if you are still unclear please make sure to look back over private and protected variables. also not sure if your add vehicle method will work at the bottom because you didn't close the parentheses. it should be addvehicle()

How do I have various pieces of information associated with one value in a dictionary?

EDIT: CHECK AT THE BOTTOM FOR A MORE CLEAR VIEW OF WHAT I AM DOING, PLEASE!
As an example, let's say I have information on three cars:
Car One
500hp
180mph
15mpg
Car Two
380hp
140mph
24mpg
Car Three
450hp
170mph
20mpg
I want to put that in a dictionary, or SOMETHING, so that I can easily access it through a function.
def fuel_eco(car):
return("The fuel economy for %s is %s" % (car, mpg))
def top_speed(car):
return("The top speed for %s is %s" % (car, speed))
def horsepower(car):
return("The horsepower for %s is %s" % (car, hp))
Basically have a module with some functions and a list/dictionary/whatever of the information, and then have another script that asks what car they want to view info on, and what information they want to know.
import carstats
car = input("What car do you want to find out about?")
stat = input("What information do you want to know?")
getStat = getattr (carstats, stat)
print(getStat(car))
How do I store the information for the three vehicles (And more if I add them) in a dictionary, so I can retrieve the information?
Okay, these are the actual files I am working with:
File one is asoiaf.py:
def sigil (house):
"""
Function to return a description of the sigil of a specified Great House.
Takes one argument, the name of the House.
"""
house = house.lower ()
if house == "stark":
sigil = "a grey direwolf on a white field."
elif house == "lannister":
sigil = "a golden lion rampant on a crimson field."
elif house == "targaryen":
sigil = "a red three-headed dragon on a black field."
else:
sigil = "Unknown"
house = str(house[0].upper()) + str(house[1:len(house)])
return("The sigil for House %s is %s" % (house, sigil))
def motto (house):
"""
Function to return the family motto of a specified Great House.
Takes one argument, the name of the House.
"""
house = house.lower ()
if house == "stark":
motto = "Winter is coming!"
elif house == "lannister":
motto = "Hear me roar!"
elif house == "targaryen":
motto = "Fire and blood!"
else:
motto = "Unknown"
house = str(house[0].upper()) + str(house[1:len(house)])
return("The motto for House %s is: %s" % (house, motto))
The second file is encyclopedia.py:
import asoiaf
#import sl4a
#droid = sl4a.Android ()
#sound = input ("Would you like to turn on sound?")
info = "yes"
while info == "yes":
#if sound == "yes":
# droid.ttsSpeak ("What house do you want to learn about?")
house = input ("What house do you want to learn about?")
house = str(house[0].upper()) + str(house[1:len(house)])
#if sound == "yes":
# droid.ttsSpeak ("What do you want to know about House %s?" % house)
area = input ("What do you want to know about House %s?" % house)
getArea = getattr (asoiaf, area)
#if sound == "yes":
# droid.ttsSpeak (getArea (house))
print (getArea (house))
#if sound == "yes":
# droid.ttsSpeak ("Would you like to continue learning?")
info = input ("Would you like to continue learning?")
if info == "no":
print ("Goodbye!")
You'll see a lot of commenting out in the last code, because I had to comment out the TTS that I have for my phone, since most people are not on an Android right now. As you can see, I am using IF, ELIF, ELSE in the functions, and I am just trying to see if there is an easier way. I apologize if it is/was confusing.
Creating a class should be the best way to do it:
class Car: # define the class
def __init__(self, name, speed, hp, mpg):
# This is the constructor. The self parameter is handled by python,
# You have to put it. it represents the object itself
self.name = name
self.speed = speed
self.hp = hp
self.mpg = hp
# This bind the parameters to the object
# So you can access them throught the object
You can then use the object this way:
my_car1 = Car('Car One', 180, 500, 15)
my_car1.speed # Will return 180
Concercing the __init__ name, it has to be this name, all constructors have this name (that's how Python know it is the class constructor). The __init__ method is called when you call Car('car one', 180, 500, 15). You have to ommit the self parameter, Python handle it.
You can add other function to your class, like
def top_speed(self):
return 'The top speed is {}'.format(self.speed)
Then you simply have to do my_car1.topspeed()
In every function you define in a class self must be the first parameter (except some rare cases such as classmethod or staticmethods). Obviously the topseed function works only if you create it in the class Car: block.
I'd suggest you should read more about object oriented programming (OOP) in Python. Just google OOP python and you will have a lot of serious ressources explaining you how to create classes and how to use them.
This official python classes tutorial should help you a lot in understanding the concept.
EDIT:
Regarding the accessing of the class in an other script. It's simple:
let's say you save the code above in a car.py file. Just place that file in the same folder as your other script, and in your other script do:
from car import Car # car is the name of the .py file, Car is the class you want to import
name = input('Car name: ')
speed = int(input('Car speed: ')) # input return a string, you have to cast to an integer to have a number
hp = int(input('Car hp: '))
mpg = int(input('Car mpg : '))
my_car = Car(name,speed,hp,mpg) # Then you just create a Car Object with the data you fetched from a user.
stuff = my_car.speed * my_car.hp # An example of how to use your class
print('The given car have {} mph top speed and have {} horsepower'.format(my_car.speed,my_car.hp))
What you have to understand is that a Class is some kind of a formated data type. When creating a Car class, you are defining how to create a car object. And Each time you call Car(...), you actually create one of these object, the value you put in the object are whatever values you want to put. It could be random number, user input or even network fetched data. You can use this object as you want.
Edit 2:
Given your code. Creating classes will change some things. Let's Give an example.
File 1 houses.py:
class House: # defining a house class
def __init__(self,name, sigil, motto):
self.name = name
self.sigil = sigil
self.moto = motto
# Then, in the same file, you create your houses.
starks = House('starks','grey direwolf on a white field','Winter is coming!')
lannisters = House('lannisters', 'a golden lion rampant on a crimson field', 'Hear me roar!')
# let's skip targaryen, it's the same way...
unknown_house = House('unknown','unknown','unknow')
houses = [starks, lannisters]
def get_house(name):
for house in houses:
if house.name == name:
return house
return unknow_house # if no house match, return unknow
Then in your second file. You just se that:
import houses
house_wanted = input('What house do you want to know about?')
my_house = houses.get_house(house_wanted)
print('this is the house {}; Sigil {} and motto {}'.format(my_house.name, my_house.sigil, my_house.motto))
If you plan on working on biggers set. You should have a look at Enums. That could fit what you want.
If you want to getting a precise attribute, you can do it this way:
import houses
house_wanted = input('What house do you want to know about?')
my_house = houses.get_house(house_wanted)
attr= input('What do you want to know about that house?')
print(getattr(my_house,attr.lower()))
Note this last thing will raise an error if you call for non-existent attr (like foo).
There are many ways to solve the broader problem you describe in the text of your question (the question of how to store multiple pieces of information about an object). Classes maybe one good one. Classes have the advantage of better robustness than dictionaries.
To answer the specific question in the summary/title: "how to have more than one item associated with one key in a dictionary" - use dictionaries as the values, like this:
car_info = {'CarOne': {'power': 500, 'speed': 180, 'mileage': 18},
'CarTwo': {'power': 380, 'spead': 200, 'mileage': 10}
}
print "Car Two has power %d mileage %d" % (car_info['CarTwo']['power'], car_info['CarTwo']['mileage'])
You can see that this is not especially robust by trying to access the 'speed' for "CarTwo". If you look closely you will see that because I made a deliberate typo in the initializer for CarTwo, it does not have a speed at all, it has a spead. Classes will catch this error, dictionaries will not.
This is not a reason not to do it with dictionaries - just something to be aware of when deciding for your particular case.
You could create a class, called car, with whatever attributes you want!
Here's a great tutorial on how to do that: class tutorial
I'm on the road right now, but if you're having trouble, please tell me so that I can write some useful code...

passing variables with inheritance [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I'm trying to practice OOP by making a class selection program
# let's make a character selection program
class player:
def __init__(self, username, age, weight, height, gender):
self.username = username
self.age = age
self.weight = weight
self.height = height
self.gender = gender
class soldier(player):
strength = weight*height*2
print strength
print "Please enter the following"
player_username = raw_input("Please enter a username: ")
player_age = input("Please enter your age: ")
player_weight = input("Please enter your weight: ")
player_height = input("Please enter your height: ")
player_gender = raw_input("Please enter your gender: ")
player_character_class = raw_input("Please enter a player class: ")
character_obj = player(player_username, player_age, player_weight, player_height, player_gender)
print soldier.strength
However, I get the error
Traceback (most recent call last):
File "character_select.py", line 11, in <module>
class soldier(player):
File "character_select.py", line 12, in soldier
strength = weight*height*2
NameError: name 'weight' is not defined
Not really sure how how weight isn't defined. I thought I inherited it by passing "player" into "solder". Could someone help me on this?
Thank you!
Since you assign attributes to your player in __init__(), they don't get created until player is instantiated. However, in your soldier class, you're trying to set class attributes at class creation time based on variables that don't exist at that time, because they only exist on instances (of a different class, no less).
I think what you probably want to do is write an __init__() method for soldier. (I have also taken the liberty of capitalizing your class names per PEP 8. This helps keep track of which names refer to classes, i.e. templates for constructing objects, and which to instances of the classes.)
class Soldier(Player):
def __init__(self, username, age, weight, height, gender):
# call parent class to set up the standard player attributes
Player.__init__(self, username, age, weight, height, gender)
# now also define a soldier-specific attribute
self.strength = weight*height*2
And then instantiate the Soldier class rather than the Player class, since you want a soldier:
character_obj = Soldier(player_username, player_age, player_weight, player_height, player_gender)
print character_obj.strength
I should further note that this:
class Soldier(Player):
is not a function call. You are not passing Player to Soldier. Instead you are saying that Soldier is a kind of Player. As such, it has all the attributes and capabilities of a Player (which you do not need to specify again, that's the whole point of inheritance) plus any additional ones you define in Soldier. However, you do not have direct access to the attributes of Player (or a Player instance) when declaring Soldier (not that you would ordinarily need them).
Soldier is a class, yet you haven't instantiated it anywhere. You've tried instantiating a player, with character_obj, but when you attempt to print soldier.xxx it's looking at the class, not any object.
I took the liberty of correcting some errors/misconceptions in the code - see if this is helpful:
# let's make a character selection program
class Player:
def __init__(self, username, age, weight, height, gender):
self.username = username
self.age = age
self.weight = weight
self.height = height
self.gender = gender
class Soldier(Player):
def __init__(self, *args):
# First of all, in order to actually inherit the attributes of "player", you need to invoke the __init__ function for "player":
Player.__init__(self, *args) # The *args business is to send any arguments that can be handled by the generic player constructor to that player constructor.
# You probably want to work on the instance variable "strength", so use self.strength, self.weight, and self.height
self.strength = self.weight*self.height*2
# print strength
print "Please enter the following"
player_username = raw_input("Please enter a username: ")
player_age = input("Please enter your age: ")
player_weight = input("Please enter your weight: ")
player_height = input("Please enter your height: ")
player_gender = raw_input("Please enter your gender: ")
player_character_class = raw_input("Please enter a player class: ")
# I'm guessing you actually wanted to make the player a "soldier", not a generic "player"
character_obj = Soldier(player_username, player_age, player_weight, player_height, player_gender)
print character_obj.strength
Here is the output:
Please enter the following
Please enter a username: Brionius
Please enter your age: 92
Please enter your weight: 50
Please enter your height: 7
Please enter your gender: yes
Please enter a player class: super soldier
700

Categories

Resources