Simplifying Python program
Question
I'm a complete beginner in Python and programming in general. I made a program for Spotify's Best Before puzzle. It was accepted. I have looked a litle around on internet and looked at other solutions to the problem, and everyone I have seen have importet several modules, inclusive the Calendar module. I understand this is probably a good solution, but I wanted to make everything myself as a practice.
I would really appreciate all tips and hint, but mainly without haveing to import code. It's primarily the printer(a)
and det dataMaker()
that needs modification.
normYear = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
leapYear = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
answerList = []
u''' Check if any of the integers are years '''
def yearCheck():
for x in xrange(0, 3):
a = dataList[x]
if len(a) > 2:
if not len(a) == 4 and int(a) in xrange(2000,3000):
if int(a) in xrange(100,1000):
dataList[x] = int(a) + 2000
else:
print data + u" is illegal"
u''' Make integers and sort '''
def integer():
for x in xrange(0, 3):
dataList[x] = int(dataList[x])
dataList.sort()
u''' Check for possible leap years '''
def leapYears():
global leapList
leapList = []
for x in xrange(0, 3):
if dataList[x] % 4 == 0:
if dataList[x] % 100 == 0:
if dataList[x] % 400 == 0:
leapList.append(x)
else:
leapList.append(x)
u''' Changes year type '''
def defYear(a):
global xYear
if a in leapList:
xYear = leapYear
else:
xYear = normYear
u''' Printer '''
def printer(a):
if dataList[a] < 2000:
dataList[a] += 2000
year = dataList[a]
del dataList[a]
if not dataList[0] == 0:
month = dataList.pop(0)
day = dataList.pop(0)
answerList.append(unicode(year))
answerList.append(unicode(u'%02d' % month))
answerList.append(unicode(u'%02d' % day))
print u'-'.join(answerList)
else:
print data + u" is illegal"
u''' Looks for legal dates, first [Y<M<D] then [M<Y<D] then [M,D,Y] '''
def dateMaker():
for x in xrange(0,4):
defYear(x)
if x == 0:
if dataList[1] <= 12 and dataList[2] <= xYear[dataList[1]-1]:
printer(x)
break
elif x == 1:
if dataList[0] <= 12 and dataList[2] <= xYear[dataList[0]-1]:
printer(x)
break
elif x == 2:
if dataList[0] <= 12 and dataList[1] <= xYear[dataList[0]-1]:
printer(x)
break
else:
print data + u" is illegal"
u''' Program '''
data = raw_input()
dataList = data.split(u"/")
yearCheck()
integer()
leapYears()
dateMaker()
Solution
I'd consider trying to re-implement this using a class. Even as an exercise this would likely be good practice.
You should also consider:
- Taking advantage of the iterable nature of strings, lists, etc. You appear to be thinking about for loops the way one might expect to see in C.
- Trying to get away from nesting your if statements. It's difficult to follow the logic. (see: http://eflorenzano.com/blog/2012/01/01/reducing-code-nesting/)
I'd consider implementing your first 2 functions as follows (there's likely further ways to improve it):
data = '8/5/32'
data_list = data.split('/')
def yearCheck(data_list):
# Years may be truncated to two digits and may in that case
# also omit the leading 0 (if there is one), so 2000 could
# be given as "2000", "00" or "0" (but not as an empty string).
# Further examples:
# if 2099, could be given as 99
# if 2005, could be given as 05 or 5
# 199 will not happen i.e. doesn't say that years may be
# truncated to three digits
for index, item in enumerate(data_list):
if len(item) > 4:
# e.g. 30000
print item, '- Data is invalid'
return
if len(item) == 4 and int(item) not in xrange(2000, 3000):
# e.g. 3015
print item, '- Data is invalid'
return
if len(item) == 3:
# e.g. 199
print item, '- Data is invalid'
return
if len(item) < 3 and int(item) in xrange(32, 100):
data_list[index] = int(item) + 2000
return data_list
def integer(data_list):
int_data_list = [int(item) for item in data_list]
return int_data_list.sort()
yearCheck(data_list)
integer(data_list)
print data_list