Using attributes from one class inside of another one - python

I'm working on a small fighting game as a learning experience and right now I'm working on implementing a store where you can buy weapons.
I decided to use a class for the store and have everything that you can do in it as a class method. But I'm unsure how to get all the data from my Weapon class and use it in the Store class. It's not pretty but here's what I have so far:
Sorry for misspelling tier.
class Item(object):
'''Anything that can be used or equiped.'''
def __init__(self, _id, desc, cost):
self._id = _id
self.desc = desc
self.cost = cost
class Weapon(Item):
def __init__(self, _id, desc, dam):
self._id = _id
self.desc = desc
self.dam = dam
def __str__(self):
return self._id
class Store(object):
dagger = Weapon('Dagger', 'A small knife. Weak but quick.', 'd4')
s_sword = Weapon('Short Sword', 'A small sword. Weak but quick.', 'd6')
l_sword = Weapon('Long Sword', 'A normal sword. Very versatile.', 'd8')
g_sword = Weapon('Great Sword', 'A powerful sword. Really heavy.', 'd10')
w_teir_1 = [dagger, s_sword, l_sword]
w_teir_2 = [w_teir_1, g_sword]
def intro(self):
print 'Welcome, what would you like to browse?'
print '(Items, weapons, armor)'
choice = raw_input(':> ')
if choice == 'weapons':
self.show_weapons(self.w_teir_1)
def show_weapons(self, teir):
for weapon in teir:
i = 1
print str(i), '.', teir._id
i += 1
raw_input()
I can't get the show_weapon function to print the _id for the weapon. All I can do is get it to print the raw object data.
Edit: I've figured out how to display the _id of the weapon when I'm passing the list w_teir_1 through the show_weapons method. But when I attempt to push w_teir_2 through, I get this error: AttributeError: 'list' object has no attribute '_id'

You need to change the last print stmt like below, since you're iterating over a list. _id attribute exists only for the elements which exists inside that list.
print str(i), '.', weapon._id
or
print str(i) + '.' + weapon._id
Update:
def show_weapons(self, teir):
for weapon in teir:
if isinstance(weapon, list):
for w in weapon:
i = 1
print str(i), '.', w._id
i += 1
raw_input()
else:
i = 1
print str(i), '.', weapon._id
i += 1
raw_input()

Related

How do i access all values of a particular instance variable in python class

I'm practicing OOP in python and I'm trying to rewrite my code using class. Each instance in the class is meant to have a unique value for a particular instance variable. So I need to check to see if the value that is to be assigned is not being used by another instance before assigning.
So for example, how do i convert something like this using class.
from random import randint
accounts = {}
acc_number = []
names = ['john','ambrose','jess']
for name in names:
acc_num = randint(1,10)
while True:
if acc_num in acc_number:
acc_num = randint(1,10)
else:
acc_number.append(acc_num)
break
accounts[name] = acc_num
print(accounts)
Since the purpose of class is to keep each instance's values apart, how can I neatly ensure acc_numberis unique?
are you talking about how to make a class that's guaranteed to have a unique attribute named acc_num?
used_acc_nums = []
class Account:
def __init__(self,name):
self.name = name
self.acc_num = random.randint(0,10)
while self.acc_num in used_acc_nums:
self.acc_num = random.randint(0,10)
used_acc_nums.append(self.acc_num)
john = Account("John")
ambrose = Account("Ambrose")
jess = Account("Jess")
for acc in [john, ambrose,jess]:
print(acc.name , acc.acc_num)
Could have something like this:
from random import choice
class Person:
def __init__(self):
self.id = list(range(1, 10))
self.accounts = {}
def assign(self, name):
get_id = choice(self.id)
self.id.remove(get_id)
self.accounts[name] = get_id
def accounts(self):
return self.accounts
person = Person()
people = ['john', 'ambrose', 'jess']
for p in people:
person.assign(p)
print(person.accounts)
>>> {'john': 6, 'ambrose': 8, 'jess': 7}

Python project help (classes/expected type)

