Posts Tagged ‘ generator

Understading Python generators in Maya

Python has the ability to create generator functions. See Python docs here:
http://docs.python.org/tutorial/classes.html#generators
http://docs.python.org/reference/expressions.html#generator-expressions
http://docs.python.org/reference/expressions.html#yieldexpr
http://docs.python.org/reference/simple_stmts.html#yield

What are they? From the Python docs (above):

“Generators are a simple and powerful tool for creating iterators. They are written like regular functions but use the yield statement whenever they want to return data. Each time next() is called, the generator resumes where it left-off (it remembers all the data values and which statement was last executed)…”

You can imagine that they are like a normal function looping over a list of items, or doing some work on each of the items in the list. The difference is, rather than looping over the whole list when the function is executed, the function pauses after each loop, waiting for you to tell it to continue.

This allows you the ability to make tools that can execute over a list of items, only executing on the next item when you tell it too.

Example below. In this example, the user writes a generator function that will create a locator placed at each vert passed into the function. But the locators are created one by one, only when we call to the generator function:

# Python code
import maya.cmds as mc

# Define our generator function
def generateLocs(verts):
    for v in verts:
        pos = mc.pointPosition(v, world=True)
        loc = mc.spaceLocator(position=pos)
        # Use 'yield' instead of 'return':
        yield loc[0]

Now put the code to use:

# First, select a polygonal object.  Then convert to verts:
verts = mc.ls(mc.polyListComponentConversion(toVertex=True), flatten=True)

# create our generator object called "loc":
loc = generateLocs(verts)

# each time we call to loc.next(), a new locator is created, base on
#  the next vert in the list:
print loc.next()
# locator1
print loc.next()
# locator2
print loc.next()
# locator3

# etc...

This post is also over on my Mel Wiki