Functions and variable references

Hello pyRevit friends :slight_smile:

Another basic python question from me.

If I have a working piece of code but if I want to put a part of it in a function I start getting errors like:

UnboundLocalError: Local variable '...' referenced before assignment.

So there has to be something I don´t understand about functions and variable assignment.

Here is an example.

def SelectSheets():
    ops = {}
    AllSheets = []
    AllSheets.extend([MyOptionSheet(x) for x in Sheets if not x.IsPlaceholder])
    ops['0_All'] = AllSheets

    for SheetSetName, SheetsBySheetSet in zip(SheetSetNames,SheetsBySheetSet):
        sheets = []
        for Sheet in SheetsBySheetSet:
            sheets.append(MyOptionSheet(Sheet))
        ops[SheetSetName] = sheets

    if OpenSheets:
        selectedSheet = forms.SelectFromList.show(ops, 'Print Sheets PDF', group_selector_title='Sheet Sets', default_group= '0_Open', multiselect=False)
    else:
        selectedSheet = forms.SelectFromList.show(ops, 'Print Sheets PDF', group_selector_title='Sheet Sets', default_group= '0_All', multiselect=False)

    return selectedSheet

BrowserSortParameter = BrowserSortParameter()
OpenSheets = OpenSheets()
Sheets = Sheets()
SheetSetNames = SheetSetNames()
SheetsBySheetSet = SheetsBySheetSet()
SheetSetNames, SheetsBySheetSet = AddOpenSheets()

if viewports or ViewportFromSectionLine:
    selectedSheet = SelectSheets()

This gives me the error:
UnboundLocalError: Local variable 'SheetsBySheetSet' referenced before assignment.

So the function SelectSheets() recognizes the parameter SheetSetNames without a problem, but it freaks out because it doesn’t know the variable SheetsBySheetSet.

I can make it work by sending the required variable to the function like this:

def SelectSheets(SheetsBySheetSet):
    .........

if viewports or ViewportFromSectionLine:
    selectedSheet = SelectSheets(SheetsBySheetSet)

So what am I missing here, why does it work for some variables and not for others?
Would be great if someone could explain why this happens.

I know that a variable that is defined in a function dies with the function, but I dont understand why I cant reference a variable that has been defined outside the function before the function was called.

Kind Regards :slight_smile:

I don’t even know where to start. That code is honestly painful to look at.

I don’t think your issue is referencing a global variable. You can reference global variables inside of a function without issue. Your issue is with the names you are using for your variables. You are using the same name for multiple things all over the place. You are just asking for errors by doing that.

Try this version with unique names out. I think it should work fine.

def SelectSheets():
    ops = {}
    AllSheets = []
    AllSheets.extend([MyOptionSheet(x) for x in Sheets if not x.IsPlaceholder])
    ops['0_All'] = AllSheets

    for sheet_set_name, sheets_by_sheet_set in zip(SheetSetNames,SheetsBySheetSet):
        sheets = []
        for Sheet in sheets_by_sheet_set :
            sheets.append(MyOptionSheet(Sheet))
        ops[sheet_set_name] = sheets

    if OpenSheets:
        selectedSheet = forms.SelectFromList.show(ops, 'Print Sheets PDF', group_selector_title='Sheet Sets', default_group= '0_Open', multiselect=False)
    else:
        selectedSheet = forms.SelectFromList.show(ops, 'Print Sheets PDF', group_selector_title='Sheet Sets', default_group= '0_All', multiselect=False)

    return selectedSheet

BrowserSortParameter = BrowserSortParameter()
OpenSheets = OpenSheets()
Sheets = Sheets()
SheetSetNames = SheetSetNames()
SheetsBySheetSet = SheetsBySheetSet()
SheetSetNames, SheetsBySheetSet = AddOpenSheets()

if viewports or ViewportFromSectionLine:
    selectedSheet = SelectSheets()

By the way if you want to know why you are getting that error there is a good video that explores the issue you are having. Local and Global Variable Lookup Weirdness in Python - YouTube

2 Likes

Hello @Nicholas.Miles and thanks for your reply.

I understand that better variable names will prevent mistakes and make the code easier to understand by others, so i will try to use better names in the future.

But about a real mistake, it seems that it was the problem that I used wrong variable names at the zipping. I used the same variable twice:

for SheetSetName, SheetsBySheetSet in zip(SheetSetNames,SheetsBySheetSet):

Correcting this mistake solved my problems.

The video you provided is really interresting, this helps a lot for understanding global and local variables.

Thanks for your help :slight_smile:

A good practice would be to use plural for variable and containers of multiple elements so that when use in an iteration you can use singular.

for thing in things: