Python'da bir etiket / goto var mı?


178

gotoPython'da belirli bir kod satırına atlayabilmek için bir ya da eşdeğeri var mı ?


2
Etiket oldukça belirsiz - aradığınız şey hakkında daha spesifik olabilir misiniz?
Dana


9
Bir arkadaşım gotoPython'a Fortran kodunu Python'a çevirirken uygulandı. Bunun için kendinden nefret ediyordu.
Cody Piersall

3
github.com/cdjc/goto ( entrian uygulamasından çok daha hızlı)
cdjc

"Etiket oldukça belirsiz", hiçbir etiket akıllı değil, yapılandırılmış bir makine gibi çalışıyor
datdinhquoc

Yanıtlar:


118

Hayır, Python etiketleri ve gitmeyi desteklemiyor, eğer peşindeyseniz. (Yüksek) yapılandırılmış bir programlama dilidir.


36
@rejinacm fonksiyonları?
UnkwnTech

79

Python, birinci sınıf işlevleri kullanarak bir goto ile yapabileceğiniz bazı şeyleri yapma olanağı sunar. Örneğin:

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

    label1:
        ...
    label2:
        ...
}

Python'da şu şekilde yapılabilir:

def func1():
    ...

def func2():
    ...

funcmap = {1 : func1, 2 : func2}

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

Kabul ettim, bu goto'nun yerine geçmenin en iyi yolu değil. Ancak, goto ile ne yapmaya çalıştığınızı tam olarak bilmeden, özel tavsiyeler vermek zor.

@ ascobol :

En iyi seçeneğiniz, onu bir işleve dahil etmek veya bir istisna kullanmaktır. İşlev için:

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

İstisna için:

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

Bunun gibi şeyler yapmak için istisnalar kullanmak, başka bir programlama dilinden gelirseniz biraz garip gelebilir. Ancak, istisnaları kullanmaktan hoşlanmıyorsanız, Python'un sizin için bir dil olmadığını iddia ediyorum. :-)


Doğru kullanın. Python'daki istisnalar diğer dillerden daha hızlıdır. Ama onlarla delirirsen hala yavaşlar.
Jason Baker

Sadece bir uyarı: loopfuncgenellikle girdiler ve uygulanması için biraz daha çaba gerektirecektir, ancak çoğu durumda bence en iyi yol budur.
kon psych

60

Son zamanlarda Python'da da böyle bir fonksiyon dekoratörü yazdımgoto , tıpkı şöyle:

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

Neden böyle bir şey yapmak istediğinden emin değilim. Bununla ilgili çok ciddi değilim dedi. Ancak, bu tür bir meta programlamanın Python'da, en azından CPython ve PyPy'de mümkün olduğunu ve sadece diğer adamın yaptığı gibi hata ayıklayıcı API'sini yanlış kullanarak değil de mümkün olduğunu belirtmek isterim . Yine de bayt kodu ile uğraşmak zorunda.


3
Yaptığınız harika dekoratör!
Bytecode

Bence bu soru için kabul edilen cevap bu olmalı. Bu, birçok iç içe döngü için yararlı olabilir, neden olmasın?
PiMathCLanguage

Bu sadece destekliyor mu .beginve .endetiketler?
Alexej Magura

29

Bunu resmi python Tasarım ve Tarih SSS bölümünde buldum .

Neden gitmiyor?

İşlev çağrılarında bile çalışan “yapılandırılmış bir goto” sağlamak için istisnaları kullanabilirsiniz. Birçok kişi, istisnaların C, Fortran ve diğer dillerin “git” veya “git” yapılarının tüm makul kullanımlarını uygun bir şekilde taklit edebileceğini düşünmektedir. Örneğin:

class label(Exception): pass  # declare a label

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

Bu, bir döngünün ortasına atlamanıza izin vermez, ancak genellikle yine de bir goto kötüye kullanımı olarak kabul edilir. Dikkatli kullanın.

Bunun resmi SSS'de bile belirtilmesi ve hoş bir çözüm örneğinin sağlanması çok güzel. Python'u gerçekten seviyorum çünkü topluluğu bile gotoböyle davranıyor;)


1
Kötüye kullanım goto, emin olmak için büyük bir programlama foux pas, ancak taklit etmek gotoiçin IMO kötüye kullanım istisnaları sadece biraz daha iyidir ve yine de çok fazla kaşlarını çatmak gerekir. Ben aslında Python yaratıcıları gotoizin vermemek için aslında yararlı olduğu birkaç kez dilde dahil olurdu çünkü "kötü, çocuklar" ve daha sonra aynı işlevselliği (ve aynı kod spagettifikasyon) almak için istisna istismar öneririz.
Abion47

15

@ascobol'Sorusunu@bobince yorumlardan gelen öneriyi kullanarak cevaplamak için :

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

elseBloğun girintisi doğrudur. Kod elsebir döngü Python sözdiziminden sonra belirsiz kullanır . Bkz Neden ve while döngüleri sonra piton kullanımı 'başka' nedir?


Başka bir blok girintisini düzelttim, bu da ilginç bir keşfe yol açtı :
Braden Best

