파이썬에 레이블 / 고토가 있습니까?


178

거기에 goto파이썬 또는 이와 동등한 코드의 특정 라인으로 이동 할 수 있도록은?


2
라벨은 매우 모호합니다. 원하는 것을 더 구체적으로 지정할 수 있습니까?
Dana


9
내 친구가 gotoFortran 코드를 Python으로 변환 할 때 Python으로 구현 했습니다. 그는 그것을 싫어했다.
코디 피어스

3
github.com/cdjc/goto ( 엔트리 안 구현보다 훨씬 빠름)
cdjc

"라벨은 꽤 모호하다", 어떤 라벨도 지능적이지 않으며 구조화가 기계처럼 작동합니다
datdinhquoc

답변:


118

아니요, 파이썬은 레이블과 이동을 지원하지 않습니다. 그것은 (높은) 구조화 된 프로그래밍 언어입니다.


36
@rejinacm 기능?
UnkwnTech

79

파이썬은 일류 함수를 사용하여 goto로 할 수있는 일을 할 수있는 기능을 제공합니다. 예를 들면 다음과 같습니다.

void somefunc(int a)
{
    if (a == 1)
        goto label1;
    if (a == 2)
        goto label2;

    label1:
        ...
    label2:
        ...
}

파이썬에서 다음과 같이 할 수 있습니다 :

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

다른 프로그래밍 언어에서 온 경우 예외를 사용하여 이와 같은 작업을 수행하는 것은 약간 어색 할 수 있습니다. 그러나 예외를 사용하는 것을 싫어하면 파이썬이 당신의 언어가 아니라고 주장합니다. :-)


신중하게 사용하십시오. 파이썬의 예외는 다른 대부분의 언어보다 빠릅니다. 그러나 당신이 그들에게 미치면 그들은 여전히 ​​느립니다.
Jason Baker

단지 고지 : loopfunc일반적으로 입력과 구현에 더 많은 노력이 필요하지만 대부분의 경우 가장 좋은 방법이라고 생각합니다.
kon psych

60

최근 에 파이썬에서 가능하게 하는 함수 데코레이터작성했습니다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에서 파이썬에서 실제로 가능하며 다른 사람이 했던 것처럼 디버거 API를 오용하는 것만이 아니라고 지적하고 싶습니다 . 그래도 바이트 코드를 엉망으로 만들어야합니다.


3
당신이 만든 훌륭한 장식 자! 바이트 코드로 바이올린을

나는 이것이이 질문에 대한 대답으로 받아 들여 져야한다고 생각합니다. 이것은 많은 중첩 루프에 유용 할 수 있습니다. 왜 그렇지 않습니까?
PiMathCLanguage

지원 .begin.end레이블 만 지원합니까 ?
Alexej Magura

29

나는 공식적인 파이썬 디자인 및 역사 FAQ 에서 이것을 발견했다 .

왜 고토가 없습니까?

예외를 사용하여 함수 호출에서도 작동하는 "구조화 된 이동"을 제공 할 수 있습니다. 많은 사람들은 예외가 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처럼 취급하기 때문에 파이썬을 정말로 좋아 합니다.)


1
남용 goto은 확실하게 주요 프로그래밍 문제이지만, 에뮬레이션을위한 IMO 남용 예외 goto는 약간 더 좋으며 여전히 찌그러져 야합니다. 오히려 파이썬 제작자는 goto"나쁘고 나쁜 사람"이기 때문에 허용하지 않는 것보다 실제로 유용한 몇 가지 경우에 언어에 포함시킨 다음 동일한 기능 (및 동일한 코드 spaghettification)을 얻기 위해 예외를 남용하는 것이 좋습니다.
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루프 파이썬 구문 후에 코드가 모호하게 사용 됩니다. 파이썬이 for 및 while 루프 후에 왜 'else'를 사용합니까?를 참조하십시오 .


나는 else 블록 들여 쓰기를 수정하여 흥미로운 발견 을 이끌어 냈습니다 .
Braden Best

3
@ B1KMusic : 들여 쓰기는 그대로 정확합니다. 특별한 파이썬 구문입니다. else실행 루프 후에 경우 break가 발생되지 않았습니다. 그 결과 내부 및 외부 루프 should_terminate_the_loop모두 종료됩니다 .
jfs

1
편집 한 후에 만 ​​검색하도록 지정해야합니다. 그 전에 인터프리터에서 버그를 발견했다고 생각했기 때문에 많은 테스트 사례를 만들고 어떤 일이 일어나고 있는지 이해하기 위해 조사 했습니다. 미안합니다.
Braden Best

1
이제 무슨 일이 일어나고 있는지 이해 했으니, 그것은 전통적인 방법으로
Braden Best

1
@ B1KMusic : 아니오. 당신의 무지를 해결하기 위해 코드를 복제하는 것은 좋은 해결책이 아닙니다. 예. return @Jason Baker제안한 것은 깊게 중첩 된 루프에서 벗어날 수있는 좋은 대안입니다.
jfs

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 리턴 기능 사용이 훨씬 더 좋아 보인다.
Erik Šťastný

7

레이블 break과는 continue제안 된 PEP 3136 2007 년에 다시 있지만 거부되었습니다. 제안서 의 동기 부여 섹션은 break파이썬으로 분류 된 모방을위한 몇 가지 일반적인 (우아한 경우) 방법을 보여줍니다 .


7

일부 작업으로 파이썬에 'goto'와 같은 문장을 추가하는 것은 기술적으로 가능합니다. "dis"및 "new"모듈을 사용하여 파이썬 바이트 코드를 스캔하고 수정하는 데 매우 유용합니다.

구현의 주요 아이디어는 먼저 "goto"및 "label"문을 사용하여 코드 블록을 표시하는 것입니다. 특수한 "@goto"데코레이터는 "goto"기능을 표시하기 위해 사용됩니다. 그런 다음이 코드에서 해당 코드를 스캔하고 필요한 수정 사항을 기본 바이트 코드에 적용합니다. 이 모든 것은 소스 코드 컴파일 타임에 발생합니다.

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 메서드를 음소거 할 수
Anonymous

@ 익명 어떤 예외? python3을 사용하십니까?
xavierskip

5

파이썬 2 & 3

pip3 install goto-statement

Python 2.6에서 3.6 및 PyPy에서 테스트되었습니다.

링크 : 진술 문


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

2

지금 있습니다. 이동

나는 이것이 당신이 찾고있는 것에 유용 할 것이라고 생각합니다.


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

나는 고토를하는 나만의 방법이있다. 별도의 파이썬 스크립트를 사용합니다.

반복하고 싶다면 :

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

앞으로 Goto의 경우 다음을 추가 할 수 있습니다.

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/label파이썬에는 동등한 코드가 없지만 goto/label루프 사용 과 같은 기능을 여전히 얻을 수 있습니다 .

goto/label파이썬 이외의 다른 언어로 사용될 수있는 아래에 표시된 코드 샘플을 보자 .

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와 같이 루프를 사용하여 파이썬에서 위의 코드 샘플과 동일한 기능을 수행 할 수 있습니다 .

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.