Есть ли в Python метка / goto?

Есть ли goto или любой эквивалент в Python, чтобы иметь возможность переходить к определенной строке кода?


person user46646    schedule 13.01.2009    source источник
comment
Ярлык довольно расплывчатый - не могли бы вы уточнить, что ищете?   -  person Dana    schedule 13.01.2009
comment
импортировать goto   -  person wim    schedule 14.11.2013
comment
Мой друг реализовал goto на Python, когда переводил некоторый код Fortran на Python. Он ненавидел себя за это.   -  person Cody Piersall    schedule 26.05.2014
comment
github.com/cdjc/goto (это намного быстрее, чем исходная реализация )   -  person cdjc    schedule 20.08.2014
comment
Этикетка довольно расплывчата, ни одна этикетка не является интеллектуальной, структурированная работает как машина   -  person datdinhquoc    schedule 26.01.2020
comment
В контексте ярлыка goto это очень понятно любому опытному программисту.   -  person Sakuragaoka    schedule 13.11.2020


Ответы (20)


Нет, Python не поддерживает метки и goto, если это то, что вам нужно. Это (высоко) структурированный язык программирования.

person unwind    schedule 13.01.2009

Python предлагает вам возможность делать некоторые вещи, которые вы могли бы сделать с помощью 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, сложно дать конкретный совет.

@ 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 не для вас. :-)

person Jason Baker    schedule 13.01.2009
comment
Используйте это разумно. Исключения в Python работают быстрее, чем в большинстве других языков. Но они все равно медленные, если вы с ума сойдете. - person Jason Baker; 13.01.2009
comment
Просто примечание: loopfunc обычно требует ввода и некоторых дополнительных усилий для реализации, но я думаю, что в большинстве случаев это лучший способ. - person kon psych; 20.05.2016
comment
Извините, но исключения не должны использоваться для управления ходом программы таким образом. - person ventaquil; 02.11.2020

Недавно я написал декоратор функций, который включает goto в Python, вот так:

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

Я не уверен, почему кто-то хотел бы делать что-то подобное. Тем не менее, я не слишком серьезно отношусь к этому. Но я хотел бы указать, что этот вид метапрограммирования действительно возможен в Python, по крайней мере, в CPython и PyPy, а не только за счет неправильного использования API отладчика как другой парень сделал. Однако вам придется повозиться с байт-кодом.

person Sebastian Noack    schedule 20.09.2015
comment
Вы сделали отличный декоратор! Потрясающе, как вы можете возиться с байт-кодом :-) - person K.Mulier; 04.10.2018
comment
Думаю, это должен быть принятый ответ на этот вопрос. Это может быть полезно для многих вложенных циклов, почему бы и нет? - person PiMathCLanguage; 31.05.2019
comment
Поддерживаются ли только ярлыки .begin и .end? - person Alexej Magura; 10.03.2020

Я нашел это в официальном FAQ по дизайну и истории Python..

Почему нет goto?

Вы можете использовать исключения, чтобы обеспечить «структурированный переход», который работает даже при вызовах функций. Многие считают, что исключения могут удобно имитировать все разумные варианты использования конструкций «go» или «goto» в C, Fortran и других языках. Например:

class label(Exception): pass  # declare a label

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

Это не позволяет вам перейти в середину цикла, но в любом случае это обычно считается злоупотреблением goto. Используйте экономно.

Очень приятно, что об этом даже упоминается в официальном FAQ и что предоставляется хороший образец решения. Мне очень нравится python, потому что его сообщество так относится даже к goto;)

