Apakah ada label / goto dengan Python?

178

Apakah ada gotoatau yang setara dengan Python untuk dapat melompat ke baris kode tertentu?

pengguna46646
sumber
2
Label cukup kabur - dapatkah Anda lebih spesifik tentang apa yang Anda cari?
Dana
7
import goto
wim
9
Seorang teman saya diimplementasikan gotodalam Python ketika dia menerjemahkan beberapa kode Fortran ke Python. Dia membenci dirinya sendiri untuk itu.
Cody Piersall
3
github.com/cdjc/goto (ini jauh lebih cepat daripada implementasi entrian)
cdjc
"Label cukup samar", tidak ada label yang cerdas, terstruktur bekerja seperti mesin
datdinhquoc

Jawaban:

118

Tidak, Python tidak mendukung label dan goto, jika itu yang Anda cari. Ini adalah bahasa pemrograman (sangat) terstruktur.

beristirahat
sumber
36
fungsi @rejinacm?
UnkwnTech
79

Python menawarkan Anda kemampuan untuk melakukan beberapa hal yang bisa Anda lakukan dengan goto menggunakan fungsi kelas satu. Sebagai contoh:

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

    label1:
        ...
    label2:
        ...
}

Bisa dilakukan dengan python seperti ini:

def func1():
    ...

def func2():
    ...

funcmap = {1 : func1, 2 : func2}

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

Memang, itu bukan cara terbaik untuk menggantikan goto. Tetapi tanpa tahu persis apa yang Anda coba lakukan dengan kebagian, sulit untuk memberikan saran khusus.

@ ascobol :

Taruhan terbaik Anda adalah dengan melampirkannya dalam suatu fungsi atau menggunakan pengecualian. Untuk fungsi:

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

Sebagai pengecualian:

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

Menggunakan pengecualian untuk melakukan hal-hal seperti ini mungkin terasa sedikit canggung jika Anda berasal dari bahasa pemrograman lain. Tapi saya berpendapat bahwa jika Anda tidak suka menggunakan pengecualian, Python bukan bahasa untuk Anda. :-)

Jason Baker
sumber
Gunakan dengan bijaksana. Pengecualian dalam Python lebih cepat dari kebanyakan bahasa lain. Tapi mereka masih lambat jika Anda gila dengan mereka.
Jason Baker
Hanya pemberitahuan: loopfuncumumnya akan membutuhkan input dan beberapa upaya lagi untuk diterapkan, tetapi itu adalah cara terbaik dalam banyak kasus saya pikir.
kon psych
60

Baru-baru ini saya menulis dekorator fungsi yang memungkinkan gotodengan Python, seperti itu:

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

Saya tidak yakin mengapa seseorang ingin melakukan sesuatu seperti itu. Yang mengatakan, saya tidak terlalu serius tentang itu. Tapi saya ingin menunjukkan bahwa pemrograman meta semacam ini sebenarnya mungkin dalam Python, setidaknya dalam CPython dan PyPy, dan tidak hanya dengan menyalahgunakan API debugger seperti yang dilakukan orang lain . Anda harus mengacaukan bytecode.

Sebastian Noack
sumber
3
Dekorator hebat yang Anda buat! Luar biasa bagaimana Anda bisa bermain-main dengan bytecode :-)
K.Mulier
Saya pikir, ini harus menjadi jawaban yang diterima untuk pertanyaan ini. Ini bisa berguna untuk banyak loop bersarang, mengapa tidak?
PiMathCLanguage
Apakah ini hanya mendukung .begindan .endmemberi label?
Alexej Magura
29

Saya menemukan ini di FAQ Desain dan Sejarah python resmi .

Kenapa tidak ada goto?

Anda dapat menggunakan pengecualian untuk memberikan "goto terstruktur" yang bahkan berfungsi lintas panggilan fungsi. Banyak yang merasa bahwa pengecualian dapat dengan mudah meniru semua penggunaan yang masuk akal dari konstruksi “go” atau “goto” dari bahasa C, Fortran, dan lainnya. Sebagai contoh:

class label(Exception): pass  # declare a label

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

Ini tidak memungkinkan Anda untuk melompat ke tengah lingkaran, tetapi itu biasanya dianggap sebagai penyalahgunaan goto. Gunakan hemat.

Sangat menyenangkan bahwa ini bahkan disebutkan dalam FAQ resmi, dan bahwa sampel solusi yang bagus disediakan. Saya sangat suka python karena komunitasnya memperlakukan bahkan gotoseperti ini;)

klaas
sumber
1
Menyalahgunakan gotoadalah pemrograman utama yang pasti, tetapi pengecualian menyalahgunakan IMO untuk ditiru gotohanya sedikit lebih baik dan masih harus sangat disukai. Saya lebih suka pencipta Python memasukkan gotodalam bahasa untuk beberapa kesempatan di mana itu sebenarnya berguna daripada melarangnya karena "itu buruk, teman-teman" dan kemudian merekomendasikan pengecualian yang menyalahgunakan untuk mendapatkan fungsi yang sama (dan spagettifikasi kode yang sama).
Abion47
15

Untuk menjawab @ascobolpertanyaan menggunakan @bobincesaran dari komentar:

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

Indentasi untuk elseblok sudah benar. Kode menggunakan tidak jelas elsesetelah sintaks Python loop. Lihat Mengapa python menggunakan 'else' setelah untuk dan sementara loop?

