Có nhãn / goto trong Python không?


178

Có một gotohoặc bất kỳ tương đương trong Python để có thể nhảy đến một dòng mã cụ thể không?


2
Nhãn khá mơ hồ - bạn có thể cụ thể hơn về những gì bạn đang tìm kiếm?
Dana


9
Một người bạn của tôi đã triển khai gotobằng Python khi anh ta đang dịch một số mã Fortran sang Python. Anh ghét bản thân mình vì điều đó.
Cody Piersall

3
github.com/cdjc/goto (đó là nhiều nhanh hơn so với việc thực hiện entrian)
cdjc

"Nhãn khá mơ hồ", không có nhãn nào thông minh, có cấu trúc hoạt động như một cỗ máy
datdinhquoc

Câu trả lời:


118

Không, Python không hỗ trợ nhãn và goto, nếu đó là những gì bạn đang theo đuổi. Đó là một ngôn ngữ lập trình có cấu trúc (rất cao).


36
@rejinacm chức năng?
UnkwnTech

79

Python cung cấp cho bạn khả năng thực hiện một số điều bạn có thể làm với một goto sử dụng các hàm hạng nhất. Ví dụ:

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

    label1:
        ...
    label2:
        ...
}

Có thể được thực hiện trong python như thế này:

def func1():
    ...

def func2():
    ...

funcmap = {1 : func1, 2 : func2}

def somefunc(a):
    funcmap[a]()  #Ugly!  But it works.

Cấp, đó không phải là cách tốt nhất để thay thế cho goto. Nhưng không biết chính xác những gì bạn đang cố gắng làm với goto, thật khó để đưa ra lời khuyên cụ thể.

@ ascobol :

Đặt cược tốt nhất của bạn là hoặc đặt nó trong một chức năng hoặc sử dụng một ngoại lệ. Đối với chức năng:

def loopfunc():
    while 1:
        while 1:
            if condition:
                return

Ngoại lệ:

try:
    while 1:
        while 1:
            raise BreakoutException #Not a real exception, invent your own
except BreakoutException:
    pass

Sử dụng ngoại lệ để làm những việc như thế này có thể cảm thấy hơi khó xử nếu bạn đến từ một ngôn ngữ lập trình khác. Nhưng tôi sẽ lập luận rằng nếu bạn không thích sử dụng ngoại lệ, Python không phải là ngôn ngữ dành cho bạn. :-)


Sử dụng nó một cách thận trọng. Các ngoại lệ trong Python nhanh hơn hầu hết các ngôn ngữ khác. Nhưng họ vẫn chậm nếu bạn phát điên với họ.
Jason Baker

Chỉ cần một thông báo: loopfuncthường sẽ yêu cầu đầu vào và một số nỗ lực hơn để thực hiện, nhưng đó là cách tốt nhất trong hầu hết các trường hợp tôi nghĩ.
tâm lý kon

60

Gần đây tôi đã viết một trình trang trí chức năng cho phép gototrong Python, giống như vậy:

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

Tôi không chắc tại sao người ta lại muốn làm một cái gì đó như thế. Điều đó nói rằng, tôi không quá nghiêm trọng về nó. Nhưng tôi muốn chỉ ra rằng loại lập trình meta này thực tế có thể có trong Python, ít nhất là trong CPython và PyPy, và không chỉ bằng cách lạm dụng API trình gỡ lỗi như những người khác đã làm. Bạn phải lộn xộn với mã byte mặc dù.


3
Trang trí tuyệt vời bạn đã thực hiện! Thật tuyệt vời khi bạn có thể
nghịch ngợm

Tôi nghĩ rằng, đây nên là câu trả lời được chấp nhận cho câu hỏi này. Điều này có thể hữu ích cho nhiều vòng lặp lồng nhau, tại sao không?
PiMathCL Language

Điều này chỉ hỗ trợ .begin.endnhãn?
Alexej Magura

29

Tôi tìm thấy điều này trong Câu hỏi thường gặp về Thiết kế và Lịch sử của python .

Tại sao không có goto?