3
@ B1KMusic: girinti olduğu gibi doğrudur. Özel bir Python sözdizimidir. elseyürütüldüğünde döngü sonrasında ise breakkarşılaşılan edilmemiştir. Etkisi, hemhem de dış halkaları should_terminate_the_loopsonlandırmasıdır .
jfs

1
Bu keşfi ancak düzenlemeyi yaptıktan sonra yaptığımı belirtmeliydim. Ondan önce, tercümanda bir hata bulduğumu sanıyordum, bu yüzden bir sürü test vakası yaptım ve neler olduğunu anlamak için biraz araştırma yaptım . Bunun için üzgünüm.
Braden Best

1
Şimdi neler olduğunu anladığım için, katılıyorum, bu daha geleneksel yöntemlerle
Braden Best

1
@ B1KMusic: Hayır. Cehaletinize geçici bir çözüm bulmak için kodu çoğaltmak iyi bir çözüm değildir. Evet. return @Jason Baker tarafından önerilen , derin yuvalanmış döngülerden kurtulmak için iyi bir alternatiftir.
jfs

12

Çalışan bir sürüm hazırlandı: http://entrian.com/goto/ .

Not: April Fool'un şakası olarak sunuldu. (yine de çalışıyor)

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

Söylemeye gerek yok. Evet komik, ama DONT kullanmayın.


1
3 mola kullanmaktan daha iyi görünüyor ... tabii ki yazmanın başka yolları da var.
Nick

1
@Nick işlevinin dönüş ile kullanılması çok daha iyi görünüyor.
Erik Šťastný

7

İçin etiketler breakve continueönerilmiştir PEP 3136 2007 yılında arka ancak reddedildi. Motivasyon teklifin bölüm birkaç yaygın (inelegant ise) etiketli taklit için yöntemler göstermektedir breakPython.


7

Bazı çalışmalarla python'a 'git' benzeri bir ifade eklemek teknik olarak mümkündür. Her ikisi de python bayt kodunu taramak ve değiştirmek için çok yararlı olan "dis" ve "new" modüllerini kullanacağız.

Uygulamanın arkasındaki ana fikir ilk olarak bir kod bloğunu "git" ve "etiket" ifadelerini kullanarak işaretlemektir. "Git" işlevlerini işaretlemek için özel bir "@goto" dekoratörü kullanılacaktır. Daha sonra bu kodu bu iki ifade için tarar ve temel bayt koduna gerekli değişiklikleri uygularız. Tüm bunlar kaynak kodu derleme zamanında gerçekleşir.

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

Umarım bu soruya cevap verir.


5

taklit etmek için Kullanıcı Tanımlı İstisnalar kullanabilirsinizgoto

misal:

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

Harika bir yöntem, ancak str istisna m yöntemini sessize alabilir miyiz
Anonim

@ Anonim hangi istisna? python3 kullanıyorsunuz?
xavierskip

5

Python 2 ve 3

pip3 install goto-statement

Python 2.6 - 3.6 ve PyPy üzerinde test edilmiştir.

Link: goto-bildirimi


foo.py

from goto import with_goto

@with_goto
def bar():

    label .bar_begin

    ...

    goto .bar_begin

3

Benzer bir şey arıyordum

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;

Bu yüzden yaklaşımım, iç içe döngülerden kurtulmak için bir boole kullanmaktı:

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

Şimdi var. git

Bence bu aradığınız şeyler için faydalı olabilir.


1

Aynı cevabı istedim ve kullanmak istemedim goto. Bu yüzden aşağıdaki örneği kullandım (learnpythonthehardway'den)

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

Gotos yapmak için kendi yolum var. Ayrı python komut dosyaları kullanıyorum.

Eğer döngü istiyorum:

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

( NOT: Bu teknik yalnızca Python 2.x sürümlerinde çalışır)


1

İleri bir Goto için şunları ekleyebilirsiniz:

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

Bu sadece basit senaryolar için yardımcı olur (yani bunları iç içe yerleştirmek sizi bir karmaşaya sokar)


1

Bir python goto eşdeğeri yerine kodumu hızlı testler için aşağıdaki şekilde break ifadesini kullanın. Bu, yapılandırılmış kod tabanınız olduğunu varsayar. Test değişkeni fonksiyonunuzun başlangıcında başlatılır ve sadece "If test: break" bloğunu test etmek istediğim iç içe if-then bloğunun veya döngüsünün sonuna taşıyorum, kodun sonunda dönüş değişkenini değiştiriyorum Ben test blok veya döngü değişkeni yansıtmak için.

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

1

goto/labelPython'da eşdeğer bir kod olmasa da, goto/labeldöngüler kullanma gibi bir işlevsellik elde edebilirsiniz .

Aşağıda, goto/labelpython dışında rastgele bir dilde kullanılabilecek bir kod örneği alalım .

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

Şimdi yukarıdaki kod örneğinin aynı işlevselliği, whileaşağıda gösterildiği gibi bir döngü kullanılarak python'da elde edilebilir .

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

hayır, goto ifadesini uygulamanın alternatif bir yolu var

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()  
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.