web-dev-qa-db-ja.com

Pythonにラベル/ gotoはありますか?

特定のコード行にジャンプできるようにするgotoまたはPythonに同等のものはありますか?

139
user46646

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

98
unwind

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はあなたにとって言語ではない、と私は主張します。 :-)

65
Jason Baker

私は最近 関数デコレータを書いた 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

しかし、なぜそのようなことをしたいのかわかりません。とはいえ、私はそれについてあまり真剣ではありません。しかし、この種のメタプログラミングは、少なくともCPythonとPyPyでPythonで実際に可能であり、デバッガAPIを誤用するだけでなく 他の人 のように実際に可能であることを指摘したいと思います。ただし、バイトコードをいじる必要があります。

38
Sebastian Noack

これは official python Design and History FAQ で見つけました。

なぜgotoがないのですか?

例外を使用して、関数呼び出し間でも機能する「構造化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で言及されていること、そしてNiceソリューションのサンプルが提供されていることは非常に素晴らしいことです。 pythonが本当に好きなのは、そのコミュニティがgotoさえもこのように扱っているからです;)

20
klaas

@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ブロックのインデントは正しいです。このコードは、ループPython構文の後にあいまいなelseを使用します。 なぜpython forおよびwhileループの後に 'else'を使用するのですか?

15
jfs

作業バージョンが作成されました: 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"

言うまでもなく。はい、面白いですが、DONTはそれを使用します。

12
harmv

「goto」のようなステートメントをpythonに追加することは技術的に実行可能です。 pythonバイトコードのスキャンと変更に非常に役立つ「dis」モジュールと「new」モジュールを使用します。

実装の背後にある主なアイデアは、最初に「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 __== '__main__':

    @goto
    def test1():
        print 'Hello' 

        goto .the_end
        print 'world'

        label .the_end
        print 'the end'

    test1()

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

7
Rabih Kodeih

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

7
Bill the Lizard

私は似たようなものを探していました

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
3
yaitloutou

今あります。 goto

これはあなたが探しているものに役立つと思います。

2
ancho

ユーザー定義の例外 を使用して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()
2
xavierskip

独自の方法でgotoを実行しています。別の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
Anonaguy

同じ答えが欲しかったので、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
Sandjaie

フォワードGotoの場合は、次を追加できます。

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

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

0
JGFMK

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(start, stop):

    label .bar_begin

    ...

    goto .bar_begin
0
Marco D.G.

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

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

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()  
0
Python Experts