这是一个相当多的代码,但如果你跟踪它直到你了解它的工作原理,你会学到很多东西。在
首先,我们需要取一个类标记并将其转换为点。您可以将其写成13if的级联,但我喜欢数据驱动的方法:import bisect
def grade_points(pct):
grade = [ 0, 50, 53, 57, 60, 63, 67, 70, 73, 77, 80, 85, 90]
points = [0.0, 0.7, 1.0, 1.3, 1.7, 2.0, 2.3, 2.7, 3.0, 3.3, 3.7, 4.0, 4.0]
if 0 <= pct <= 100:
# find the highest grade <= pct
idx = bisect.bisect_right(grade, pct) - 1
# return the corresponding grade-point
return points[idx]
else:
raise ValueError('pct value should be in 0..100, not {}'.format(pct))
下一步,我们需要一个学生类,以便于跟踪每个学生的数据
^{pr2}$
所以你可以创建一个学生,然后找到她的GPA,如下所示:sally = Student('ab2773', 'S Atkins', [
('MAT3000', 4, 81.0),
('ENG3010', 4, 85.0)
])
print sally # ' ab2773 S Atkins 3.85'
现在我们需要能够流式传输学生的文件。从OOP的角度来看,这有点痛苦,因为Student对象实际上不需要知道任何关于File对象的信息,反之亦然,更重要的是因为我们希望将您升级到更好的文件格式-学生对象绝对不需要知道多个不兼容的文件类型。在
我通过子类化Student来实现这一点;我编写了Student.__init__方法,这样我就可以来回转换,而不必为子类重写它,所以子类只知道如何将自己转换成你讨厌的文件格式class NastyFileStudent(Student):
@classmethod
def from_strings(cls, strings):
if len(strings) > 3 and len(strings) == 3 + int(strings[2])*3:
codes = strings[3::3]
hours = map(int, strings[4::3])
grades = map(float, strings[5::3])
return Student(strings[0], strings[1], zip(codes, hours, grades))
else:
# not enough data returned - probably end of file
return None
def __str__(self):
data = [self.id, self.name, str(len(self.classes))] + [str(i) for c in self.classes for i in c]
return '\n'.join(data)
文件只知道它有学生的数据,但对内容一无所知class NastyFile(object):
START = 'Start'
END = 'End'
@staticmethod
def _read_until(endfn, seq):
is_end = endfn if callable(endfn) else lambda s: s==endfn
data = []
for s in seq:
if is_end(s):
break
else:
data.append(s)
return data
def __init__(self, name, mode='r'):
self.name = name
self.mode = mode
self._f = open(name, mode)
self.lines = (ln.strip() for ln in self._f)
def __del__(self):
self._f.close()
def __iter__(self):
return self
def next(self):
_ = NastyFile._read_until(NastyFile.START, self.lines)
strings = NastyFile._read_until(NastyFile.END, self.lines)
student = NastyFileStudent.from_strings(strings)
if student is None:
raise StopIteration()
else:
return student
def read(self):
return list(self)
def write(self, s):
if not hasattr(s, '__iter__'):
s = [s]
for student in s:
self._f.write('{}\n{}\n{}\n'.format(NastyFile.START, str(NastyFileStudent(student)), NastyFile.END))
现在我们可以读写学生档案了>>> students = NastyFile('student_records.txt').read()
>>> for s in students:
... print s
eh2727 Josh D 4.0
ah2718 Mary J 4.0
>>> students.append(sally)
>>> students.sort(key=lambda s: s.name.rsplit(None,1)[-1]) # sort by last name
>>> for s in students:
... print s
ab2773 S Atkins 3.85
eh2727 Josh D 4.0
ah2718 Mary J 4.0
>>> newfile = NastyFile('new_records.txt', 'w')
>>> newfile.write(students)
>>> for i,s in enumerate(NastyFile('new_records.txt'), 1):
... print '{:>2}: {}'.format(i, s)
1: ab2773 S Atkins 3.85
2: eh2727 Josh D 4.0
3: ah2718 Mary J 4.0