Bạn có thể sử dụng các trường hợp ngoại lệ để cung cấp một goto có cấu trúc của Youtube mà thậm chí hoạt động trên các lệnh gọi hàm. Nhiều người cảm thấy rằng các trường hợp ngoại lệ có thể mô phỏng một cách thuận tiện tất cả các cách sử dụng hợp lý của các cấu trúc của trò chơi go go hay hoặc goto của C, Fortran và các ngôn ngữ khác. Ví dụ:

class label(Exception): pass  # declare a label

try:
    ...
    if condition: raise label()  # goto label
    ...
except label:  # where to goto
    pass
... 

Điều này không cho phép bạn nhảy vào giữa vòng lặp, nhưng dù sao đó thường được coi là lạm dụng goto. Sử dụng một cách tiết kiệm.

Thật tuyệt khi điều này thậm chí còn được đề cập trong Câu hỏi thường gặp chính thức và một mẫu giải pháp tốt được cung cấp. Tôi thực sự thích trăn vì cộng đồng của nó đang đối xử gotonhư thế này;)


1
Lạm dụng gotolà một chương trình chính yếu để đảm bảo, nhưng IMO lạm dụng các ngoại lệ để mô phỏng gotochỉ tốt hơn một chút và vẫn nên được tán thành. Tôi muốn thay vào đó, những người tạo Python bao gồm gotongôn ngữ trong một số trường hợp thực sự hữu ích hơn là không cho phép vì "nó xấu, các bạn" và sau đó khuyên bạn nên lạm dụng các ngoại lệ để có cùng chức năng (và cùng một mã spaghettization).
Abion47

15

Để trả lời @ascobolcâu hỏi bằng cách sử dụng @bobinceđề xuất từ ​​các nhận xét:

for i in range(5000):
    for j in range(3000):
        if should_terminate_the_loop:
           break
    else: 
        continue # no break encountered
    break

Việc thụt lề cho elsekhối là chính xác. Mã sử ​​dụng tối nghĩa elsesau một cú pháp Python lặp. Xem tại sao python sử dụng 'other' sau vòng lặp for và while?


Tôi đã sửa lỗi thụt khối khác của bạn, dẫn đến một khám phá thú vị :
Braden Best

3
@ B1KMusic: thụt lề là chính xác. Đây là một cú pháp Python đặc biệt. elseđược thực hiện sau vòng lặp nếu breakkhông gặp phải. Hiệu quả là should_terminate_the_loopchấm dứt cả các vòng bên trong và bên ngoài.
jfs

1
Tôi nên đã xác định rằng tôi chỉ thực hiện khám phá đó sau khi tôi thực hiện chỉnh sửa. Trước đó, tôi nghĩ rằng tôi đã phát hiện ra một lỗi trong trình thông dịch, vì vậy tôi đã tạo ra một loạt các trường hợp thử nghiệmthực hiện một số nghiên cứu để hiểu những gì đang xảy ra. Xin lỗi vì điều đó.
Braden hay nhất

1
Bây giờ tôi đã hiểu những gì đang diễn ra, tôi đồng ý, đó là một số mã bí truyền sẽ được thực hiện dễ dàng hơn rất nhiều với các phương pháp truyền thống hơn
Braden Best

1
@ B1KMusic: Không. Sao chép mã để khắc phục sự thiếu hiểu biết của bạn không phải là một giải pháp tốt. Đúng. return được đề xuất bởi @Jason Baker là một lựa chọn tốt để thoát ra khỏi các vòng lặp được lồng sâu.
jfs

12

Một phiên bản làm việc đã được thực hiện: http://entrian.com/goto/ .

Lưu ý: Nó được cung cấp như một trò đùa Cá tháng Tư. (mặc dù làm việc)

# 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"

Không cần nói rằng. Có nó buồn cười, nhưng KHÔNG sử dụng nó.


1
có vẻ tốt hơn đối với tôi hơn là sử dụng 3 lần nghỉ ... tất nhiên cũng có những cách khác để viết nó.
Nick

