Python is support a goto command.
But blender bpy is not support goto command.
Realy?
I want to know whether supported a goto command at blender bpy.
And perhaps, is there a way of double for loop exit at once.
Please answer to me.
Thank you.
Python is support a goto command.
But blender bpy is not support goto command.
Realy?
I want to know whether supported a goto command at blender bpy.
And perhaps, is there a way of double for loop exit at once.
Please answer to me.
Thank you.
No one really uses goto anymore.
Just use if/then/else.
Agreed
“No One really uses goto anymore…?” <- Wait! =)
Well, actually… using if, elif, else… in bytecode - you have your ‘gotos’ (branches)
see: http://akaptur.github.io/blog/2013/08/14/python-bytecode-fun-with-dis/
But in Python files you always have conditions like if, else and so on…
I really miss a switch command in Python… I know I can just create a jump-table with functions or classes…
But it would be a bit nicer to have a ‘native’ command for that…
See ya…
ciao, joerg.
You seem to be highly confused about several things. Just to clear a few things up:
There are a couple of ways to break out of nested for-loops.
exit = False
for i in range(0, 100):
for j in range(0, 100):
if <some condition>
exit = True
break
if exit:
break
If you don’t mind writing some dirty code and you are pretty sure that you are the only one that will ever see it, then you could wrap your for-loops in a try-except clause and throw an exception when you want to exit.
Another way would be to put your for-loops inside a function and ‘return’ when you hit your condition.
I really don’t recommend the later two approaches.
class Switch:
def __init__(self):
self._cases = {}
def __call__(self, value):
if value in self._cases:
case = self._cases[value]
elif "default" in self._cases:
case = self._cases["default"]
else:
return
case()
def case(self, *case_results):
def wrapper(case_func):
for case_result in case_results:
self._cases[case_result] = case_func
return case_func
return wrapper
def default(self, case_func):
self._cases["default"] = case_func
return case_func
switch = Switch()
case = switch.case
default = switch.default
@case(1)
@case(2)
def on_one_or_two():
print("One or two")
@default
def default():
print("DEFAULTED")
switch(1)
Python makes them pretty easy though, as you say
Or even very amusing
import inspect
class Switch:
def __init__(self, value):
self._locals = inspect.currentframe().f_back.f_locals
self.value = value
def __enter__(self):
self.local_dict = self._locals.copy()
def __exit__(self, *args, **kwargs):
default = None
chained_functions = {}
cases = {}
for name, attr in self._locals.items():
if self.local_dict.get(name) is attr:
continue
try:
annotations = attr.__annotations__
except AttributeError:
continue
try:
match_cases = annotations['return']
except KeyError:
# Allow short hand default case by name
if name == "default":
default = attr
continue
try:
chain = annotations["follow"]
except KeyError:
pass
else:
chained_functions[chain] = attr
# Short hand for default without list of cases
if match_cases == "default":
default = attr
continue
# Assume list of cases
for case in match_cases:
# Look for default case in list
if case == "default":
default = attr
else:
cases[case] = attr
def evaluate_func(func):
if "follow" in func.__annotations__:
func(None)
else:
func()
if func in chained_functions:
evaluate_func(chained_functions[func])
for case, case_func in cases.items():
if case == value:
evaluate_func(case_func)
return
if callable(default):
default()
value = 5
with Switch(value):
def a() -> [1]:
print("One or two")
# If a is evaluated, so is b
def b(follow:a) -> [3,4,5]:
print("Three, four or five")
# If b is evaluated, so is c
def c(follow:b) -> [6]:
print("Six")
def default():
print("DEFAULTED")
But seeing as you asked so nicely, here’s GOTO
import sys
from os import path
try:
import bpy
text_name = path.split(__file__)[1]
text_block = bpy.data.texts[text_name]
source = text_block.as_string()
except ImportError:
import inspect
source = inspect.getsource(sys.modules[__name__])
class StupidParser:
parser = None
def __init__(self, source):
self.__class__.parser = self
self.source = source
self.stack = []
self.goto_indices = {}
self.index = 0
def read_label(self, line):
line = line.lstrip()
name = ''.join((c for c in line[line.find("=") + 1:] if c.isalpha()))
return name
def set_index(self, index):
self.index = index
def parse(self):
gotos = {}
is_protected = True
labelled_stack = []
for line in self.source.split("
"):
if "mai""n" in line:
is_protected = False
continue
if is_protected:
continue
line = line[4:]
if "LABEL" in line:
label_name = self.read_label(line)
gotos[label_name] = len(labelled_stack)
else:
labelled_stack.append(line)
for index, line in enumerate(labelled_stack):
if "GOTO" in line:
key = "GOTO ="
call_name = self.read_label(line)
header_line = line[:line.find("GOTO")]
target = gotos[call_name]
call_code = "{}.parser.set_index({})".format(self.__class__.__name__, target)
labelled_stack[index] = "{}{}".format(header_line, call_code)
self.file = labelled_stack
print(self.file)
def evaluate(self):
locals_dict = {}
self.index = 0
print(self.file)
file = self.file
while self.index < len(file):
line = file[self.index]
self.index += 1
exec(line, locals_dict, globals())
parser = StupidParser(source)
parser.parse()
parser.evaluate()
def main():
LABEL = "do"
print("DONE")
GOTO = "do"