person klaas    schedule 20.01.2017
comment
Злоупотребление goto - это, безусловно, серьезный недостаток программирования, но ИМО, злоупотребляющее исключениями для имитации goto, лишь немного лучше и все же должно вызывать осуждение. Я бы предпочел, чтобы создатели Python включали goto в язык для тех немногих случаев, когда это действительно полезно, чем запрещать его, потому что это плохо, ребята, а затем рекомендовать злоупотреблять исключениями, чтобы получить ту же функциональность (и ту же спагеттификацию кода). - person Abion47; 09.07.2020
comment
Это интересная часть в FAQ. Название в FAQ немного вводит в заблуждение, поскольку фактически не отвечает на вопрос «Почему». - person np8; 23.12.2020
comment
@ np8: Я думаю, что это так, если сказать, что .. Вы можете использовать исключения для обеспечения «структурированного перехода» .. и что ... Многие считают, что исключения могут удобно имитировать все разумные варианты использования «go» или «goto». Я интерпретирую это так, что в python нет специального goto, потому что функциональность и даже немного больше могут быть легко достигнуты с использованием других механизмов языка. Но я также согласен с тем, что нет реальной причины, по которой он не был добавлен в качестве синтаксического сахара. Опять же, ИМХО, я думаю, что основное внимание уделяется структурированию, в отличие от goto, которое может буквально прыгать в любом месте кода. - person klaas; 24.12.2020
comment
Лол, я думал, что я первый, кто использует try...except... для имитации goto (потому что почти все ответы из Интернета предлагают библиотеку python-goto третьей части). Поэтому пытаюсь ответить здесь, пока не увижу этот ответ. Приятно видеть, что это упоминается в официальном документе. - person bearzyj; 15.05.2021

Чтобы ответить на вопрос @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 после синтаксиса цикла Python. См. Почему python использует else после циклов for и while?

person jfs    schedule 17.01.2009
comment
Я исправил отступ блока else, что привело к интересному открытию: - person Braden Best; 07.02.2015
comment
@ B1KMusic: отступ правильный как есть. Это особый синтаксис Python. else выполняется после цикла, если break не обнаружен. В результате should_terminate_the_loop завершает как внутренние, так и внешние циклы. - person jfs; 07.02.2015
comment
Я должен был указать, что сделал это открытие только после того, как внес правку. До этого я думал, что обнаружил ошибку в интерпретаторе, поэтому сделал набор тестов и провел небольшое исследование, чтобы понять, что происходит. Извини за это. - person Braden Best; 07.02.2015
comment
Теперь, когда я понимаю, что происходит, я согласен, что это некий эзотерический код, который было бы намного проще выполнить с помощью более традиционных методов - person Braden Best; 07.02.2015
comment
@ B1KMusic: предложенный вами метод (двойное копирование условия) хуже. Обычно вместо них могут использоваться found, done болевые переменные. - person jfs; 07.02.2015
comment
Что ж, если OP желает (хотел) прибегнуть к рискованному выражению goto, я бы поспорил с дублированием небольшого фрагмента кода, длина которого не может превышать 10 символов, это не слишком большая натяжка. Цель - удобочитаемость, и проверка if..else с кратким поясняющим комментарием для меня более читабельна, чем цикл, полный довольно непонятного синтаксиса, который может заставить людей подумать, что есть ошибка отступа. Лично, если бы я столкнулся с конкретной необходимостью выйти сразу из нескольких циклов, это о том, как я сделает это. - person Braden Best; 07.02.2015
comment
@ B1KMusic: Нет. Дублирование кода для обхода вашего незнания - не лучшее решение. да. return , предложенный @Jason Baker, является хорошей альтернативой для выхода из глубоко вложенных циклов. - person jfs; 07.02.2015
comment
@BradenBest lol, если бы целью была удобочитаемость, они бы не хотели, чтобы оператор goto. Обычно я обнаружил, что это снижает LOC. плюс то, что что-то считается непонятным синтаксисом, не является причиной не использовать его. вот почему они придумали комментарии #forthewin - person theEpsilon; 11.01.2020

Создана рабочая версия: 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"

Разумеется. Да, это забавно, но НЕ используйте это.

person harmv    schedule 21.05.2015
comment
мне кажется лучше, чем использовать 3 перерыва ... конечно, есть и другие способы написать это. - person Nick; 30.08.2017
comment
@Nick Использование функции с возвратом выглядит еще лучше. - person Erik Šťastný; 04.10.2018

Технически возможно добавить в Python оператор типа goto с некоторой работой. Мы будем использовать модули «dis» и «new», оба очень полезны для сканирования и изменения байтового кода Python.

