I’ve been plowing through Automate the Boring Stuff with Python by Al Sweigart. Since I generally skip over chapters with scary names or giant blocks of text, the bit about nested dictionaries and lists went blazing right over my head. But when I wanted to start shaping objects in Blender into letters (as pictured above), I went right back to it because they’re actually quite useful.
Alright. Here we go.
A nested list is actually just a list within a list. Sounded completely useless to me when I first read about it. Why would you want to shove more things into an already crowded set of things?
Turns out it’s a sanity preservation thing. It’s just far easier to see elements clustered into bundles before sending them through a loop.
Say you want to put a bunch of objects into the shape of a letter H. For our purposes today, the objects are little silver rings. You can make the basic shape with about 12 of them—arranged to be 1 Blender unit high and 1 Blender unit wide. Like so.
Coordinates here are represented with two digits, an X and a Y. Keep in mind that when working in a 3-D environment like Blender, you’ll have 3 axes–X,Y, and Z. In my code, I’ve used X for the length, Z for the height, and set Y to 0 because my H doesn’t require depth.
To start the script, I put the coordinates into a basic list and looped them through the location data of selected objects, like so:
#SPOILER ALERT: THIS SCRIPT DOESN'T WORK hList = [0,0,0,0,.25,0,0,.5,0,0,.75,0,0,1,.3,0,.5,.6,0,.5,1,0,1,1,0,.75,1,0,.5,1,0,.25,1,0,0] index=0 for obj in bpy.context.selected_objects: obj.location.x=hNest[index] obj.location.y=hNest[index+1] obj.location.z=hNest[index+2] index+=3
Then I ran the script and realized one of my coordinates was really damn off, and I had no idea which one it was.
Here’s where nesting came in handy. You can break each X,Y,Z cluster into its own list within the greater H list—that way, you can see the elements more clearly as [X,Y,Z].
How Do You Write a Nested List?
When nested, the hList above becomes this:
hNest = [ [0,0,0] , [0,0,.25] , [0,0,.5] , [0,0,.75] , [0,0,1] , [.3,0,.5] , [.6,0,.5] , [1,0,1] , [1,0,.75] , [1,0,.5] , [1,0,.25] , [1,0,0] ]
To retrieve items from a nested list, all you have to do is give the list name, the position of the stuffed list, and the position of the item within that stuffed list.
The added benefit of writing the coordinates into a nested list is that when you call len(hNest), it’ll return the number of elements not counting the stuffing. Meaning the above list would return 5, not 15.
Since I only want one object at each x,y,z, cluster, I can use that to tell the program how many times total to run.
Here’s a breakdown of the script used to make the gif at the top. It basically takes whatever objects you have selected and scatters them around a scene, then reassembles them into letters at frame 60. Copy/paste version below.
import bpy import random hNest = [ [0,0,0] , [0,0,.25] , [0,0,.5] , [0,0,.75] , [0,0,1] , [.3,0,.5] , [.6,0,.5] , [1,0,1] , [1,0,.75] , [1,0,.5] , [1,0,.25] , [1,0,0] ] iNest = [[1.5,0,0] , [1.5,0,.25] , [1.5,0,.5] , [1.5,0,1]] for obj in bpy.context.selected_objects: obj.location.x=random.uniform(-8,8) obj.location.y=random.uniform(-8,8) obj.location.z=random.uniform(0,15) obj.keyframe_insert(data_path="location",frame=0) selObj =  for obj in bpy.context.selected_objects: selObj.append(obj.name) ObjElem=0 i=0 while i < len(hNest): obj = bpy.data.objects[selObj[ObjElem]] obj.location.x=hNest[i] obj.location.y=hNest[i] obj.location.z=hNest[i] i+=1 ObjElem+=1 obj.keyframe_insert(data_path="location",frame=60) i=0 while i < len(iNest): obj = bpy.data.objects[selObj[ObjElem]] obj.location.x=iNest[i] obj.location.y=iNest[i] obj.location.z=iNest[i] i+=1 ObjElem+=1 obj.keyframe_insert(data_path="location",frame=60)