Hướng dẫn dùng goto python python

Gotos được phổ biến rộng rãi trong khoa học máy tính và lập trình vì chúng dẫn đến mã rất không có cấu trúc.

Python (giống như hầu hết mọi ngôn ngữ lập trình hiện nay) đều hỗ trợ lập trình có cấu trúc điều khiển luồng sử dụng if/then/other, loop và chương trình con.

Chìa khóa để suy nghĩ theo cách có cấu trúc là hiểu cách thức và lý do tại sao bạn phân nhánh trên mã.

Ví dụ: hãy giả vờ Python có câu lệnh goto và tương ứng label shudder . Nhìn vào đoạn mã sau. Trong đó nếu một số lớn hơn hoặc bằng 0, chúng tôi sẽ in nếu nó

number = input()
if number < 0: goto negative
if number % 2 == 0:
   print "even"
else:
   print "odd"
goto end
label: negative
print "negative"
label: end
print "all done"

Nếu chúng ta muốn biết khi nào một đoạn mã được thực thi, chúng ta cần cẩn thận truy nguyên trong chương trình và kiểm tra xem nhãn đã được chuyển đến như thế nào - đó là điều không thể thực hiện được.

Ví dụ: chúng ta có thể viết lại như trên:

number = input()
goto check

label: negative
print "negative"
goto end

label: check
if number < 0: goto negative
if number % 2 == 0:
   print "even"
else:
   print "odd"
goto end

label: end
print "all done"

Ở đây, có hai cách có thể để đến "điểm cuối" và chúng ta không thể biết cái nào được chọn. Khi các chương trình trở nên lớn, loại vấn đề này trở nên tồi tệ hơn và kết quả là mã spaghetti

Để so sánh, bên dưới là cách bạn sẽ viết chương trình này bằng Python:

number = input()
if number >= 0:
   if number % 2 == 0:
       print "even"
   else:
       print "odd"
else:
   print "negative"
print "all done"

Tôi có thể xem một dòng mã cụ thể và biết trong điều kiện nào nó được đáp ứng bằng cách truy ngược lại cây if/then/else chặn nó. Ví dụ, tôi biết rằng dòng print "odd" sẽ được chạy khi một ((number >= 0) == True) and ((number % 2 == 0) == False).

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.

7 hữu ích 0 bình luận chia sẻ