Pythonにlabel / gotoはありますか?


178

そこにあるgotoPythonでまたは任意の同等のコードの特定の行にジャンプすることができるようにするには?


2
レーベルはかなり漠然としている-あなたが探しているものについてもっと具体的に言えますか?
Dana、


9
私の友人は、gotoいくつかのFortranコードをPythonに変換するときにPythonで実装しました。彼はそれを嫌っていた。
Cody Piersall、2014年

3
github.com/cdjc/goto(それはだずっと速くentrian実装よりも)
cdjc

「ラベルはかなり漠然としている」、インテリジェントなラベルはなく、構造化されたものは機械のように機能しています
datdinhquoc

回答:


118

いいえ、Pythonはラベルとgotoをサポートしていません。(高度に)構造化されたプログラミング言語です。


36
@rejinacm関数?
UnkwnTech 2009年

79

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で何をしようとしているのかを正確に知らなければ、具体的なアドバイスをするのは困難です。

@ ascobol

あなたの最善の策は、それを関数で囲むか、例外を使用することです。関数について:

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の例外は、他のほとんどの言語よりも高速です。しかし、あなたがそれらに夢中になれば、それらはまだ遅いです。
Jason Baker、

単なる通知:loopfunc通常、入力と実装するためのいくつかの努力が必要になりますが、ほとんどの場合、これが最善の方法だと思います。
kon psych 2016年

60

最近、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を誤用するだけではないことを指摘しておきます。ただし、バイトコードをいじる必要があります。


3
あなたが作った素晴らしいデコレータ!バイトコードをいじることができるすばらしい方法:-)
K.Mulier

私は、これがこの質問の受け入れられた答えであるべきだと思います。これは多くのネストされたループに役立ちますが、なぜでしょうか?
PiMathCLanguage

これはラベル.begin.endラベルのみをサポートしていますか?
Alexej Magura

29

私はこれを公式のpythonデザインと履歴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に記載されていることと、素晴らしいソリューションサンプルが提供されていることは非常に素晴らしいことです。コミュニティがgotoこのように扱っているので、私は本当にpythonが好きです;)


1
悪用はgoto確認するために、主要なプログラミングfoux PASのですが、IMOエミュレートするための例外を乱用することはgotoわずかに優れていると、まだ重くひんしゅくを買うべきです。私はむしろ、Pythonの作成者がgoto「それは悪いことだ」という理由でそれを許可せずに同じ機能を(そして同じコードのスパゲティフィケーションを取得するため)例外を悪用することを推奨するよりも、実際に役立ついくつかの機会に言語に含めたいと思います。
Abion47

15

コメントからのの提案を使用して@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構文を曖昧にしています。forループとwhileループの後でPythonが 'else'を使用する理由を参照してください


興味深い発見につながる、elseブロックのインデントを修正しました:
Braden Best

3
@ B1KMusic:インデントはそのままです。これは特別なPython構文です。ループelseが検出されていない場合は、ループの後に実行されますbreak。その結果、内部ループと外部ループの両方should_terminate_the_loop終了します。
jfs

1
編集を行った後にのみ、その発見を行うことを指定する必要がありました。私が作ったので、その前に、私は、私が通訳のバグを発見したと思ったテストケースの束をして、いくつかの研究を行なった上で何が起こっていたかを理解すること。申し訳ありません。
ブレーデンベスト

1
何が起こっているのかが理解できたので、同意します。これは、従来の方法で
Braden Best

1
@ B1KMusic:いいえ。無知を回避するためにコードを複製することは良い解決策ではありません。はい。return @Jason Bakerによって提案されたのは、深くネストされたループから抜け出すための良い代替手段です。
jfs 2015

12

作業バージョンが作成されました:http : //entrian.com/goto/

注:エイプリルフールのジョークとして提供されました。(働いています)

# Example 1: Breaking out from a deeply nested loop:
from goto import goto, label

for i in range(1, 10):
    for j in range(1, 20):
        for k in range(1, 30):
            print i, j, k
            if k == 3:
                goto .end
label .end
print "Finished\n"

言うまでもなく。はい、面白いですが、使用しないでください。


