How I learned a Python trick from a JavaScript book
Tags: scopes, maya, python, javascript
Published: 2019-07-10 12:30:14

---
title: How I learned a Python trick from a JavaScript book
published: true
tags: scopes,maya,python,javascript
canonical_url: https://medium.com/@yairmorr/how-i-learned-a-python-trick-from-a-javascript-book-d5c9c89fc5c3
---

![](https://cdn-images-1.medium.com/max/1024/1*naasd4ZbU2oKvS6cDj33vQ.jpeg)

I’m working on a nice little tool for project management in Autodesk Maya. It has a few drop down menus that contain folders and files inside a project root directory. This tool automates a few steps and helps the user quickly switch from one project to another without browsing for files.

![](https://cdn-images-1.medium.com/max/1024/1*wfA0Hgq8oPMdhFc4Cuwlqw.png)<figcaption>Maya Project Browser, how it looks as it is in development</figcaption>

While working on this tool, I ran into an annoying scope issue with my algorithm when iterating over a loop, that prevented me from assigning the value I wished to a variable. I wanted to track an index value for each drop down menu, and instead I got the same value for all menus.

I then remembered reading on a very similar issue on my favourite JavaScript book series — _You Don’t Know JS_ by _Kyle Simposon_. In his book [Scope & Closures](https://www.amazon.com/dp/B00IV3J2A2/ref=cm_sw_r_cp_awdb_t1_qMBjDbYMR0TFP), he explains that while assigning a variable to a function from inside of a loop captures a copy of that variable, it is still sharing the same scope. This means that each function call inside my loop refers to a copy of the variable that eventually points to the same value. But I write my tool in Python and not JS, as it is the language used in Maya for writing scripts.

From my experience in visual effects, problems are usually similar across different platforms, and the solutions are usually similar as well. But can this bit of wisdom serve me in the world of code? Not surprisingly, the answer is yes! I figured if this scope issue happens in JavaScript, it might as well happen in Python.

Simpson’s solution in Scope & Closures to this problem was to pass that variable to the same function, but enclosing it inside an IIFE. Now you can assign that variable to a local variable inside the IIFE (which is inside the loop). The local variable now holds a copy of the value for each iteration and passes that value to the function and it does not change after the loop iterates again and again.

In Python, as far as I can tell, there are no IIFEs and no blocks of code, like in JavaScript. To solve this issue, I just enclosed the code inside the loop in a new method and called this method within the loop. This new method essentially serves as an inner scope, similar to JavaScript’s IIFE, which “locks” the value I require and pass it down safely to the method inside.

This is basically it! Following below is a detailed explanation of how I implemented this in my code.

My script has a main class that contains all the methods and variables for the tool.  
The first method is _initUI()_, which creates a window and adds some buttons and the dropdown menus (Maya’s _cmds.optionMenu()_) and stores them in a dictionary called _self.menus_.

{% gist https://gist.github.com/YairMorr/60d34aa4daf0283bdefcafd3496ffe26 %}

The _cmds.optionMenu()_ function in line 6 above takes a label for the dropdown menu, which is _“Menu”+str(i)_. The _cc_ attribute passes a callback event handler that executes once a user selects an item from the menu. To pass in additional custom parameters, I use a lambda function and call my event handler _self.indexFolders()_ within it.  
The important part here is the variable _i_ that is passed to every optionMenu’s _indexFolders()_ method. It holds the dropdown menu’s index, the variable I wish to use later when I want to update the content of my menus.

As it is now, once the script executes, every dropdown menu’s _indexFolders()_ has _i_ passed in each iteration of the loop, but eventually every _indexFolders()_ holds the value _i_ had at the last iteration of the loop, instead of the value _i_ has at the time of declaration. This means that every time I select an item from any optionMenu object, I get the same value (in this case, 3), instead of an index from 0 to 3 for each menu respectively.

In Scopes & Enclosures, Simpson suggests enclosing the body of the loop in a block {} or an IIFE. The solution I found in Python was to put my code in another function and call it within the loop, like this:

{% gist https://gist.github.com/YairMorr/437aeade051f4d4c47951f28ebd7720a %}

The _createMenu()_ method has the exact line of code as in the previous snippet’s line 6. I just changed the name of the variable from the loop’s global _i_ to the method’s local _level_. Now I call _createMenu()_ from within my for loop and assign it _i_ every time, and _createMenu()_ assigns it’s local _level_ to the event handler with the value I intended it to have — the index for the loop.  
Now each optionMenu object has a different value, based on it’s index, and I can use that value to know exactly which menus to update!

Learning JavaScript is great, and it’s even better when the knowledge I acquire helps me indirectly solving problems with other languages and establishing a deeper understanding of coding and computer science.