在while循环中有效地构造“switch”语句

时间:2014-03-05 18:18:42

标签: python python-2.7

这是我的问题的简约视图(删除所有不必要的细节)。从本质上讲,它是一个“汇编代码”执行者:

while(self.pc < len(self.memory)):
  instruction = [int(i) for i in str(self.memory[self.pc])]

  #simulated "switch" statement.
  def switch(Opcode):
    op1 = getOperand(instruction[1], instruction[2])
    op2 = getOperand(instruction[3], instruction[4])
    def add():
      if op1['mode'] = self.modes['gpr']:
        self.gpr[op1['gpr']] = op1['opValue'] + op2['opValue']
      else:
        self.memory[op1['opAddress']] = op1['opValue'] + op2['opValue']
      self.clock += self.clockSpeed['add']
    def subtract():
      if op1['mode'] = self.modes['gpr']:
        self.gpr[op1['gpr']] = op1['opValue'] - op2['opValue']
      else:
        self.memory[op1['opAddress']] = op1['opValue'] - op2['opValue']
      self.clock += self.clockSpeed['subtract']
    def invalid():
      raise ValueError('invalid Opcode in instruction: {}'.format(instruction) 
    return {
      0: add,
      1: subtract,
      "invalid": invalid
    }.get(Opcode, "invalid")()

  switch(instruction[0])
  self.pc += 1

当我使用timeit module使用大约40个元素的简单数组(稍微复杂的方法,但不多)运行此程序时,它确实需要相当长的时间:

print 'timing execution of execute: ', timeit.timeit('vm.CPUexecuteProgram()', setup="from __main__ import OS; vm=OS(); vm.AbsoluteLoader('../assembly_code/assemble_code.exe')")

timing execution of execute: 0.673621892929

我相信这个定义在每次迭代时都会“重新制作”。是否会有更有效的方式遵循此处显示的相同“模式”?如果可能的话,我想避免使用if / elif / else,以使其更具可读性。

4 个答案:

答案 0 :(得分:1)

此:

if op1['mode'] = self.modes['gpr']:

需要:

if op1['mode'] == self.modes['gpr']:

进行所有比较。双重等于“确实是等于对吗?”。单一的等于是“从右向左分配,然后向右回”。

答案 1 :(得分:1)

是的,您的代码会在每条指令上创建所有函数和整个字典。在您的实际代码中(假设有40个不同的操作码),这意味着每条指令执行至少42个对象实例化(每个操作码1个,switch,dict)。您可以简单地将循环不变部分(创建addsub,...;创建操作码 - >&gt;函数dict)拉出循环,生成op1op2参数,并将循环减少到:

while self.pc < len(self.memory):
    instruction = ...
    op1 = ...
    op2 = ...
    implementations[instruction](op1, op2)
    self.pc += 1

这应该在相当一部分时间内减少。可能有其他地方可以优化一点,但因为那不是你真正的代码而且它很邋(几个语法错误,有些部分看起来不对)我会避免猜测。

答案 2 :(得分:1)

重新排列:

def add(op1, op2):
  if op1['mode'] = self.modes['gpr']:
    self.gpr[op1['gpr']] = op1['opValue'] + op2['opValue']
  else:
    self.memory[op1['opAddress']] = op1['opValue'] + op2['opValue']
  self.clock += self.clockSpeed['add']

def subtract(op1, op2):
  if op1['mode'] = self.modes['gpr']:
    self.gpr[op1['gpr']] = op1['opValue'] - op2['opValue']
  else:
    self.memory[op1['opAddress']] = op1['opValue'] - op2['opValue']
  self.clock += self.clockSpeed['subtract']

def invalid(op1, op2):
  raise ValueError('invalid Opcode in instruction: {}'.format(instruction)

switch = {0: add, 1: subtract} 
while (self.pc < len(self.memory)):
  instruction = [int(i) for i in str(self.memory[self.pc])]
  Opcode = instruction[0]

  op1 = getOperand(instruction[1], instruction[2])
  op2 = getOperand(instruction[3], instruction[4])
  switch.get(Opcode, invalid)(op1, op2)
  self.pc += 1

这样每次都不会重新定义所有方法。

答案 3 :(得分:1)

import operator

class Something(object):
    _operations =  {
        0: lambda self, instruction: self._execute("add", instruction),
        1: lambda self, instruction: self._execute("subtract", instruction),
        "invalid": lambda self, instruction: self_invalid(instruction)
        }
    _operators = {
        "add": operator.add,
        "substract": operator.sub
        }

    def _execute(self, operation, instruction):
        op1 = getOperand(instruction[1], instruction[2])
        op2 = getOperand(instruction[3], instruction[4])
        operator = self._operators[operation]
        val = operator(op1, op2)
        if op1['mode'] == self.modes['gpr']:
            self.gpr[op1['gpr']] = val
        else:
            self.memory[op1['opAddress']] = val
        self.clock += self.clockSpeed[operation]

    def _invalid(self, instruction):
        raise ValueError(
            'invalid Opcode in instruction: {}'.format(instruction)
            )

    def _switch(self, instruction):
        return self._operations.get(instruction[0], self._invalid)(self, instruction)

    def whatever(self):
        while self.pc < len(self.memory):
            instruction = [int(i) for i in str(self.memory[self.pc])]
            self._switch(instruction)
            self.pc += 1