I have the below code base:
from datetime import datetime
class Person:
def __init__(self,day,month,year):
self.day = day
self.mon = month
self.year = year
def __repr__(self):
if self.day < 10:
day = "0" + str(self.day)
else:
day = str(self.day)
if self.mon < 10:
mon = "0" + str(self.mon)
else:
mon = str(self.mon)
display = day + "-" + mon + "-" + str(self.year)
return display
def sortdates(l1):
for dates in l1:
date.finalbirthdate = datetime.strptime(str(print(dates)),"%d-%m-%Y")
print (date.finalbirthdate)
if __name__ == '__main__':
p1 = Person(18,9,1984)
print (p1)
p2 = Person(13,1,1988)
print (p2)
sortdates([p1,p2])
Now the main function of sortdates function is to sort the Person objects as per the dates. For that i somehow need to convert the string representation of the Person object into datetime object.
Also since i have to do that i have to somehow capture the string representation into a variable and pass that to datetime.strptime function.
Can someone please guide me out on how to do this?
Thanks in advance.
The correct way to do this is to define __lt__, __gt__, __eq__ methods for your Person object; this way your Person object becomes "sortable" on its own.
class Person:
def __init__(self,day,month,year):
self.day = day
self.mon = month
self.year = year
def _as_date(self):
return datetime.date(self.year, self.mon, self.day)
def __lt__(self, other):
return self._as_date() < other._as_date()
def __gt__(self, other):
return self._as_date() > other._as_date()
def __eq__(self, other):
return self._as_date() == other._as_date()
def __ne__(self, other):
return ! self.__eq__(other)
def __repr__(self):
return '{}-{}-{}'.format(str(self.day).zfill(2),
str(self.mon).zfill(2),
self.year)
Now, you can just sort your objects directly:
if __name__ == '__main__':
p1 = Person(18,9,1984)
print (p1)
p2 = Person(13,1,1988)
print (p2)
sorted_dates = sorted([p1,p2])
Related
This is the exercise:
Write the special method __str__() for CarRecord.
Sample output with input: 2009 'ABC321'
Year: 2009, VIN: ABC321
The following code is what I have came up with, but I'm receiving an error:
TYPEERROR: __str__ returned non-string
I can't figure out where I went wrong.
class CarRecord:
def __init__(self):
self.year_made = 0
self.car_vin = ''
def __str__(self):
return "Year:", (my_car.year_made), "VIN:", (my_car.car_vin)
my_car = CarRecord()
my_car.year_made = int(input())
my_car.car_vin = input()
print(my_car)
You're returning a tuple using all those commas. You should also be using self, rather than my_car, while inside the class. Try like this:
def __str__(self):
return f"Year: {self.year_made}, VIN: {self.car_vin}"
The f before the string tells Python to replace any code in braces inside the string with the result of that code.
class Car:
def __init__(self):
self.model_year = 0
self.purchase_price = 0
self.current_value = 0
def print_info():
print('Car Info') # It specifies a print_info class method but doesnt actually need to print anything useful.
def calc_current_value(self, current_year):
depreciation_rate = 0.15
car_age = current_year - self.model_year
self.current_value = round(self.purchase_price * (1 - depreciation_rate) ** car_age)
def print_info(self):
print("Car's information:")
print(" Model year:", self.model_year)
print(" Purchase price:", self.purchase_price)
print(" Current value:", self.current_value)
if __name__ == "__main__":
year = int(input())
price = int(input())
current_year = int(input())
my_car = Car()
my_car.model_year = year
my_car.purchase_price = price
my_car.calc_current_value(current_year)
my_car.print_info()
def __str__(self):
return "Year: {}, VIN: {}".format(self.year_made, self.car_vin)
The trick here is that you pull values from the top of the class as they are set later in the code.
This answer works for grading
def __str__(self):
return f"Year: {}, VIN: {}".format(self.year_made, self.car_vin)`
This is easier to understand
def __str__(self):
f"Year: {self.year_made}, VIN: {self.car_vin}")
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 have issue with extending date class in python.
Since date is static class, however, I haven't get it working as it supposed to be. I tried to modify code base on datetime, since this class extend from date. However, failed.
Question is:
How to modify code to make it working like:
ed = ExtendDate(2011,1,1,week=3, quarter=3)
print ed.week # 3
How to deal with __new__, and __init__ in python static class (in theory) ?
How to extend date class (in general) ?
Thanks.
class ExtendDate(date):
"""Extend to have week and quarter property"""
#
# def __init__(self, year, month, day, week=None, quarter=None):
# pass
def __init__(self, year, month, day, week=None, quarter=None):
print 0
super(ExtendDate, self).__init__(year,month,day)
print 1
self._week = week
self._quarter = quarter
#staticmethod
def __new__(cls, year, month, day, week=None, quarter=None):
cls._week = 1
super(ExtendDate, cls).__new__(year, month, day)
def __cmp__(self, other):
if self.cmp_year(other) in [-1,0,1]:
return self.cmp_year(other)
if hasattr(self, 'quarter'):
return self.cmp_quarter(other)
if hasattr(self, 'week'):
return self.cmp_week(other)
# TODO: test - what if it's just a normal date object ?
pass
def cmp_quarter(self, other):
if self.quarter < other.quarter:
return -1
elif self.quarter == other.quarter:
return 0
elif self.quarter > other.quarter:
return 1
def cmp_week(self, other):
if self.week < other.week:
return -1
elif self.week == other.week:
return 0
elif self.week > other.week:
return 1
def cmp_year(self, other):
if self.year < other.year:
return -1
elif self.year == other.year:
return 0
elif self.year > other.year:
return 1
def __repr__(self):
return 'year:' + str(self.year) + ' ' + \
'quarter:' + str(self.quarter) + ' ' + \
'month:' + str(self.month) + ' '+ \
'week:' + str(self.week) + ' '+ \
'day:' + str(self.day) + ' '
week = property(lambda self: 0)
quarter = property(lambda self: 0)
#week.setter
def week(self, value):
self._week = value
#quarter.setter
def quarter(self, value):
self._quarter = value
__new__ isn't supposed to be decorated with #staticmethod (it's a class method implicitly, no decorator should be used). And it's supposed to return the instance created, where your code is modifying cls (which it shouldn't) and not returning the result of the super __new__ call (which it should). Also, if you're providing a __new__ (to make the class logically immutable), you shouldn't provide a __init__.
Really, the code you'd want would be something like:
class ExtendDate(date):
"""Extend to have week and quarter property"""
__slots__ = '_week', '_quarter' # Follow date's lead and limit additional attributes
def __new__(cls, year, month, day, week=None, quarter=None):
self = super(ExtendDate, cls).__new__(cls, year, month, day)
self._week = week
self._quarter = quarter
return self
Presumably, you'd also want functional getters, e.g.
#property
def week(self):
return self._week
# ... etc. ...
As #ShadowRanger answsered, I changed some lines to make it working.
The major change is __new__(cls, year, month, day):
from datetime import date
class ExtendDate(date):
"""Extend to have week and quarter property"""
__slots__ = '_week', '_quarter'
def __new__(cls, year, month, day, week=None, quarter=None):
# self = super(ExtendDate, cls).__new__(year, month, day)
self = date.__new__(cls, year, month, day)
self._week = week
self._quarter = quarter
return self
def __cmp__(self, other):
if self.cmp_year(other) in [-1,0,1]:
return self.cmp_year(other)
if hasattr(self, 'quarter'):
return self.cmp_quarter(other)
if hasattr(self, 'week'):
return self.cmp_week(other)
# TODO: test - what if it's just a normal date object ?
pass
def cmp_quarter(self, other):
if self.quarter < other.quarter:
return -1
elif self.quarter == other.quarter:
return 0
elif self.quarter > other.quarter:
return 1
def cmp_week(self, other):
if self.week < other.week:
return -1
elif self.week == other.week:
return 0
elif self.week > other.week:
return 1
def cmp_year(self, other):
if self.year < other.year:
return -1
elif self.year == other.year:
return 0
elif self.year > other.year:
return 1
def __repr__(self):
return 'year:' + str(self.year) + ' ' + \
'quarter:' + str(self.quarter) + ' ' + \
'month:' + str(self.month) + ' '+ \
'week:' + str(self.week) + ' '+ \
'day:' + str(self.day) + ' '
#property
def week(self):
return self._week
#property
def quarter(self):
return self._quarter
ed = ExtendDate(2011,1,2,3,4)
print type(ed)
print ed._week
class Course(object):
def __init__(self,cnum,name):
self.name = name
self.cnum = cnum
def __str__(self):
return 'Course:' , self.cnum , self.name
class AssigendCourse(Course):
def __init__(self,Course,dept,year,semester):
self.name = Course.name
self.cnum = Course.cnum
if dept == 'SE' or dept == 'CE' or dept == 'CIE' or dept == 'ME':
self.dept = dept
else:
self.dept = None
if year >= 1 and year <= 4:
self.year = year
else:
self.year = None
if semester >= 1 and semester <= 3:
self.semester = semester
else:
self.semester = None
def __str__(self):
return 'Course: ' , self.name , self.cnum
results in this type of error
TypeError: __str__ returned non-string (type tuple)
I can't figure what type of syntax I need to use for the __str__ func in order to get the print for the object when using:
it = iter(db)
for i in it:
print(i)
Your __str__ methods return tuples:
def __str__(self):
return 'Course:' , self.cnum , self.name
The comma makes it it tuple.
You'll need to join those values; I recommend string formatting:
def __str__(self):
return 'Course: {} {}'.format(self.cnum, self.name)
One part of my program requires that the user enters a date and this date is then checked against each product in the dictionary to see if the date the product arrived plus its shelf life causes the product to expire before or after the date entered by the user.
import sys
from string import *
import pickle
import datetime
cheeseDictionary = {}
userInput = ""
def loadProduct(fileName):
global cheeseDictionary
f = open(fileName,"r")
line = f.readline() # Reads line from file
while line:
line = line[:-1]
data = split(line,":") # Splits line when there is a colon
cheeseDictionary[data[0]] = {"date":data[1], "life":data[2], "name":data[3]} # Stores each split item
line = f.readline() # Next line
f.close()
def saveProduct(fileName,cheeseDictionary):
f = open(fileName, "w")
for i in sorted(cheeseDictionary.keys()):
v = cheeseDictionary[i]
f.write("%s:%s:%s:%s\n" % (i, v["date"], v["life"], v["name"]))
f.close()
def printProduct(cheeseDictionary):
print "ID"," ","Date"," ","Life(days)"," ","Name"
for cheese in cheeseDictionary:
print cheese," ",cheeseDictionary[cheese]["date"]," ",cheeseDictionary[cheese]["life"]," ",cheeseDictionary[cheese]["name"]
def addProduct():
global cheeseDicitonary
correct = 0
idInput = ""
dateInput = ""
lifeInput = ""
nameinput = ""
while correct != 1:
idInput = raw_input("Please enter the ID of the cheese to be added. ")
if cheeseDictionary.has_key(idInput):
print ("This ID already exists. Please try again.")
correct = 0
else:
newID = idInput
correct = 1
dateInput = raw_input("Please enter the date of the cheese to be added in the format dd/mm/yyyy. ")
lifeInput = raw_input("Please enter the life of the cheese to be added in days. ")
nameInput = raw_input("Please enter the name of the cheese to be added. ")
cheeseDictionary[idInput] = {"date":dateInput, "life":lifeInput, "name":nameInput}
def checkProduct(cheeseDictionary):
dateCheck = raw_input("Please enter the date in the format dd/mm/yyyy: ")
for cheese in cheeseDictionary:
I know I need to change the dates store din the dictionary into the date time format but I am unsure how to do this. Thanks for any advice given. :)
If I understand correctly, you need to transform strings representing dates in the format "dd/mm/yyyy" into datetime objects?
If so, you should use the datetime.strptime method. For example:
from datetime import datetime
d = datetime.strptime("28/03/2011", "%d/%m/%Y")
print repr(d)
This prints:
datetime.datetime(2011, 3, 28, 0, 0)
In order to parse a date string into a datetime object, you can use the strptime method:
http://www.tutorialspoint.com/python/time_strptime.htm
Almost everything you ever need to know about Python can be found in the documentation. Here is the documentation of datetime:
http://docs.python.org/library/datetime.html
As for date maths (addition and subtraction), they can be done by adding or subtracting a timedelta object to/from a datetime object. Here are the allowed operations:
datetime2 = datetime1 + timedelta
datetime2 = datetime1 - timedelta
timedelta = datetime1 - datetime2
datetime1 < datetime2
All the details can be found on the documentation page in the link above.
And here is another little tutorial on date maths:
http://phr0stbyte.blogspot.com/2008/08/python-datetime-math.html
For the heck of it I've done a pretty comprehensive object-oriented rewrite:
import datetime
class Date(object):
def __init__(self, s):
if isinstance(s, Date):
self.date = s.date
elif isinstance(s, datetime.date):
self.date = s
else:
self.date = datetime.datetime.strptime(s, "%d/%m/%Y")
def __add__(self, val):
if isinstance(val, Life):
val = val.life
elif not isinstance(val, datetime.timedelta):
val = datetime.timedelta(val)
return self.__class__(self.date + val)
def __cmp__(self, val):
return (self.date - val.date).days
def __str__(self):
return self.date.strftime("%d/%m/%Y")
class Life(object):
def __init__(self, s):
if isinstance(s, Life):
self.life = s.life
elif isinstance(s, datetime.timedelta):
self.life = s
else:
self.life = datetime.timedelta(days=int(s))
def __str__(self):
return str(self.life.days)
class Product(object):
FMT = "{0:10} {1:10} {2:24}".format
def __init__(self, date, life, name):
super(Product,self).__init__()
self.date = Date(date)
self.life = Life(life)
self.name = str(name).strip()
def __str__(self):
return Product.FMT(self.date, self.life, self.name)
def expires(self):
return Date(self.date + self.life)
#classmethod
def get(cls):
date = getClass(Date, "Please enter the date (DD/MM/YYYY): ")
life = getClass(Life, "Please enter the life (in days): ")
name = raw_input("Please enter the name of the cheese: ")
return cls(date, life, name)
def vals(self):
return self.date, self.life, self.name
class FileOf(object):
def __init__(self, cls):
self.data = {}
self.cls = cls
def loadFile(self, fname, mode='r', sep=':'):
_data = self.data
_cls = self.cls
with open(fname, mode) as inf:
for line in inf:
try:
items = line.strip().split(sep)
id = items.pop(0)
_data[id] = _cls(*items)
except ValueError, e:
print(e)
return self
def saveFile(self, fname, mode='w', sep=':', eol='\n', key=None):
_data = self.data
keys = _data.keys()
keys.sort(key=key)
with open(fname, mode) as outf:
for id in keys:
outf.write(str(id)+sep)
outf.write(sep.join(str(v) for v in _data[id].vals()))
outf.write(eol)
return self
def addNew(self):
id = getNewKey(self.data, "Please enter the new ID: ")
obj = getClass(self.cls)
self.data[id] = obj
return self
def printAll(self, key=None):
_data = self.data
_cls = self.cls
ID = "{0:4} ".format
print ID("id") + _cls.FMT("Date", "Life", "Name")
keys = _data.keys()
keys.sort(key=key)
for id in keys:
print ID(id) + _cls.FMT(*(_data[id].vals()))
return self
def filter(self, filterFn):
newFile = FileOf(self.cls)
newFile.data = {id:item for id,item in self.data.iteritems() if filterFn(id, item)}
return newFile
def getNewKey(keys, msg='', keytype=str):
"Prompt for a key not already in keys"
while True:
key = keytype(raw_input(msg))
if key in keys:
print("This key already exists. Please try again.")
else:
return key
def getClass(cls, *args, **kwargs):
"Return a new instance of given class; prompt for required values"
if hasattr(cls, 'get'):
# if the class knows how to 'get' itself, let it
return cls.get(*args, **kwargs)
else:
# otherwise we assume the class knows how to init itself from a string
while True:
s = raw_input(*args)
try:
return cls(s, **kwargs)
except ValueError, e:
print(e)
def getExpired(cheeses, asOf=None):
asOf = Date(asOf) if asOf else getClass(Date, "Please enter expiration test date (DD/MM/YYYY): ")
return cheeses.filter(lambda id,obj: obj.expires() <= asOf)
def main():
cheeses = FileOf(Product).loadFile('cheesefile.txt')
cheeses.printAll()
cheeses.addNew()
expiredA = getExpired(cheeses) # prompt for expiration date
expiredB = getExpired(cheeses, "12/3/2011") # use given date
print("The expired items are:")
expiredB.printAll()
cheeses.saveFile('cheesefile.txt')
if __name__=="__main__":
main()
and a sample cheesefile.txt file:
ab:03/01/2011:10:brie
ac:03/01/2001:20:camembert
de:01/03/2011:30:brie
fg:01/03/2011:1:blink and it's gone
hi:01/05/2011:200:hard white cheddar
jkl:01/04/2011:60:jarlsberg