goto
特定のコード行にジャンプできるようにするために、Pythonに同等のものはありますか?
21 に答える
いいえ、Python はラベルと goto をサポートしていません。これは (高度に) 構造化されたプログラミング言語です。
Python では、最初のクラスの関数を使用して、goto で実行できるいくつかのことを実行できます。例えば:
void somefunc(int a)
{
if (a == 1)
goto label1;
if (a == 2)
goto label2;
label1:
...
label2:
...
}
次のようにPythonで実行できます。
def func1():
...
def func2():
...
funcmap = {1 : func1, 2 : func2}
def somefunc(a):
funcmap[a]() #Ugly! But it works.
確かに、これは goto の代わりとして最適な方法ではありません。しかし、goto で何をしようとしているのかを正確に知らなければ、具体的なアドバイスをすることは困難です。
@アスコボル:
あなたの最善の策は、それを関数で囲むか、例外を使用することです。関数の場合:
def loopfunc():
while 1:
while 1:
if condition:
return
例外について:
try:
while 1:
while 1:
raise BreakoutException #Not a real exception, invent your own
except BreakoutException:
pass
例外を使用してこのようなことを行うと、別のプログラミング言語を使用している場合、少しぎこちなく感じるかもしれません。しかし、例外を使用するのが嫌いなら、Python はあなたのための言語ではないと私は主張します。:-)
私は最近、Python で有効にする関数デコレータを作成しました。goto
from goto import with_goto
@with_goto
def range(start, stop):
i = start
result = []
label .begin
if i == stop:
goto .end
result.append(i)
i += 1
goto .begin
label .end
return result
なぜそのようなことをしたいのか、私にはわかりません。そうは言っても、私はそれについてあまり深刻ではありません。しかし、この種のメタ プログラミングは Python で、少なくとも CPython と PyPy で実際に可能であり、他の人のようにデバッガ API を誤用するだけではないことを指摘したいと思います。ただし、バイトコードをいじる必要があります。
これは、公式の python Design and History FAQで見つけました。
なんで後藤がないの?
例外を使用して、関数呼び出し間でも機能する「構造化された goto」を提供できます。例外は、C、Fortran、およびその他の言語の「go」または「goto」構造のすべての合理的な使用法を便利にエミュレートできると多くの人が感じています。例えば:
class label(Exception): pass # declare a label
try:
...
if condition: raise label() # goto label
...
except label: # where to goto
pass
...
これにより、ループの途中にジャンプすることはできませんが、通常は goto の乱用と見なされます。控えめに使用してください。
これが公式の FAQ にも記載されており、すばらしい解決策のサンプルが提供されていることは非常に素晴らしいことです。コミュニティがこのように扱っているので、私はPythonが本当に好きgoto
です;)
コメントからの提案を使用して@ascobol
質問に答えるには:@bobince
for i in range(5000):
for j in range(3000):
if should_terminate_the_loop:
break
else:
continue # no break encountered
break
ブロックのインデントelse
は正しいです。else
このコードは、ループPython構文の後にあいまいなものを使用しています。Pythonがforループとwhileループの後に「else」を使用するのはなぜですか?を参照してください。
「goto」のようなステートメントを python に追加することは、技術的に実行可能です。「dis」モジュールと「new」モジュールを使用します。どちらも Python バイト コードのスキャンと変更に非常に役立ちます。
実装の背後にある主なアイデアは、最初に「goto」ステートメントと「label」ステートメントを使用してコードのブロックをマークすることです。「goto」関数をマークする目的で、特別な「@goto」デコレータが使用されます。その後、これら 2 つのステートメントのコードをスキャンし、基になるバイト コードに必要な変更を適用します。これはすべて、ソース コードのコンパイル時に発生します。
import dis, new
def goto(fn):
"""
A function decorator to add the goto command for a function.
Specify labels like so:
label .foo
Goto labels like so:
goto .foo
Note: you can write a goto statement before the correspnding label statement
"""
labels = {}
gotos = {}
globalName = None
index = 0
end = len(fn.func_code.co_code)
i = 0
# scan through the byte codes to find the labels and gotos
while i < end:
op = ord(fn.func_code.co_code[i])
i += 1
name = dis.opname[op]
if op > dis.HAVE_ARGUMENT:
b1 = ord(fn.func_code.co_code[i])
b2 = ord(fn.func_code.co_code[i+1])
num = b2 * 256 + b1
if name == 'LOAD_GLOBAL':
globalName = fn.func_code.co_names[num]
index = i - 1
i += 2
continue
if name == 'LOAD_ATTR':
if globalName == 'label':
labels[fn.func_code.co_names[num]] = index
elif globalName == 'goto':
gotos[fn.func_code.co_names[num]] = index
name = None
i += 2
# no-op the labels
ilist = list(fn.func_code.co_code)
for label,index in labels.items():
ilist[index:index+7] = [chr(dis.opmap['NOP'])]*7
# change gotos to jumps
for label,index in gotos.items():
if label not in labels:
raise Exception("Missing label: %s"%label)
target = labels[label] + 7 # skip NOPs
ilist[index] = chr(dis.opmap['JUMP_ABSOLUTE'])
ilist[index + 1] = chr(target & 255)
ilist[index + 2] = chr(target >> 8)
# create new function from existing function
c = fn.func_code
newcode = new.code(c.co_argcount,
c.co_nlocals,
c.co_stacksize,
c.co_flags,
''.join(ilist),
c.co_consts,
c.co_names,
c.co_varnames,
c.co_filename,
c.co_name,
c.co_firstlineno,
c.co_lnotab)
newfn = new.function(newcode,fn.func_globals)
return newfn
if __name__ == '__main__':
@goto
def test1():
print 'Hello'
goto .the_end
print 'world'
label .the_end
print 'the end'
test1()
これが質問に答えることを願っています。
私は似たようなものを探していました
for a in xrange(1,10):
A_LOOP
for b in xrange(1,5):
for c in xrange(1,5):
for d in xrange(1,5):
# do some stuff
if(condition(e)):
goto B_LOOP;
したがって、私のアプローチは、ブール値を使用して、ネストされた for ループから抜け出すことでした。
for a in xrange(1,10):
get_out = False
for b in xrange(1,5):
if(get_out): break
for c in xrange(1,5):
if(get_out): break
for d in xrange(1,5):
# do some stuff
if(condition(e)):
get_out = True
break
Python に相当するコードはありませんが、ループを使用する goto/label
ことでそのような機能を得ることができます。goto/label
goto/label
Python 以外の任意の言語で使用できる、以下に示すコード サンプルを見てみましょう。
String str1 = 'BACK'
label1:
print('Hello, this program contains goto code\n')
print('Now type BACK if you want the program to go back to the above line of code. Or press the ENTER key if you want the program to continue with further lines of code')
str1 = input()
if str1 == 'BACK'
{
GoTo label1
}
print('Program will continue\nBla bla bla...\nBla bla bla...\nBla bla bla...')
上記のコード サンプルと同じ機能を、次にwhile
示すようにループを使用して Python で実現できます。
str1 = 'BACK'
while str1 == 'BACK':
print('Hello, this is a python program containing python equivalent code for goto code\n')
print('Now type BACK if you want the program to go back to the above line of code. Or press the ENTER key if you want the program to continue with further lines of code')
str1 = input()
print('Program will continue\nBla bla bla...\nBla bla bla...\nBla bla bla...')
今ある。後藤
これはあなたが探しているものに役立つかもしれないと思います。
私は同じ答えが欲しかったので、使いたくありませんgoto
でした。そこで、次の例を使用しました(learnpythonthehardwayから)
def sample():
print "This room is full of gold how much do you want?"
choice = raw_input("> ")
how_much = int(choice)
if "0" in choice or "1" in choice:
check(how_much)
else:
print "Enter a number with 0 or 1"
sample()
def check(n):
if n < 150:
print "You are not greedy, you win"
exit(0)
else:
print "You are nuts!"
exit(0)