jfs
sumber
Saya memperbaiki indentasi blok Anda yang lain, yang mengarah pada penemuan yang menarik :
Braden Best
3
@ B1KMusic: indentasi sudah benar apa adanya. Ini adalah sintaks Python khusus. elsedieksekusi setelah loop jika breakbelum ditemukan. Efeknya adalah bahwa should_terminate_the_loopberakhir baik loop dalam dan luar.
jfs
1
Saya seharusnya menentukan bahwa saya hanya membuat penemuan itu setelah saya mengedit. Sebelum itu, saya pikir saya telah menemukan bug pada penerjemah, jadi saya membuat banyak kasus uji dan melakukan riset untuk memahami apa yang sedang terjadi. Maaf soal itu.
Braden Best
1
Sekarang saya mengerti apa yang sedang terjadi, saya setuju, itu adalah beberapa kode esoterik yang akan dilakukan lebih mudah dengan metode yang lebih tradisional
Braden Best
1
@ B1KMusic: Tidak. Kode duplikat untuk mengatasi ketidaktahuan Anda bukanlah solusi yang baik. Iya. return disarankan oleh @Jason Baker adalah alternatif yang baik untuk keluar dari loop yang sangat bersarang.
jfs
12

Versi yang berfungsi telah dibuat: http://entrian.com/goto/ .

Catatan: Itu ditawarkan sebagai lelucon April Mop. (meskipun bekerja)

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

Tak perlu dikatakan. Ya itu lucu, tapi JANGAN menggunakannya.

bahaya
sumber
1
terlihat lebih baik bagi saya daripada menggunakan 3 istirahat ... tentu saja ada cara lain untuk menulisnya juga.
Nick
1
@Nick Penggunaan fungsi dengan pengembalian terlihat jauh lebih baik.
Erik Šťastný
7

Label untuk breakdan continuediusulkan dalam PEP 3136 pada tahun 2007, tetapi ditolak. Bagian Motivasi proposal menggambarkan beberapa metode yang umum (jika tidak berlaku) untuk meniru berlabel breakPython.

Bill the Lizard
sumber
7

Secara teknis layak untuk menambahkan pernyataan seperti 'goto' ke python dengan beberapa pekerjaan. Kami akan menggunakan modul "dis" dan "baru", keduanya sangat berguna untuk memindai dan memodifikasi kode byte python.

Gagasan utama di balik implementasi ini adalah untuk pertama menandai blok kode sebagai menggunakan pernyataan "goto" dan "label". Dekorator "@ goto" khusus akan digunakan untuk tujuan menandai fungsi "goto". Setelah itu kami memindai kode itu untuk kedua pernyataan ini dan menerapkan modifikasi yang diperlukan untuk kode byte yang mendasarinya. Ini semua terjadi pada waktu kompilasi kode sumber.

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

Semoga ini menjawab pertanyaan.

Rabih Kodeih
sumber
5

Anda dapat menggunakan Pengecualian Buatan Pengguna Buatan untuk menirugoto

contoh:

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()
xavierskip
sumber
Metode yang luar biasa tetapi bisakah kita membisukan metode pengecualian m
Anonim
@Anonim pengecualian mana? Anda menggunakan python3?
xavierskip
5

Python 2 & 3

pip3 install goto-statement

Diuji pada Python 2.6 hingga 3.6 dan PyPy.

Tautan: pernyataan-goto


foo.py

from goto import with_goto

@with_goto
def bar():

    label .bar_begin

    ...

    goto .bar_begin
Marco DG
sumber
3

Saya mencari sesuatu yang mirip

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;

Jadi pendekatan saya adalah menggunakan boolean untuk membantu keluar dari sarang untuk loop:

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
yaitloutou
sumber
2

Ada sekarang. pergi ke

Saya pikir ini mungkin berguna untuk apa yang Anda cari.

ancho
sumber
1

Saya menginginkan jawaban yang sama dan saya tidak ingin menggunakannya goto. Jadi saya menggunakan contoh berikut (dari 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)
Sand1512
sumber
1

Saya punya cara sendiri dalam melakukan goto. Saya menggunakan skrip python terpisah.

Jika saya ingin mengulang:

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

( CATATAN: Teknik ini hanya berfungsi pada versi Python 2.x)

Anonaguy
sumber
1

Untuk maju Goto, Anda bisa menambahkan:

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

Ini hanya membantu untuk skenario sederhana (yaitu bersarang ini akan membuat Anda berantakan)

JGFMK
sumber
1

Sebagai pengganti python goto equivalent saya menggunakan pernyataan break dengan cara berikut untuk tes cepat kode saya. Ini mengasumsikan Anda memiliki basis kode terstruktur. Variabel tes diinisialisasi pada awal fungsi Anda dan saya hanya memindahkan blok "If test: break" ke akhir blok if-then bersarang atau loop yang ingin saya uji, memodifikasi variabel kembali di akhir kode untuk mencerminkan variabel blok atau loop yang saya uji.

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

Meskipun tidak ada kode yang setara dengan goto/labelPython, Anda masih bisa mendapatkan fungsionalitas goto/labelmenggunakan loop.

Mari kita ambil contoh kode yang ditunjukkan di bawah ini di mana goto/labeldapat digunakan dalam bahasa arbitrer selain 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...')

Sekarang fungsi yang sama dari contoh kode di atas dapat dicapai dengan python dengan menggunakan whileloop seperti yang ditunjukkan di bawah ini.

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...')
Somanna
sumber
0

tidak ada cara alternatif untuk mengimplementasikan pernyataan 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()  
Ahli Python
sumber