I want to know a goto command.

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 :wink:

“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:

  1. python does not in fact have a goto statement
  2. blender contains a full python 3 interpreter, it supports all statements that python 3 supports
  3. bpy is not blender python. It is a python module that exposes the blender api to the python interpreter

There are a couple of ways to break out of nested for-loops.

  1. Best practice is to add an ‘exit’ boolean to each for-loop and check that for an exit signal.

exit = False
for i in range(0, 100):
  for j in range(0, 100):
    if &lt;some condition&gt;
      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.

A: Python command within script to abort without killing Blender


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() -&gt; [1]:
        print("One or two")
        
    # If a is evaluated, so is b
    def b(follow:a) -&gt; [3,4,5]:
        print("Three, four or five")
    
    # If b is evaluated, so is c
    def c(follow:b) -&gt; [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 &lt; 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"