1
@Nick Sử dụng chức năng với trả lại trông thậm chí còn tốt hơn nhiều.
Erik Šťastný

7

Các nhãn cho breakcontinueđã được đề xuất trong PEP 3136 vào năm 2007, nhưng nó đã bị từ chối. Phần Động lực của đề xuất minh họa một số phương thức phổ biến (nếu không liên quan) để bắt chước được gắn nhãn breaktrong Python.


7

Về mặt kỹ thuật có thể thêm một câu lệnh 'goto' vào python với một số công việc. Chúng tôi sẽ sử dụng các mô-đun "dis" và "new", cả hai đều rất hữu ích để quét và sửa đổi mã byte python.

Ý tưởng chính đằng sau việc triển khai là trước tiên đánh dấu một khối mã là sử dụng các câu lệnh "goto" và "nhãn". Một trình trang trí "@goto" đặc biệt sẽ được sử dụng cho mục đích đánh dấu các chức năng "goto". Sau đó, chúng tôi quét mã đó cho hai câu lệnh này và áp dụng các sửa đổi cần thiết cho mã byte bên dưới. Tất cả điều này xảy ra tại thời gian biên dịch mã nguồn.

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

Hy vọng điều này trả lời câu hỏi.


5

bạn có thể sử dụng Ngoại lệ do người dùng xác định để mô phỏnggoto

thí dụ:

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

Phương pháp tuyệt vời nhưng chúng ta có thể tắt tiếng phương thức str ngoại lệ
Ẩn danh

@ Đồng nghĩa ngoại lệ nào? bạn dùng python3?
xavierskip

5

Python 2 & 3

pip3 install goto-statement

Đã thử nghiệm trên Python 2.6 đến 3.6 và PyPy.

Liên kết: tuyên bố goto


foo.py

from goto import with_goto

@with_goto
def bar():

    label .bar_begin

    ...

    goto .bar_begin

3

Tôi đang tìm kiếm một số thứ tương tự như

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;

Vì vậy, cách tiếp cận của tôi là sử dụng một boolean để giúp thoát ra khỏi các vòng lặp lồng nhau:

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

Có ngay bây giờ. đi đến

Tôi nghĩ rằng điều này có thể hữu ích cho những gì bạn đang tìm kiếm.


1

Tôi muốn câu trả lời tương tự và tôi không muốn sử dụng goto. Vì vậy, tôi đã sử dụng ví dụ sau (từ 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

Tôi có cách làm gotos của riêng tôi. Tôi sử dụng các kịch bản python riêng biệt.

Nếu tôi muốn lặp:

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")

( LƯU Ý: Kỹ thuật này chỉ hoạt động trên các phiên bản Python 2.x)


1

Đối với một Goto chuyển tiếp, bạn chỉ cần thêm:

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

Điều này chỉ giúp cho các kịch bản đơn giản mặc dù (nghĩa là lồng chúng sẽ khiến bạn rơi vào một mớ hỗn độn)


1

Thay cho một python goto tương đương, tôi sử dụng câu lệnh break theo kiểu sau để kiểm tra nhanh mã của tôi. Điều này giả định rằng bạn có cơ sở mã cấu trúc. Biến kiểm tra được khởi tạo khi bắt đầu chức năng của bạn và tôi chỉ cần di chuyển khối "If test: break" đến cuối khối if-then lồng nhau hoặc vòng lặp tôi muốn kiểm tra, sửa đổi biến trả về ở cuối mã để phản ánh khối hoặc biến vòng lặp tôi đang thử nghiệm.

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

1

Mặc dù không có bất kỳ mã nào tương đương với goto/labelPython, bạn vẫn có thể có chức năng goto/labelsử dụng các vòng lặp như vậy .

Hãy lấy một mẫu mã được hiển thị bên dưới, nơi goto/labelcó thể được sử dụng trong một ngôn ngữ tùy ý khác với 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...')

Bây giờ chức năng tương tự của mẫu mã trên có thể đạt được trong python bằng cách sử dụng một whilevòng lặp như dưới đây.

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

không có cách nào khác để thực hiện câu lệnh 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()  
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.