Есть ли в Python ярлык / переход? - PullRequest
138 голосов
/ 13 января 2009

Есть ли в Python goto или какой-либо эквивалент, позволяющий перейти к определенной строке кода?

Ответы [ 16 ]

97 голосов
/ 13 января 2009

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

65 голосов
/ 13 января 2009

Python предлагает вам возможность делать некоторые вещи, которые вы могли бы сделать с goto, используя функции первого класса. Например:

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

    label1:
        ...
    label2:
        ...
}

Может быть сделано в python так:

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

38 голосов
/ 20 сентября 2015

Я недавно написал функцию декоратора , которая включает 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 отладчика, как это сделал другой парень . Вы должны возиться с байт-кодом, хотя.

20 голосов
/ 20 января 2017

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

Почему нет гото?

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

class label(Exception): pass  # declare a label

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

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

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

15 голосов
/ 17 января 2009

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

12 голосов
/ 21 мая 2015

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

Излишне говорить. Да, это смешно, но НЕ используйте его.

7 голосов
/ 05 мая 2015

Технически выполнимо добавить оператор «goto» в python с некоторой работой. Мы будем использовать модули "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()

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

7 голосов
/ 27 марта 2012

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

3 голосов
/ 07 июля 2016

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

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 голосов
/ 22 сентября 2015

есть сейчас. Гото

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...