Основная идея реализации состоит в том, чтобы сначала пометить блок кода как использующий операторы «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()

Надеюсь, это ответит на вопрос.

person Rabih Kodeih    schedule 05.05.2015

Ярлыки для break и continue были предложены в PEP 3136 еще в 2007 году, но это Было отказано. Раздел предложения Мотивация иллюстрирует несколько распространенных (хотя и неэлегантных) методов. для имитации маркированного break в Python.

person Bill the Lizard    schedule 26.03.2012

Python 2 и 3

pip3 install goto-statement

Протестировано на Python 2.6–3.6 и PyPy.

Ссылка: инструкция goto


foo.py

from goto import with_goto

@with_goto
def bar():

    label .bar_begin

    ...

    goto .bar_begin
person Marco D.G.    schedule 01.08.2019

вы можете использовать определяемые пользователем исключения для имитации 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()
person xavierskip    schedule 27.03.2015
comment
Отличный метод, но можем ли мы отключить метод str exception m - person Anonymous; 23.05.2019
comment
@ Анонимно какое исключение? вы используете python3? - person xavierskip; 09.11.2019

Я искал что-то похожее на

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
person yaitloutou    schedule 07.07.2016

Хотя в Python нет кода, эквивалентного goto/label, вы все равно можете получить такую ​​функциональность goto/label, используя циклы.

Давайте возьмем пример кода, показанный ниже, где goto/label можно использовать на любом языке, отличном от 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...')

Теперь те же функциональные возможности, что и в приведенном выше примере кода, могут быть достигнуты в Python с помощью цикла 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...')
person Somanna    schedule 15.12.2019

Есть сейчас. goto

Я думаю, это может быть полезно для того, что вы ищете.

person ancho    schedule 22.09.2015

Я хотел того же ответа и не хотел использовать 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)
person Sandjaie Ravi    schedule 30.07.2015

У меня есть свой способ делать gotos. Использую отдельные скрипты на 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)

person Anonaguy    schedule 18.02.2018

Для прямого Goto вы можете просто добавить:

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

Это помогает только в простых сценариях (например, их вложение приведет вас в беспорядок)

person JGFMK    schedule 02.06.2018

Вместо эквивалента goto в Python я использую оператор break следующим образом для быстрой проверки моего кода. Это предполагает, что у вас есть структурированная кодовая база. Тестовая переменная инициализируется в начале вашей функции, и я просто перемещаю блок «If test: break» в конец вложенного блока if-then или цикла, который я хочу протестировать, изменяя возвращаемую переменную в конце кода. чтобы отразить переменную блока или цикла, которую я тестирую.

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

Вы можете добиться этого, используя вложенные методы внутри Python

def func1():
    print("inside func1")
    def inline():
        print("im inside")
    
    inline()
    
func1()
person Nikhil Dinesh    schedule 27.05.2021

нет альтернативного способа реализации инструкции 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()  
person Python Experts    schedule 31.01.2019

Я думаю, что цикл while является альтернативой goto_Statement. Потому что после 3.6 цикл goto больше не работает. Я также пишу пример цикла while.

str1 = "stop"
while str1 == "back":
    var1 = int(input(" Enter Ist Number: "))
    var2 = int(input(" Enter 2nd Number: "))
    var3 = print("""  What is your next operation
                      For Addition   Press And Enter : 'A'
                      For Muliplt    Press And Enter : 'M'
                      For Division   Press And Enter : 'D'
                      For Subtaction Press And Enter : 'S' """)

    var4 = str(input("For operation press any number : "))
    if(var1 == 45) and (var2 == 3):
        print("555")
    elif(var1 == 56) and (var2 == 9):
        print("77")
    elif(var1 == 56) and (var2 == 6):
        print("4")
    else:
        if(var4 == "A" or "a"):
            print(var1 + var2)
        if(var4 == "M" or "m"):
            print(var1 * var2)
        if(var4 == "D" or "d"):
            print(var1 / var2)
        if(var4 == "S" or "s"):
            print(var1 - var2)

    print("if you want to continue then type  'stop'")

    str1 = input()
print("Strt again")    
person Hamza Tanveer    schedule 27.11.2020