Python inheritance woes - python
This is a homework question, but as you can see I've written most of the code already. :) What I'm trying to have happen is that the Agent object inherits the methods from the Investor object, as the Agent object's methods are suppose to be basically the same. The only different is the constructors, Investor takes 6 parameters, Agent takes 7. You can see that the parameters are also basically the same.
Investor.load and Investor.report work, for the most part, as expected. The inherited methods in Agent do not. See below.
My main issues:
When I run report(o) on Investor, the output is slightly messed up. It has little paragraph symbols at the end of each line, rather than a carriage return. (I'm developing on linux)
When I run load and report on Agent, it does not populate my arrays (reports and data) as it should. Because of that, report prints nothing. How do I set up my class variables so that they work in the way I want them to?
Thanks!
Will re-add after turnin date.
Here is how the above code SHOULD function.
>>> from sys import stdout as o
>>> import datetime
>>> from hedgefunds import *
>>>
>>> i = Investor('Flintstone','Fred',datetime.date(1965,12,3),'male','Mr.')
>>>
>>> i
Investor('Flintstone', 'Fred', datetime.date(1965, 12, 3), 'male', 'Mr.', 1)
>>> repr(i)
"Investor('Flintstone', 'Fred', datetime.date(1965, 12, 3), 'male', 'Mr.', 1)"
>>> i.__repr__() # THIS CONTROLS PREVIOUS TWO LINES
"Investor('Flintstone', 'Fred', datetime.date(1965, 12, 3), 'male', 'Mr.', 1)"
>>> eval(repr(i)) # OBJECT CAN BE RECREATED FROM ITS REPR STRING
Investor('Flintstone', 'Fred', datetime.date(1965, 12, 3), 'male', 'Mr.', 1)
>>>
>>> i # NOTICE ONE ADDITIONAL BIT OF DATA WE DIDN'T SPECIFY?
Investor('Flintstone', 'Fred', datetime.date(1965, 12, 3), 'male', 'Mr.', 1)
>>> # THE '1' AT THE END IS THE RECORD ID rid. THE REPR STRING INCLUDES ALL DATA SO YOU SEE IT.
>>> # THE INVESTOR CLASS SHOULD ASSIGN A rid IF ONE IS NOT PASSED INTO THE CONSTRUTOR.
>>>
>>> print i
1, Mr. Fred Flintstone, 12/03/1965, male
>>> i.__str__() # THIS CONTROLS PREVIOUS LINE
'1, Mr. Fred Flintstone, 12/03/1965, male'
>>>
>>> # NOTE THE NAME IS NICELY PUT TOGETHER AND AND rid IS AT THE START
>>> # NOTE datetime.date(YYYY, MM, DD) BUT WE PRINT IN MM/DD/YYYY FORMAT
>>>
>>> # NOW LET'S LOOK AT OUR INVESTOR OBJECT'S ATTRIBUTES
>>> i.last_name
'Flintstone'
>>> i.first_name
'Fred'
>>> i.dob
datetime.date(1965, 12, 3)
>>> i.date_of_birth
'12/03/1965'
>>> i.gender
'male'
>>> i.title
'Mr.'
>>> i.name
'Mr. Fred Flintstone'
>>> i.rid
1
>>>
>>> # BUT WE'RE GONNA NEED SOMEHWERE TO STORE MULTIPLE INVESTOR OBJECTS
>>> # SO AS WELL AS CREATING INVESTOR OBJECTS, THE INVESTOR CLASS MUST ACT LIKE A RECORDSET
>>>
>>> Investor.report(o) # o WAS SET TO STDOUT AT THE TOP OF THIS TRACE BUT COULD BE ANY FILE
>>> Investor.add(i) # NO RECORDS SO LET'S ADD ONE
>>> Investor.report(o) # NOW WE HAVE SOMETHING TO REPORT
1, Mr. Fred Flintstone, 12/03/1965, male
>>>
>>> Investor.add(Investor('Flintstone','Wilma',datetime.date(1968,1,15),'female','Mrs.'))
>>> Investor.report(o)
1, Mr. Fred Flintstone, 12/03/1965, male
2, Mrs. Wilma Flintstone, 01/15/1968, female
>>>
>>> # WE COULD CONTINUE ADDING INVESTORS MANUALLY BUT SINCE WE'VE GOT A FILE FULL OF THEM....
>>> Investor.load('investors.csv')
>>> Investor.report(o)
1, Mr. Charles Creed, 12/05/1928, male
2, Miss Sheila Geller, 11/12/1962, female
3, Mr. Fred Kenobi, 07/13/1957, male
4, Miss Rachel Geller, 07/11/1968, female
5, Mr. Charles Rubble, 09/23/1940, male
6, Mrs. Leah Skywalker, 07/02/1929, female
7, Mr. Bill Balboa, 03/06/1988, male
8, Dr. Sheila Barkley, 08/26/1950, female
.
.
>>> # YOU SHOULD SEE 120 RECORDS (OUR TWO MANUALLY ADDED RECORDS ARE GONE)
>>>
>>>
>>>
>>> # AGENTS
>>>
>>> a = Agent(2.1,'Rubble','Barney',datetime.date(1966,4,20),'male','Mr.')
>>> a
Agent(2.1000000000000001, 'Rubble', 'Barney', datetime.date(1966, 4, 20), 'male', 'Mr.', 1)
>>> repr(a)
"Agent(2.1000000000000001, 'Rubble', 'Barney', datetime.date(1966, 4, 20), 'male', 'Mr.', 1)"
>>> eval(repr(a))
Agent(2.1000000000000001, 'Rubble', 'Barney', datetime.date(1966, 4, 20), 'male', 'Mr.', 1)
>>> print a
1, Mr. Barney Rubble, 04/20/1966, male, 2.1
>>> a.last_name
'Rubble'
>>> a.first_name
'Barney'
>>> a.dob
datetime.date(1966, 4, 20)
>>> a.date_of_birth
'04/20/1966'
>>> a.gender
'male'
>>> a.title
'Mr.'
>>> a.name
'Mr. Barney Rubble'
>>> a.rid
1
>>> a.commission
2.1000000000000001
>>> Agent.add(a)
>>> Agent.report(o)
1, Mr. Barney Rubble, 04/20/1966, male, 2.1
>>> Agent.load('agents.csv')
>>> Agent.report(o)
1, Mr. Barney Flintstone, 02/13/1933, male, 4.0
2, Miss Rachel Rubble, 11/21/1982, female, 2.5
3, Dr. Ted Geller, 03/14/1963, male, 8.0
4, Miss Phoebe Creed, 11/06/1959, female, 5.5
5, Mr. Luke Kenobi, 08/24/1945, male, 2.5
6, Dr. Megan Creed, 03/26/1957, female, 5.5
7, Mr. Ted Rubble, 09/14/1931, male, 3.5
8, Mrs. Monica Balboa, 05/07/1934, female, 1.5
There is a lot going on here, so I'll try to be brief.
class Investor(object):
reports = []
data = []
def __init__(self, LastName, FirstName, Date, Gender, Title, Rid=1):
# the following two lines define variables which only exist inside
# __init__, so they can basically be gotten rid of.
# reports = []
# data = []
# but they *don't need to be initialized*. Actually creating a new list
# in each constructor is *bad* unless you want one report per instance
# ... later, be sure to add "self" instead of adding to the local vars
self.add(self)
#classmethod
def report(self, o):
result = ""
for x in self.reports:
# Just use join, that's what you mean anyway.
result = ', '.join(x)
# \n should result in \n\n. I think you mean o.write(result)
o.write(result + "\n")
#classmethod
def load(self, f):
self.reports = []
self.data = []
file = open(f)
# why the extra readline?
file.readline()
list = []
while 1:
line = file.readline()
# you need to get rid of the trailing whitespace
items = line[:-1].split(", ")
if not line:
break
else:
# self, here, refers to the class, so you can use it as the
# constructor as well
# use the * to make a list into an argument list.
self(*items)
# No need to add it, the value is added at the end of __init__
# as things stand.
class Agent(Investor):
reports = []
data = []
def __init__(self, Commission, LastName, FirstName, \
Date, Gender, Title, Rid=1):
super(Agent, self).__init__(self, LastName, FirstName, Date, \
Gender, Title, Rid)
self.commission = Commission
def __str__(self):
# Be lazy! Use super!
return super(Agent,self).__str__() + ', ' + self.commission
# this was doing the same thing in the parent class.
# def __repr__(self):
# The classmethod methods are not needed unless you want to redefine
# behavior in a child class.
#classmethod
def add(self, i):
# If you do change something, though, make sure to use super
# here as well...
super(Agent, self).add(i)
I believe that should take care of most of your issues.
If you want to have the format Investor('Flintstone', 'Fred', datetime.date(1965, 12, 3), 'male', 'Mr.', 1), you'll need to include the __name__ and quote the properties:
def __repr__(self):
# notice the " and ' below.
return self.__name__ + "('" + str(self.rid) + "', '" + \
self.name + "', " + self.date_of_birth + ", '" + self.gender + "')"
In Agent you will need to use a sub-string to get what you need:
def __repr__(self):
# remove the Agent( so you can add the commission at the *front*
s = super(Agent,self).__str__()
return self.__name__ + "('" + self.commission + "'," + \
s[len(self.__name__ + 1):]
Related
How to create class diagram and write pseudocode that defines the class?
I want to design a class named houses that holds the street address, asking price, number of bedrooms and number of bathrooms in the house. I would also like methods included to get and set values for each data field. First time working with classes. I got the class setup and I'm able to print the classes but I'm not sure how or which methods to use. class houses: def __init__(self, Adress, Askingprice, NumOfBedrooms, NumofBathroom): self.Adress = Adress self.Askingprice = Askingprice self.NumOfBedrooms = NumOfBedrooms self.NumofBathroom = NumofBathroom def HouseDetails(self): return "The house is at {} with a price of {} and has {} Bedroom/s and {} bathroom/s" \ .format(self.Adress, self.Askingprice, self.NumOfBedrooms, self.NumofBathroom) house1 = houses("Almonaster_Avenue87", "R 500k", 1, 1) house2 = houses("Audubon_Place33", "R 900k", 3, 3) house3 = houses("Baronne_Street78", "R800k", 3, 2) house4 = houses("Basin_Street55", "R700k", 2, 1) house5 = houses("Bayou_Road11", "R 900", 4, 2) house6 = houses("Bienville_Street78", "R700k", 2, 2) house7 = houses("Bourbon_Street45", "R 800k", 4, 1) house8 = houses("Broad_Street56", "R 900k", 5, 3) print("\n",house1.HouseDetails()) Please Note The "R" at asking price is my currency.
If you must have getter and setter methods, here's a succinct way to do it using Python's built-in property class. The create_property() utility function shown is a simplified version of recipe 9.21 in the 3rd edition of the Python Cookbook by Beazley & Jones (2013). def create_property(name): """ Utility to define repetitive property methods. """ storage_name = '_' + name #property def prop(self): # getter return getattr(self, storage_name) #prop.setter def prop(self, value): # setter return setattr(self, storage_name, value) return prop class House: address = create_property('address') asking_price = create_property('asking_price') num_bedrooms = create_property('num_bedrooms') num_bathrooms = create_property('num_bathrooms') def __init__(self, address, asking_price, num_bedrooms, num_bathrooms): self.address = address self.asking_price = asking_price self.num_bedrooms = num_bedrooms self.num_bathrooms = num_bathrooms def __str__(self): return("The house is at {} with a price of {} and has " "{} Bedroom/s and {} bathroom/s".format(self.address, self.asking_price, self.num_bedrooms, self.num_bathrooms)) house1 = House("Almonaster Avenue 87", "R 500k", 1, 1) house2 = House("Audubon Place 33", "R 900k", 3, 3) house3 = House("Baronne Street 78", "R 800k", 3, 2) house4 = House("Basin Street 55", "R 700k", 2, 1) house5 = House("Bayou Road1 1", "R 900", 4, 2) house6 = House("Bienville Street 78", "R 700k", 2, 2) house7 = House("Bourbon Street 45", "R 800k", 4, 1) house8 = House("Broad Street 56", "R 900k", 5, 3) print(house1) Output: The house is at Almonaster Avenue 87 with a price of R 500k and has 1 Bedroom/s and 1 bathroom/s
Trying to get a weighted average out of a dictionary of grades data
I am trying to return the weighted average of the student's grades based on the last definition. I have the dictionaries defined, but think my attempt to pull the numbers out is incorrect. def Average(lst): return sum(lst) / len(lst) # Driver Code lst = [1,2,3,4,5] average = Average(lst) print("Average of the list =", average) def get_weighted_average(student): return average('homework')*0.10 + average('quizzes')*0.30 + average('tests')*.60 #driver code students = [steve, alice, tyler] print(get_weighted_average('steve')) How to get a weighted average out of a dictionary of grades above?
What is the primary source of your data? Text? Anyway, it looks like you have something like this in mind. Imperative approach 1 - Your "database" students_marks = { 'steve':{ 'homework':[1,2,3,4,5], 'quizzes' :[5,4,3,2,1], 'tests' :[0,0,0,0,0], }, 'alice':{ 'homework':[5,4,3,2,1], 'quizzes' :[0,0,0,0,0], 'tests' :[1,2,3,4,5], }, } use case: >>> students_marks['steve'] {'homework': [1, 2, 3, 4, 5], 'quizzes': [5, 4, 3, 2, 1], 'tests': [0, 0, 0, 0, 0]} >>> students_marks['steve']['homework'] [1, 2, 3, 4, 5] 2 - The definition of average and get_weighted_average def average(lst): return sum(lst)/len(lst) # Python3 #return sum(lst)/float(len(lst)) # Python2 def get_weighted_average(student_name): student_marks = students_marks[student_name] return round( average(student_marks['homework'])*.1 + average(student_marks['quizzes'])*.3 + average(student_marks['tests'])*.6 , 2) use case: >>> get_weighted_average('steve') 1.2 >>> get_weighted_average('alice') 2.1 or using list >>> students_names = ['steve', 'alice'] >>> [get_weighted_average(name) for name in students_names] [1.2, 2.1] or using dict >>> {name:get_weighted_average(name) for name in students_names} {'steve': 1.2, 'alice': 2.1} Object-Oriented (OO) approach All this being shown, what you want to do would probably be better done by programming in an OO manner. A quick example class Student(object): homeworks_weight = .1 quizzes_weight = .3 tests_weight = .6 def __init__(self, name, homeworks_marks, quizzes_marks, tests_marks): self.name = name self.homeworks_marks = homeworks_marks self.quizzes_marks = quizzes_marks self.tests_marks = tests_marks #staticmethod def average(marks): return sum(marks)/len(marks) def get_gpa(self, rd=2): return round( self.average(self.homeworks_marks)*self.homeworks_weight + average(self.quizzes_marks)*self.quizzes_weight + average(self.tests_marks)*self.tests_weight , rd) use case: >>> steve = Student( name = 'Steve', homeworks_marks = [1,2,3,4,5], quizzes_marks = [5,4,3,2,1], tests_marks = [0,0,0,0,0] ) >>> steve.get_gpa() 1.2 >>> steve.homeworks_marks [1, 2, 3, 4, 5]
Python textwrap.dedent with comment does not work as expected
I'm using Python 3.6 on visual studio. Below is python interactive log >>> from textwrap import dedent >>> dedent("\ta = 4\n") 'a = 4\n' >>> dedent("\ta = 4\n#") '\ta = 4\n#' >>> dedent("\ta = 4\n\t#") 'a = 4\n#' >>> dedent("\ta = 4\n\t\n#") '\ta = 4\n\n#' >>> dedent("\ta = 4\n\t\n\t#") 'a = 4\n\n#' >>> dedent("\ta = 4\n\t#\n\t") 'a = 4\n#\n' >>> dedent("\ta = 4\n\t\n#\t") '\ta = 4\n\n#\t' >>> dedent properly unindents leading tab on first case, but when i added '#', leading tab does not unindents. Is this intended?
textwrap.dedent() assumes its argument is plain text, not Python source code. It doesn't interpret "#" as a comment. These two examples will behave similarly: >>> dedent("\ta = 4\n#") '\ta = 4\n#' >>> dedent("\ta = 4\nx") '\ta = 4\nx'
How to compare "peewee.DateField" with "datatime.date"?
I wrote the below program to fetch some rows of my database that contain information about the users whom born after 22-Jan-1963: import datetime as dt import peewee as pw db = pw.SqliteDatabase('people.db') class Person(pw.Model): name = pw.CharField() birthday = pw.DateField(formats=['%d-%b-%Y']) class Meta: database = db # This model uses the "people.db" database. db.create_tables([Person]) bob = Person(name = 'Bob', birthday = '21-Jan-1960') james = Person(name = 'James', birthday = '22-Jan-1965') steve = Person(name = 'Steve', birthday = '20-Jan-1970') alex = Person(name = 'Alex', birthday = '18-Jan-1975') bob.save() james.save() steve.save() alex.save() for item in Person.select().where(Person.birthday > dt.date(1963,1,22)): print item.name,item.birthday, item.birthday > dt.date(1963,1,22) But when I run this, output is not what I have expected (I expect James, Steve and Alex in the output): >>> ================================ RESTART ================================ >>> Bob 1960-01-21 False James 1965-01-22 True Steve 1970-01-20 True >>> Well, I replaced dt.date(1963,1,22) with "22-Jan-1963" in the where() method, and now the result is: >>> ================================ RESTART ================================ >>> James 1965-01-22 True >>> As you see above, it is not correct still. What shall I do?
Following the documentation, I’d suggest other = dt.date(1963, 1, 22) Person.select().where( Person.birthday.year >= other.year ).where( Person.birthday.year > other.year | Person.birthday.month >= other.month ).where( Person.birthday.year > other.year | Person.birthday.month > other.month | Person.birthday.day > other.day ) Yeah, it’s quite verbose...
I absolutely do not know PeeWee, but given that Sqlite does not have a native date-time format (it mimics it as a string), you may want to try and change the date format to "%Y-%m-%d"; this will automatically be sorted correctly as a string, which may then work for Sqlite.
How to pivot/cross-tab data in Python 3?
What is the best solution to pivot/cross-tab tables in Python 3? Is there a built-in function that will do this? Ideally, I'm looking for a Python 3 solution that does not have external dependencies. For example, given a nested list: nl = [["apples", 2 "New York"], ["peaches", 6, "New York"], ["apples", 6, "New York"], ["peaches", 1, "Vermont"]] I would like to be able to rearrange rowed data and groupby fields: apples peaches New York 2 6 Vermont 6 1 The above is a trivial example, but is there a solution that would be easier than using itertools.groupby everytime a pivot is desired? Ideally, the solution would allow rowed data to be pivoted on any column. I was debating about using pandas, but it is an external library and only has limited Python 3 support.
Here is some simple code. Providing row/column/grand totals is left as an exercise for the reader. class CrossTab(object): def __init__( self, missing=0, # what to return for an empty cell. # Alternatives: '', 0.0, None, 'NULL' ): self.missing = missing self.col_key_set = set() self.cell_dict = {} self.headings_OK = False def add_item(self, row_key, col_key, value): self.col_key_set.add(col_key) try: self.cell_dict[row_key][col_key] += value except KeyError: try: self.cell_dict[row_key][col_key] = value except KeyError: self.cell_dict[row_key] = {col_key: value} def _process_headings(self): if self.headings_OK: return self.row_headings = list(sorted(self.cell_dict.keys())) self.col_headings = list(sorted(self.col_key_set)) self.headings_OK = True def get_col_headings(self): self._process_headings() return self.col_headings def generate_row_info(self): self._process_headings() for row_key in self.row_headings: row_dict = self.cell_dict[row_key] row_vals = [ row_dict.get(col_key, self.missing) for col_key in self.col_headings ] yield row_key, row_vals if __name__ == "__main__": data = [["apples", 2, "New York"], ["peaches", 6, "New York"], ["apples", 6, "New York"], ["peaches", 1, "Vermont"]] ctab = CrossTab(missing='uh-oh') for s in data: ctab.add_item(row_key=s[2], col_key=s[0], value=s[1]) print() print('Column headings:', ctab.get_col_headings()) for row_heading, row_values in ctab.generate_row_info(): print(repr(row_heading), row_values) Output: Column headings: ['apples', 'peaches'] 'New York' [8, 6] 'Vermont' ['uh-oh', 1] See also this answer. And this one, which I'd forgotten about.
itertools.groupby was exactly made for this problem. You will be hard-pressed to find something better, especially within the standard library.