1
3つの休憩を使用するよりも私には見栄えがします...もちろん、それを書く方法は他にもあります。
Nick

1
@Nick returnを使用した関数の使用はさらに良く見えます。
ErikŠťastný2018年

7

ラベルbreakとは、continue中で提案されたPEP 3136、2007年に戻って、それが拒否されました。提案の動機のセクションは、breakPythonでラベル付けされた模倣するためのいくつかの一般的な(エレガントでない場合)メソッドを示しています。


7

「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()

これが質問に答えることを願っています。


5

ユーザー定義の例外を使用してエミュレートできますgoto

例:

class goto1(Exception):
    pass   
class goto2(Exception):
    pass   
class goto3(Exception):
    pass   


def loop():
    print 'start'
    num = input()
    try:
        if num<=0:
            raise goto1
        elif num<=2:
            raise goto2
        elif num<=4:
            raise goto3
        elif num<=6:
            raise goto1
        else:
            print 'end'
            return 0
    except goto1 as e:
        print 'goto1'
        loop()
    except goto2 as e:
        print 'goto2'
        loop()
    except goto3 as e:
        print 'goto3'
        loop()

素晴らしいメソッドですが、str例外mメソッドをミュートできますか
匿名

@匿名どの例外?あなたはpython3を使いますか?
xavierskip

5

Python 2および3

pip3 install goto-statement

Python 2.6から3.6およびPyPyでテストされています。

リンク:goto-statement


foo.py

from goto import with_goto

@with_goto
def bar():

    label .bar_begin

    ...

    goto .bar_begin

3

私はに似たものを探していました

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


1

同じ答えが欲しくて使用したくありません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)

1

私は自分のゴトのやり方を持っています。個別のpythonスクリプトを使用しています。

ループしたい場合:

file1.py

print("test test")
execfile("file2.py")
a = a + 1

file2.py

print(a)
if a == 10:
   execfile("file3.py")
else:
   execfile("file1.py")

file3.py

print(a + " equals 10")

注:この手法はPython 2.xバージョンでのみ機能します)


1

転送後藤の場合は、次のように追加できます。

while True:
  if some condition:
    break
  #... extra code
  break # force code to exit. Needed at end of while loop
#... continues here

ただし、これは単純なシナリオでのみ役立ちます(つまり、これらをネストすると混乱に陥ります)


1

python gotoに相当するものの代わりに、次のようにbreakステートメントを使用して、コードをすばやくテストしています。これは、構造化されたコードベースがあることを前提としています。テスト変数は関数の開始時に初期化され、「If test:break」ブロックをテストしたいネストされたif-thenブロックまたはループの最後に移動し、コードの最後で戻り変数を変更しますテストしているブロックまたはループ変数を反映します。

def x:
  test = True
  If y:
     # some code
     If test:
            break
  return something

1

goto/labelPythonに相当するコードはありませんが、次のような機能を取得できます。goto/labelループ使用する使用できます。

goto/labelPython以外の任意の言語で使用できる以下のコードサンプルを見てみましょう。

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...')

0

gotoステートメントを実装する代替方法はありません

class id:
     def data1(self):
        name=[]
        age=[]   
        n=1
        while n>0:
            print("1. for enter data")
            print("2. update list")
            print("3. show data")
            print("choose what you want to do ?")
            ch=int(input("enter your choice"))
            if ch==1:    
                n=int(input("how many elemet you want to enter="))
                for i in range(n):
                    name.append(input("NAME "))
                    age.append(int(input("age "))) 
            elif ch==2:
                name.append(input("NAME "))
                age.append(int(input("age ")))
            elif ch==3:
                try:
                    if name==None:
                        print("empty list")
                    else:
                        print("name \t age")
                        for i in range(n):
                            print(name[i]," \t ",age[i])
                        break
                except:
                    print("list is empty")
            print("do want to continue y or n")
            ch1=input()
            if ch1=="y":
                n=n+1
            else:
                print("name \t age")
                for i in range(n):
                    print(name[i]," \t ",age[i])
                n=-1
p1=id()
p1.data1()  
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.