Czy goto
w Pythonie istnieje odpowiednik lub jego odpowiednik, który umożliwia przejście do określonej linii kodu?
goto
w Pythonie, kiedy tłumaczył kod w języku Fortran na Python. Nienawidził siebie za to.
Czy goto
w Pythonie istnieje odpowiednik lub jego odpowiednik, który umożliwia przejście do określonej linii kodu?
goto
w Pythonie, kiedy tłumaczył kod w języku Fortran na Python. Nienawidził siebie za to.
Odpowiedzi:
Python oferuje możliwość zrobienia niektórych rzeczy, które można zrobić za pomocą goto, używając funkcji pierwszej klasy. Na przykład:
void somefunc(int a)
{
if (a == 1)
goto label1;
if (a == 2)
goto label2;
label1:
...
label2:
...
}
Można to zrobić w Pythonie w ten sposób:
def func1():
...
def func2():
...
funcmap = {1 : func1, 2 : func2}
def somefunc(a):
funcmap[a]() #Ugly! But it works.
To prawda, że nie jest to najlepszy sposób na zastąpienie goto. Ale nie wiedząc dokładnie, co próbujesz zrobić z goto, trudno jest udzielić konkretnej porady.
@ ascobol :
Najlepszym rozwiązaniem jest umieszczenie go w funkcji lub użycie wyjątku. Dla funkcji:
def loopfunc():
while 1:
while 1:
if condition:
return
Z wyjątkiem:
try:
while 1:
while 1:
raise BreakoutException #Not a real exception, invent your own
except BreakoutException:
pass
Używanie wyjątków do robienia takich rzeczy może wydawać się nieco niezręczne, jeśli pochodzisz z innego języka programowania. Ale argumentowałbym, że jeśli nie lubisz używać wyjątków, Python nie jest dla ciebie językiem. :-)
loopfunc
generalnie będzie wymagał wkładu i trochę więcej wysiłku, aby go wdrożyć, ale w większości przypadków jest to najlepszy sposób.
Niedawno napisałem dekorator funkcji, który włącza goto
w Pythonie, tak po prostu:
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
Nie jestem jednak pewien, dlaczego chciałoby się coś takiego zrobić. To powiedziawszy, nie podchodzę do tego poważnie. Chciałbym jednak zwrócić uwagę, że tego rodzaju metaprogramowanie jest w rzeczywistości możliwe w Pythonie, przynajmniej w CPython i PyPy, i nie tylko przez niewłaściwe użycie interfejsu API debuggera, tak jak zrobił to tamten facet . Musisz jednak zadzierać z kodem bajtowym.
.begin
i .end
etykiety?
Znalazłem to w oficjalnym Pythonie FAQ Design and History .
Dlaczego nie ma goto?
Możesz użyć wyjątków, aby zapewnić „strukturalne goto”, które działa nawet w przypadku wywołań funkcji. Wielu uważa, że wyjątki mogą wygodnie naśladować wszystkie rozsądne zastosowania konstrukcji „go” lub „goto” w językach C, Fortran i innych. Na przykład:
class label(Exception): pass # declare a label
try:
...
if condition: raise label() # goto label
...
except label: # where to goto
pass
...
Nie pozwala to wskoczyć w środek pętli, ale i tak jest to zwykle uważane za nadużycie goto. Używaj oszczędnie.
To bardzo miłe, że jest to nawet wspomniane w oficjalnym FAQ i że dostarczono fajną próbkę rozwiązania. Bardzo lubię Pythona, ponieważ jego społeczność traktuje nawet w goto
ten sposób;)
goto
pewnością nadużywanie jest poważnym foux pasem programistycznym, ale nadużywanie wyjątków przez IMO w celu emulacji goto
jest tylko nieznacznie lepsze i nadal powinno być mocno krytykowane. Wolałbym, żeby twórcy Pythona włączyli goto
do języka kilka sytuacji, w których faktycznie jest to użyteczne, niż zablokować go, ponieważ „to jest złe, chłopaki”, a następnie zalecić nadużywanie wyjątków, aby uzyskać tę samą funkcjonalność (i ten sam kod spaghetti).
Aby odpowiedzieć na @ascobol
pytanie użytkownika, korzystając @bobince
z sugestii z komentarzy:
for i in range(5000):
for j in range(3000):
if should_terminate_the_loop:
break
else:
continue # no break encountered
break
Wcięcie else
bloku jest poprawne. Kod używa niejasnej else
składni Pythona po pętli. Zobacz Dlaczego python używa „else” po pętli for i while?
else
jest wykonywany po pętli, jeśli break
nie został napotkany. Efektem jest to, że should_terminate_the_loop
zamyka obie pętle wewnętrzne i zewnętrzne.
return
sugerowane przez @Jason Baker to dobra alternatywa dla wyrwania się z głęboko zagnieżdżonych pętli.
Wykonano działającą wersję: http://entrian.com/goto/ .
Uwaga: był oferowany jako żart primaaprilisowy. (choć działa)
# 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"
Nie trzeba dodawać że. Tak, to zabawne, ale NIE używaj go.
Jest technicznie wykonalne, aby dodać do Pythona instrukcję podobną do „goto”. Będziemy używać modułów „dis” i „new”, które są bardzo przydatne do skanowania i modyfikowania kodu bajtowego Pythona.
Główną ideą implementacji jest najpierw oznaczenie bloku kodu za pomocą instrukcji „goto” i „label”. Specjalny dekorator „@goto” będzie używany do oznaczania funkcji „goto”. Następnie skanujemy ten kod w poszukiwaniu tych dwóch instrukcji i wprowadzamy niezbędne modyfikacje do bazowego kodu bajtowego. To wszystko dzieje się w czasie kompilacji kodu źródłowego.
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()
Mam nadzieję, że to odpowiada na pytanie.
do emulacji można użyć wyjątków zdefiniowanych przez użytkownikagoto
przykład:
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()
pip3 install goto-statement
Testowane na Pythonie 2.6 do 3.6 i PyPy.
Link: instrukcja goto
foo.py
from goto import with_goto
@with_goto
def bar():
label .bar_begin
...
goto .bar_begin
Szukałem czegoś podobnego do
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;
Więc moje podejście polegało na użyciu wartości logicznej, aby pomóc wyrwać się z zagnieżdżonych pętli 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
Chciałem tej samej odpowiedzi i nie chciałem używać goto
. Więc użyłem następującego przykładu (z 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)
Mam swój własny sposób robienia rzeczy gotowych. Używam osobnych skryptów Pythona.
Jeśli chcę zapętlić:
plik1.py
print("test test")
execfile("file2.py")
a = a + 1
plik2.py
print(a)
if a == 10:
execfile("file3.py")
else:
execfile("file1.py")
plik3.py
print(a + " equals 10")
( UWAGA: ta technika działa tylko w wersjach Python 2.x)
Zamiast odpowiednika goto w Pythonie używam instrukcji break w następujący sposób do szybkich testów mojego kodu. Zakłada się, że masz strukturalną podstawę kodu. Zmienna testowa jest inicjowana na początku twojej funkcji i po prostu przenoszę blok "If test: break" na koniec zagnieżdżonego bloku lub pętli if-then, które chcę przetestować, modyfikując zmienną zwracaną na końcu kodu aby odzwierciedlić testowaną zmienną bloku lub pętli.
def x:
test = True
If y:
# some code
If test:
break
return something
Chociaż nie ma żadnego kodu odpowiadającego temu goto/label
w Pythonie, nadal możesz uzyskać taką funkcjonalnośćgoto/label
przy użyciu pętli.
Weźmy przykładowy kod pokazany poniżej, w którym goto/label
można go użyć w dowolnym języku innym niż 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...')
Teraz tę samą funkcjonalność powyższego przykładu kodu można osiągnąć w Pythonie za pomocą while
pętli, jak pokazano poniżej.
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...')
nie, istnieje alternatywny sposób implementacji instrukcji 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()