Thursday, July 11, 2013

Using Python Iterables

Lets take a look at how we can use iterables in our workflow when rigging for writing procedural methods or classes. Im talking rigging modules, custom nodes, tools, etc..

Lets first understand what are iterables.

Iterables

The idea of iteration can be easily seen in a for loop where we read the items in a list one by one and print them.
numbers = [1, 2, 3, 4, 5]
for i in numbers:
    print i
Result:
1
2
3
4
5

The list numbers is an iterable. When you instance a list through list comprehension you are creating an iterable.
numbers = [x * x for x in range(5)]
for i in numbers:
    print i
Result:
0
1
4
9
25

Other examples of iterables are strings, files, dictionaries, etc... Iterables are useful because they can be read as often as you want.

To further understand iterables lets discuss generators.


Generators

Generators are what we call iterators. These we can only iterate over one time. The reason for this, is because unlike iterables that store the values in memory, generators create the values when they are queried.
numbers = (x*x for x in range(5))
for i in numbers:
    print i
Result:
0
1
4
9
25

Notice here we use parenthesis () and not brackets [ ]. Once we iterate over these values, we are done, we can't iterate read it again.

Finally we can take a look at yield.

Yield

Yield is a function that behaves similar to a return call. However, what it returns is a generator.

This is nice because now if we can iterate over all nodes in the current scene that fit a specific requirement for example. 

Lets iterate over all 3 joints in the scene:
import maya.cmds as cmds
def iter():
    for node in cmds.ls(type="joints"):
        yield node

joints = iter()

for joint in joints:
    print joint
Result:
joint1
joint2
joint3

If your writing your own class that creates a custom node (usually accompanied by an identifier under a  custom attribute) you can write a class method to iterate over all custom nodes in the scene with something like this:
@classmethod
def iter(cls):
    for node in cmds.ls(type="network"):
        if cmds.attributeQuery("type", exists=True, node=node):
            if cmds.getAttr(node + ".type") == cls.TYPE:
                yield cls(node)

In this case the example class will create a custom node of type network and it searches for a custom attribute as an identifier called type. The class has an attribute TYPE. We've found our custom node if the node attribute value matches the value in TYPE.


0 comments:

Post a Comment