3

TkInterを利用してユーザー入力に基づいて線を引く非常に基本的なスクリプトを作成しようとしています。ユーザーは、パラメーターを使用して描画された線を決定し、コマンドラインからスクリプトを実行します。

可能なコマンドは次のとおりです。

(# signifies any whole number the user chooses)

P #   (selects a pen to draw with)
D     (pen down / starts drawing)
N #   (moves the pen north # increments)
E #   (moves the pen east # increments)
S #   (moves the pen south # increments)
W #   (moves the pen west # increments)
U     (pen up / stops drawing)

例:

Parser.py P 3 D N 4 E 2 S 4 W 2 U

上記の例では、背の高い長方形を描画します。

私は、すべての引数を実行し、上記の引数とその順序に基づいて辞書からメソッドを実行するsys.argvの基本的なパーサーを作成しようとしています。

sys.argvを実行し、引数に基づいて配列を作成するコードを次に示します(エラーチェックを追加するので、今は幸せなシナリオを想定してください)。

class JoshSourceReader(object):
    """ responsibe for providing source text for parsing and drawing
        Initiates the Draw use-case.
        Links to a parser and passes the source text onwards """
    def __init__(self):
        self.parser = JoshParser()
        self.source = []
    def go(self):
        i = 1
        x = len(sys.argv)
        while i < x:
            if sys.argv[i]=="P":
                self.source.append("P " + str(sys.argv[i + 1]))
                i += 2
            elif sys.argv[i]=="D":
                self.source.append("D")
                i += 1
            elif sys.argv[i]=="N":
                self.source.append("N " + str(sys.argv[i + 1]))
                i += 2
            elif sys.argv[i]=="E":
                self.source.append("E " + str(sys.argv[i + 1]))
                i += 2
            elif sys.argv[i]=="S":
                self.source.append("S " + str(sys.argv[i + 1]))
                i += 2
            elif sys.argv[i]=="W":
                self.source.append("W " + str(sys.argv[i + 1]))
                i += 2
            elif sys.argv[i]=="U":
                self.source.append("U")
                i += 1
        self.parser.parse(self.source)

したがって、上記の例から生成される配列は次のようになります。

source=['P 3', 'D', 'N 4', 'E 2', 'S 4', 'W 2', 'U']

だから私の質問はこれです:上記の配列で動作し、配列要素に基づいてメソッドを1つずつ実行するメソッドの効率的な辞書を作成するにはどうすればよいですか?一部のメソッドはプロパティ(数)を渡す必要があり、一部は渡さないという事実のために、それが可能かどうかさえ疑問に思い始めています。この問題に光を当てることができる人はいますか?

また、私はPythonを初めて使用することを忘れないでください。

編集:私は1つの重要な情報を忘れました。N、E、S、Wはすべて同じメソッドを参照しますが、毎回異なる引数を取ります。メソッドは次のとおりです(まだ描画していません):

def drawLine(self, direction, distance):
    print("drawing line of length " + str(distance) + " at "
          + str(direction))

したがって、「S 3」を使用してこのメ​​ソッドを呼び出す場合は、次のように呼び出します。

drawer.drawLine(180, 3)

また、「W 1」を使用して呼び出す場合は、次のように呼びます。

drawer.drawLine(270, 1)
4

5 に答える 5

2

関数にデフォルトの引数を与えることができます。だから、ちょうどこのようなことをしてください:

parsedict = {}
def func_P(times=0):
    #do whatever here
parsedict["P"] = func_P
#repeat however many times
for x in source:
    splitx = x.split(" ")
    if len(splitx) >= 2:
        parsedict[splitx[0]](splitx[1])
    else:
        parsedict[splitx[0]]()

他に何か必要な場合は、コメントしてください。動作するはずですが、テストしませんでした。ラムダ関数を使用することもできますが、Pythonは初めてだとおっしゃっていたので、関数を手動で定義しました。

于 2012-08-02T01:03:04.997 に答える
1

これは少しトリッキーな問題であり、適切な解析フレームワークを使用することでおそらく最もよく解決されます。私は通常、このようなことのためにpyparsingをお勧めします。ただし、これは外部フレームワークを使用しないソリューションです。

やや醜いですが、基本的には、入力文字列、たとえば「P1」を演算と整数に解析します。ディクショナリには、呼び出すメソッドと、メソッドに渡される追加のパラメータ(ケースのdrawLine()場合)が含まれています。

クラスを使用せずにこれを実行しましたが、selfすべてに最初のパラメーターとして追加するだけで、それを整理する必要があります。

def selectPen(pen):
    print('called selectPen with pen', pen)

def penDown():
    print('called penDown')

def drawLine(direction, length):
    print('called drawLine with direction', direction, 'and length', length)

def penUp():
    print('called penUp')

def parseSource(source):
    tempSource = [op.split(' ') for op in source]
    parsedSource = []
    for op in tempSource:
        parsedOp = []
        for i, el in enumerate(op):
            if i == 0:
                parsedOp.append(el)
            else:
                try:
                    parsedOp.append(int(el))
                except ValueError:
                    parsedOp.append(el)
        parsedSource.append(tuple(parsedOp))

    return parsedSource

def dispatch(parsedSource):
    opDict = {'P':(selectPen,), 'D':(penDown,), 'N': (drawLine, 0), 'S':(drawLine, 180), 
    'E': (drawLine, 90), 'W': (drawLine, 270), 'U': (penUp,)}

    for op in parsedSource:
        methodName = op[0]
        methodToCall = opDict[methodName][0] 
        args = op[1:]
        if len(opDict[methodName])>1:
            args = opDict[methodName][1:] + args

        methodToCall(*args)

if __name__ == '__main__':
    source=['P 3', 'D', 'N 4', 'E 2', 'S 4', 'W 2', 'U']
    parsedSource = parseSource(source)
    dispatch(parsedSource)
于 2012-08-02T03:10:48.737 に答える
0

次のようなことを行うことができます。この場合、辞書は「コマンド」をそれらが取る引数の数にマップします。

argdict = {
    'P': 1,
    'D': 0,
    'N': 1,
    'E': 1,
    'S': 1,
    'W': 1,
    'U': 0
}

args = sys.argv[1:]
source = []

while args:
    command = [args.pop(0)]
    nargs = argdict[command[0]]
    command.extend(args[:nargs])
    args = args[nargs:]
    source.append(' '.join(command))

print source

サンプル入力を指定すると、次のようなリストが作成されます。

['P 3', 'D', 'N 4', 'E 2', 'S 4', 'W 2', 'U']
于 2012-08-02T01:10:50.330 に答える
0
class Painter(object):                                                            
    pencil_width = 1
    is_drawing = False

    def set_pencil(self, width=1):
        self.pencil_width = int(width)
    P = set_pencil

    def draw_north(self, blocks=1):
        if self.is_drawing:
            ...
    N = draw_north

    def process_command(self, str_):
        func_name = str_.split(' ')[0]
        args = str_.split(' ')[1:]
        try:
            func = getattr(self, func_name)
        except AttributeError:
            raise ValueError('Method %s does not exists'
                              % func_name)
        func(*args)


painter = Painter()
for command in source:
    painter.process_command(command)
于 2012-08-02T01:14:17.283 に答える
0

これは答えではありませんが、コードに関する拡張コメントです。過去にCまたはCのような言語(Java、JavaScriptなど)で作業したことがあると思います。あなたはsys.argv このように繰り返しています:

i = 1
x = len(sys.argv)
while i < x:
    if sys.argv[i]=="P":

Pythonでは、リストを反復処理する簡単な方法があります。例えば:

for arg in sys.argv:
    if arg == 'P':
于 2012-08-02T01:02:47.410 に答える