I am working on a project for school, simulating a payroll program, and I am getting an error. The error I am getting is
'Expected type 'Classification', got 'Employee' instead'. The relevant code is (I put *** around the code generating the error, it is the 5th function under the Employee Class).
class Employee:
def __init__(self, emp_id, first_name, last_name, address, city, state, zipcode, clas = None):
self.emp_id = emp_id
self.first_name = first_name
self.last_name = last_name
self.address = address
self.city = city
self.state = state
self.zipcode = zipcode
self.classification = clas
def make_hourly(self, hourly_rate):
self.clas = Hourly(hourly_rate)
self.classification = self.clas
def make_salaried(self, salary):
self.clas = Salaried(salary)
self.classification = self.clas
def make_commissioned(self, salary, rate):
self.clas = Commissioned(rate, salary)
self.classification = self.clas
def issue_payment(self):
***pay = Classification.compute_pay(self)***
print('Mailing', pay, 'to', self.first_name, self.last_name, 'at', self.address, self.city, self.state, self.zipcode)
class Classification(ABC):
''' Interface for employee classifications '''
#abstractmethod
def compute_pay(self):
pass
class Hourly(Classification):
''' Manages timecard info. Computes pay '''
def __init__(self, hourly_rate):
self.hourly_rate = hourly_rate
self.timecards = [] # A list of floats representing hours worked
def compute_pay(self):
for i in list_of_timecards:
if i[0] == self.emp_id:
self.timecards.extend(i[1:])
total = list(map(float, self.timecards))
total = sum(total)
self.timecards.clear()
return total * self.hourly_rate
def add_timecard(self, hours):
self.timecards.append(hours)
class Salaried(Classification):
def __init__(self, salary):
self.salary = salary
def compute_pay(self):
return self.salary / 24
class Commissioned(Salaried):
def __init__(self, salary, commission_rate):
self.commission_rate = commission_rate
self.salary = salary
self.receipts = []
def add_receipt(self, amount):
self.receipts.append(amount)
def compute_pay(self):
for i in list_of_receipts:
if i[0] == self.emp_id:
self.receipts.extend(i[1:])
total = list(map(float, self.receipts))
total = sum(total)
self.receipts.clear()
return (self.salary / 24) + ((self.commission_rate / 100) * total)
My understanding of the problem is that I need to pass my 'employee' object to the 'compute_pay' function, which then passes it to the relevant child class (hourly etc...) to run and return the result. I have tried changing
pay = Classification.compute_pay(self)
to
pay = Classification.compute_pay(self.clas)
however that returns error 'AttributeError: 'Employee' object has no attribute 'clas'
which makes no sense. Maybe it is that I am not assigning the employees to the class correctly?
The code for that is (it pulls from a CSV file, and it is pulling the data correctly and generating the class objects, I have checked)
def load_employees():
f = open("employees.csv")
f.readline() # skip header line
for line in f:
fields = line.strip().split(',')
emp = Employee(*fields[:7])
if fields[7] == '3':
clas = Hourly(fields[10]) # Need to define Hourly
emp.classification = clas
elif fields[7] == '2':
clas = Commissioned(fields[8], fields[9])
emp.classification = clas
elif fields[7] == '1':
clas = Salaried(fields[8])
emp.classification = clas
employees.append(emp)
I will figure out your line Classification.compute_pay(self):
Classification => the class Classification
compute_pay => class
method self => this = an Employee instance
pass means do nothing and is used to avoid unneccessary code.
Every class method has self as an argument to allow refering to this instance of the class.
To pass an argument (here your employee) use a parameter. Also implementing a method of the parent class overrides this method.
Every function compute_pay should have a second argument
def compute_pay(self, employee):
# do your stuff
And then you can use this line in issue_payment
pay = self.clas.compute_pay(self)
Two issues here,
Firstly, your Employee instance has two attributes: clas and classification. However, in your constructor, only classification is set.
def __init__(...
...
self.classification = clas
But self.clas is not set to anything. That's why you are getting that error 'Employee' object has no attribute 'clas'. It is only set when one of the make_hourly, make_salaried, or make_commissioned methods are invoked. So when you load the employees CSV, instead of manually creating the instance like you are doing here
clas = Hourly(fields[10])
you should be calling the method make_hourly on your emp instance, like so
emp.make_hourly(fields[10])
It's worth noting that fields[10] is terrible naming. Instead of unpacking all the fields at once, try to unpack them during the for loop:
for a, b, c, d in csv:
...
Secondly, this line of code is wrong in multiple ways
pay = Classification.compute_pay(self)
compute_pay is not a static function or a classmethod. So it shouldn't be called on the Classification class itself, but the Classification instance. This is what you stored in your self.clas attribute. So, compute_pay should be called on self.clas:
def issue_payment(self):
pay = self.clas.compute_pay()
...
In addition to that, when you call a method of a class from inside of another method in the same class, you don't ever need to pass the self argument. It is implied. So even if compute_pay was static or a class method, which it isn't, it would be called like so,
Classification.compute_pay()
Notice there is no self inside the parentheses. Similarly, when you call another method that is not static, self is never passed as an argument:
def my_method(self):
self.another_method()

Method as an argument with self parameter

Disregard the naming conventions as to what class is part of which it is just a test run.
I need some help with the OOP inheritance i have created a class of Students, Teachers, and the principal. My goal is for the principal to be able to add employees. The problem is i just want to use a for loop to get the names and then pass that method as an attribute for the principal object. i was able to do it with the class Input without the self parameter. can someone tell me
what is going on here and how can i fix this with self. i removed input from names so that my question wont get shut down
class Input:
def count():
cnt = []
for i in range(4):
name = ('Enter name here: ')
cnt.append(name)
return cnt
class Student:
def __init__(self,name,lastname):
self.name = name
self.lastname = lastname
class StudentCouncil(Student):
def __init__(self, name, lastname, tenure):
super().__init__(name,lastname)
self.tenure = tenure
class Principal(StudentCouncil):
def __init__(self, name, lastname, tenure,employees=None):
super().__init__(name,lastname,tenure)
if employees is None:
self.employees = []
else:
self.employees = employees
def display(self):
for names in self.employees:
print(names,end=' ')
count = Input.count()
tij = Principal('Mike','Thoma','3',count)
tij.display()
If the method takes a self parameter, you need to create an instance of the class. So it would be:
class Input:
def count(self):
cnt = []
for i in range(4):
name = input('Enter name here: ')
cnt.append(name)
return cnt
and then you would do:
myinput = Input()
count = myinput.count()
Your count() method doesn't use any attributes of self, so it doesn't currently need to be written this way. But you might want to redefine it like this:
class Input:
def __init__(self, howmany):
self.howmany = howman
def count(self):
return [input('Enter name here: ') for _ in range(self.howmany)]
myinput = Input(4)
count = myinput.count()
If count is all you want from Input, just make it a function:
def input_names():
cnt = []
for i in range(4):
name = ('Enter name here: ')
cnt.append(name)
return cnt
If you want a configurable Input type of some sort, then you want to run count on an instance of that, you need self:
class Input:
def count(self):
cnt = []
for i in range(self.num_names): # if we need some configuration
name = ('Enter name here: ')
cnt.append(name)
return cnt
Else, the kosher way to do this is to use the staticmethod decorator:
class Input:
#staticmethod
def count():
cnt = []
for i in range(4):
name = ('Enter name here: ')
cnt.append(name)
return cnt
Your current code will work as you use it currently, Input.count(), but if you instantiated an input, Input().count() would throw an exception. The staticmethod decorator ensures that this method is safe to call on either the class directly or on an instance of that class.

Where attribute does not exist, create an attribute and give it a default value

I am learning Python out of a book and have written myself a long quiz/type game which prints a summary at the end. However, the summary looks for attributes that will not always exist depending on what choices have been made by the user.
I have abstracted this into a basic example to show what I am trying to do. Essentially, I just want to run an attribute error check, for every variable that does not have an attribute, create an attribute with a default value of N/A.
In the below example, I would want it to print:
Forename: Joe
Surname: Bloggs
Smith Test: N/A
Test 4: N/A
I created a class called CodeCleaner which I was going to use to set the N/A values, but got very stuck!
class QuestionSet(object):
next_set = 'first_set'
class ClaimEngine(QuestionSet):
def current_set(self):
last_set = "blank"
while_count = int(0)
quizset = Sets.subsets
ParentSet = QuestionSet()
while ParentSet.next_set != last_set and int(while_count)<50:
quizset[ParentSet.next_set].questioning()
while_count = while_count+1
class FirstSet(QuestionSet):
def questioning(self):
self.value1 = raw_input("Forename:\n")
QuestionSet.next_set = "second_set"
class SecondSet(QuestionSet):
def questioning(self):
self.value2 = raw_input("Surname:\n")
if self.value2 == "Smith":
self.value3 = "He's a Smith!"
self.value4 = "Test val 4"
QuestionSet.next_set = "summary"
else:
QuestionSet.next_set = "summary"
class CodeCleaner(QuestionSet):
def questioning(self):
mapping = Sets()
sets = mapping.subsets
variable_list = {
[sets['first_set']].value1,
[sets['second_set']].value2,
[sets['second_set']].value3,
[sets['second_set']].value4
}
#while key_no < 4:
# try:
# print variable_list
# except AttributeError:
class Summary(QuestionSet):
def questioning(self):
mapping = Sets()
sets = mapping.subsets
print "Forename:",sets['first_set'].value1
print "Surname:",sets['second_set'].value2
print "Smith Test:",sets['second_set'].value3
print "Test 4:",sets['second_set'].value4
exit(0)
class Sets(object):
subsets = {
'first_set': FirstSet(),
'second_set': SecondSet(),
'summary': Summary()
}
run = ClaimEngine()
run.current_set()
I feel quite lazy asking this question, however, I've been wrestling with this for a few days now! Any help would be appreciated.
I'm not sure I go exactly your approach, but you can implement a __getattr__ method in an object that would be called when the attribute is not found:
class A(object):
def __getattr__(self, name):
print("Creating attribute %s."%name)
setattr(self, name, 'N/A')
Then:
>>> a = A()
>>> a.a
Creating attribute a.
>>> a.a
'N/A'

using a class instead of a list python

I have the following code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys import re
companies = {}
for line in open('/home/ibrahim/Desktop/Test.list'):
company, founding_year, number_of_employee = line.split(',')
number, name = company.split(")")
companies[name] = [name, founding_year, number_of_employee]
print "Company: %s" % company
CompanyIndex = raw_input('\n<Choose a company you want to know more about.>\n\n<Insert a companyspecific-number and press "Enter" .>\n')
if CompanyIndex in companies:
name, founding_year, number_of_employee = companies[CompanyIndex]
print 'The companys name is: ',name,'\nThe founding year is: ', founding_year,'\nThe amount of employees is: ', number_of_employee
else:
print"Your input is wrong."
This program reads some information from a text file which looks like this:
(1)Chef,1956,10
(2)Fisher,1995,20
(3)Gardener,1998,50
My aim is to get a class, where I can save the information about the company's name, the founding year, and the number of employees instead of using the dictionary which also contains a list.
I read several tutorials but I really do not know how to do that. It was really confusing what this "self" is what __init__ and __del__ does and so on. How do I go about doing this?
You can do:
class Company(object):
def __init__(self, name, founding_year, number_of_employee):
self.name = name
self.founding_year = founding_year
self.number_of_employee = number_of_employee
After that you can create a Company object by writing company = Company('Chef', 1956, 10).
Here's an example of how you could create a CompanyInfo class.
class CompanyInfo(object):
def __init__(self, name, founded_yr, empl_count):
self.name = name
self.founded_yr = founded_yr
self.empl_count = empl_count
def __str__(self):
return 'Name: {}, Founded: {}, Employee Count: {}'.format(self.name, self.founded_yr, self.empl_count)
And here's an example of how you might create it:
# ...
for line in open('/home/ibrahim/Desktop/Test.list'):
company, founding_year, number_of_employee = line.split(',')
comp_info = CompanyInfo(company, founding_year, number_of_employee)
And here's an example of how you might use it:
print "The company's info is:", str(comp_info)
class companies(object):
def __init__(self,text_name):
text_file = open(text_name,'r')
companies = {}
all_text = text_file.read()
line = all_text.split('\n') #line is a list
for element in line:
name,year,number = element.split(',')
companies[name] = [year,number]
self.companies = companies
def get_information(self,index):
print self.companies[index]
#an instance of the class defined above
my_company = companies(r'company.txt')
#call function of my_company
my_company.get_information(r'Gardener')
class Company:
def __init__(self, name, year_of_funding, num_of_employees):
'''
This is the constructor for the class. We pass the
info as arguments, and save them as class member variables
'''
self.name = name
self.year_of_funding = year_of_funding
self.num_of_employees = num_of_employees
def get_name(self):
'''
This method returns the company name
'''
return self.name
def get_year_of_funding(self):
'''
This method returns the year the company was funded
'''
return self.year_of_funding
def get_num_of_employees(self):
'''
This method returns the number of employees this company has
'''
return self.num_of_employees
Then you can create an instance of the class, and use the get methods to fetch the data:
my_company = Company('Microsoft', 1964, 30000)
print my_company.get_name() + ' was funded in ' + str(my_company.get_year_of_funding()) + ' and has ' + str(my_company.get_num_of_employees()) + ' employees'
# OUTPUT: Microsoft was funded in 1964 and has 30000 employees

Categories

Resources