我应该如何将这个巨大的功能分解成更小的部分
How should I break down this huge function into smaller parts
我正在尝试理解 Python 中好的设计模式,但我想不出一种方法可以将这个巨大的功能分解成更小的部分,而不会使代码混乱、过于复杂或简单丑陋。
我不想通过发布整个文件来扰乱我的问题,我的意思是这个函数本身已经非常大了。但是 class 只有两个方法: parse_midi() 和 generate_midi(file_name, file_length).
音高、速度、增量、持续时间和间隔都是马尔可夫链对象。 MarkovChain 是一个简单的 class,具有以下方法:add_event(event)、generate_markov_dictionary() 和 get_next_event(previous_event)。 MarkovChain.src_events 是生成马尔可夫链的事件列表。它是一阶马尔可夫链的简单实现。
def parse_midi(self):
# on_notes dictionary holds note_on events until corresponding note_of event is encountered
on_notes = {}
time = 0
previous_pitch = -1
tempos = []
delta = 0
for message in self.track_in:
time += message.time
delta += message.time
# There are also MetaMessages in a midi file, such as comments, track names, etc.
# We just ignore them
if isinstance(message, mido.Message) and message.type in ["note_on", "note_off"]:
# some midi files use note_on events with 0 velocity instead of note_oof events
# so we check if velocity > 0
if message.velocity > 0 and message.type == "note_on":
on_notes[message.note] = time
self.pitches.add_event(message.note)
self.velocities.add_event(message.velocity)
self.deltas.add_event(delta)
delta = 0
if previous_pitch == -1:
self.intervals.add_event(0)
else:
self.intervals.add_event(message.note - previous_pitch)
else:
# KeyError means note_off came without a prior associated note_on event!"
# Just ignore them
with ignored(KeyError):
self.durations.add_event(time - on_notes[message.note])
del on_notes[message.note]
previous_pitch = message.note
# Tempo might be many tempo changes in a midi file, so we store them all to later calculate an average tempo
elif message.type == "set_tempo":
tempos.append(message.tempo)
elif message.type == "time_signature":
self.time_signature = self.TimeSignature(message.numerator, message.denominator,
message.clocks_per_click, message.notated_32nd_notes_per_beat)
# some tracks might be aempty in a midi file. For example they might contain comments as track name, and no note events
if len(self.pitches.src_events) == 0:
print("There are no note events in track {}!\n"
"The file has {} tracks. Please try another one.".format(self.selected_track, self.num_tracks))
exit(1)
# a midi file might not contain tempo information at all. if it does, we calculate the average
# else we just assign a default tempo of 120 bpm
try:
self.average_tempo = int(sum(tempos) / len(tempos))
except ZeroDivisionError:
self.average_tempo = mido.bpm2tempo(120)
事实证明这个方法没有多少重构,但是,可以找到回答这个问题的最佳尝试here
我正在尝试理解 Python 中好的设计模式,但我想不出一种方法可以将这个巨大的功能分解成更小的部分,而不会使代码混乱、过于复杂或简单丑陋。
我不想通过发布整个文件来扰乱我的问题,我的意思是这个函数本身已经非常大了。但是 class 只有两个方法: parse_midi() 和 generate_midi(file_name, file_length).
音高、速度、增量、持续时间和间隔都是马尔可夫链对象。 MarkovChain 是一个简单的 class,具有以下方法:add_event(event)、generate_markov_dictionary() 和 get_next_event(previous_event)。 MarkovChain.src_events 是生成马尔可夫链的事件列表。它是一阶马尔可夫链的简单实现。
def parse_midi(self):
# on_notes dictionary holds note_on events until corresponding note_of event is encountered
on_notes = {}
time = 0
previous_pitch = -1
tempos = []
delta = 0
for message in self.track_in:
time += message.time
delta += message.time
# There are also MetaMessages in a midi file, such as comments, track names, etc.
# We just ignore them
if isinstance(message, mido.Message) and message.type in ["note_on", "note_off"]:
# some midi files use note_on events with 0 velocity instead of note_oof events
# so we check if velocity > 0
if message.velocity > 0 and message.type == "note_on":
on_notes[message.note] = time
self.pitches.add_event(message.note)
self.velocities.add_event(message.velocity)
self.deltas.add_event(delta)
delta = 0
if previous_pitch == -1:
self.intervals.add_event(0)
else:
self.intervals.add_event(message.note - previous_pitch)
else:
# KeyError means note_off came without a prior associated note_on event!"
# Just ignore them
with ignored(KeyError):
self.durations.add_event(time - on_notes[message.note])
del on_notes[message.note]
previous_pitch = message.note
# Tempo might be many tempo changes in a midi file, so we store them all to later calculate an average tempo
elif message.type == "set_tempo":
tempos.append(message.tempo)
elif message.type == "time_signature":
self.time_signature = self.TimeSignature(message.numerator, message.denominator,
message.clocks_per_click, message.notated_32nd_notes_per_beat)
# some tracks might be aempty in a midi file. For example they might contain comments as track name, and no note events
if len(self.pitches.src_events) == 0:
print("There are no note events in track {}!\n"
"The file has {} tracks. Please try another one.".format(self.selected_track, self.num_tracks))
exit(1)
# a midi file might not contain tempo information at all. if it does, we calculate the average
# else we just assign a default tempo of 120 bpm
try:
self.average_tempo = int(sum(tempos) / len(tempos))
except ZeroDivisionError:
self.average_tempo = mido.bpm2tempo(120)
事实证明这个方法没有多少重构,但是,可以找到回答这个问题的最佳尝试here