CSVファイルまたはDBからオブジェクト(タスク)を読み取るプログラムがあります。どちらのソースにも、使用後にリソースへのアクセスを明示的に閉じる必要があるという共通点があります。
CSVクラスとDBクラスの両方を反復可能にするアプローチに従ったので、それらを反復するとタスクが返されます。これはそれらを使用するのに便利ですが、私はそれがきれいであるとは確信していません、そして私は次の質問があります:
- ファイルまたはDBにアクセスするための最良の方法は何ですか?そのためにコンストラクターを使用していますが、マルチスレッドなどについてはよくわかりません...
- リソース(ファイル、カーソル)を閉じるための最良の方法は何ですか。外部オブジェクトがアクセスが完了したことを通知する必要がありますか、それともCSVまたはDBオブジェクトがファイルの最後にいることを検出して、ファイルを閉じる必要がありますか?
私はこれを正しく行っているかどうかわかりません(これはシングルランで機能しますが、これはWebサイトに接続されるため、複数のアクセス権があります)
class CSV(AbstractDAO):
def __init__(self, sourcePath):
self.sourcePath = sourcePath
self.csvFile = codecs.open(sourcePath, 'rb', 'UTF-8')
def __iter__(self):
return self
def next(self):
return self._buildTaskFromLine(self.csvFile.next())
def deleteAllTasks(self):
pass
def loadTask(self, taskID):
csvFile = codecs.open(self.sourcePath, 'rb', 'UTF-8')
for line in csvFile:
taskValues = line.split(";")
if taskValues[0] == unicode(taskID):
return self._buildTaskFromLine(line)
else:
return None
def saveTask(self, task):
pass
def loadPredecessorsID(self, task):
csv = codecs.open(self.sourcePath, 'rb', 'UTF-8')
for line in csv:
taskValues = line.split(";")
if taskValues[0] == unicode(task.id):
return taskValues[2].split(",")
return None
def _buildTaskFromLine(self, line):
taskValues = line.split(";")
taskID = taskValues[0]
taskName = taskValues[1]
taskAncestors = taskValues[2]
taskDuration = int(taskValues[3])
return Task(taskID, taskName, taskDuration)
これがDBの実装です
class SQLite(AbstractDAO):
def __init__(self, sourcePath):
self.connection = sqlite3.connect(sourcePath)
self.cursor = None
def __iter__(self):
self.cursor = self.connection.cursor()
self.cursor.execute("select * from Tasks")
return self
def next(self):
if self.cursor is not None:
row = self.cursor.fetchone()
if row is None:
self.cursor.close()
raise StopIteration
else:
return self._buildTaskFromRow(row)
def deleteAllTasks(self):
cursor = self.connection.cursor()
cursor.execute("delete from Tasks")
self.connection.commit()
cursor.close()
def loadTask(self, id):
cursor = self.connection.cursor()
param = (id,)
cursor.execute("select * from Tasks t where t.id = ? ", param)
taskRow = cursor.fetchone()
task = self._buildTaskFromRow(taskRow)
cursor.close()
return task
def saveTask(self, task):
cursor = self.connection.cursor()
param = (task.id,)
cursor.execute("select * from Tasks t where t.id = ? ", param)
taskRow = cursor.fetchone()
if taskRow is None:
param = (task.id, task.name, task.duration)
cursor.execute("insert into Tasks values (?,?,?)", param)
self.connection.commit()
cursor.close()
else:
param = (task.id, task.name, task.duration)
cursor.execute("update Tasks \
set description = ?, duration = ? \
where id = ? ", param)
self.connection.commit()
cursor.close()
def loadPredecessors(self, task):
pass
def _buildTaskFromRow(self, row):
taskId = row[0]
taskName = row[1]
taskDuration = row[2]
return Task(taskId, taskName, taskDuration)
最後に、上記のコードは、たとえばma TaskTreeによってこのように呼び出されます(これはすべてのタスクを保持するオブジェクトです)
def loadTreeFrom(self, source, sourcePath):
if source not in ('CSV', 'DB'):
raise AttributeError('Unknown source : supported sources are CSV or DB')
dao = None
if source == 'CSV':
dao = CSV(sourcePath)
elif source == "DB":
dao = SQLite(sourcePath)
#populate the tasks first
for task in dao:
self.tasks[unicode(task.id)] = task
# then populate the dependencies
for item in self.tasks.iteritems():
ancestorsID = dao.loadPredecessorsID(item[1])
self.addDependencies(item[1], ancestorsID)