官术网_书友最值得收藏!

Learning to use list comprehensions

Let's look at list comprehensions in depth now that we've used simpler versions several times. It's a powerful-yet-simple syntax that has been in Python since version 2.0. List comprehensions are described very succinctly and with very clear examples in PEP 202 at http://www.python.org/dev/peps/pep-0202/.

Tip

A Python Enhancement Proposal (PEP) is a design document for a Python feature (or similar). Often it can be very long and technical. PEP 202 is a very straightforward PEP that is well worth reading, consisting of three paragraphs and one example block. Some other notable PEPs will be mentioned in this book and in the appendices.

Oh, and PEP 1 describes PEPs and the PEP process, of course.

A list comprehension has the following form:

[<map> for <variable> in <selection> | if <predicate>]

The map is the item that ends up in the list. It can be the same as variable if no transformation is to take place. It's commonly a function that transforms variable. The variable is the item in selection being iterated over. The selection is the sequence being iterated. The predicate is optional expression, but is a function that takes variable and returns True if the item should be included in the result or False if not. For example, the following list comprehension generates a list of uppercase letters from an input string:

>>> s = 'hi!'
>>> [c.upper() for c in s if c.isalpha()]
['H', 'I']

In the preceding example:

  • s is the selection.
  • c is the variable.
  • c.alpha() is the predicate.
  • c.upper() is the map.

Let's look at some more simple examples.

>>> [i + 1 for i in [1, 2, 3]]
[2, 3, 4]
>>> [i for i in [1, 2, 3] if i > 2]
[3]
>>> [(i, chr(i)) for i in [65, 66, 67]]
[(65, 'A'), (66, 'B'), (67, 'C')]

You can also nest list comprehensions, but we'll avoid that for this book. PEP 202 includes many examples of nested list comprehensions, and they can be very useful. However, only attempt them once you are comfortable with regular list comprehensions.

List comprehensions are vital when writing composable code, and we'll use them repeatedly throughout the rest of the book. If you're still uncomfortable, fire up a Python interpreter and get comfortable!

Implementing is_exact_type

With our experience building composable code and using list comprehensions, let's take a stab at creating an is_exact_type function that will replace the need for the exactType parameter in Maya's listing functions.

First, we need to choose a place to put the function. The minspect.py file we created in Chapter 1, Introspecting Maya, Python, and PyMEL, is a reasonable location for it. Let's put the new is_exact_type function there.

def is_exact_type(node, typename):"""node.type() == typename"""return node.type() == typename

The is_exact_type function is very simple, checking whether two type strings are equal.

We can add more predicates just as easily. The following is_type function returns True if the type of node has a MEL type of typename or a subclass.

def is_type(node, typename):
    """Return True if node.type() is typename or
    any subclass of typename."""
    return typename in node.nodeType(inherited=True)

Let's look at some examples that use our new predicates. Notice how is_exact_type matches only the camera node, but is_type finds the joint, sphere transform, and camera nodes.

>>> objs = pmc.joint(), pmc.polySphere(), pmc.camera()
>>> [o for o in pmc.ls() if minspect.is_exact_type(o, 'camera')]
[...nt.Camera(u'cameraShape1')]
>>> [o for o in pmc.ls() if minspect.is_type(o, 'transform')]
[...nt.Joint(u'joint1'), nt.Transform(u'pSphere1'), nt.Transform(u'camera1')]

When a list comprehension uses a simple predicate, we may not even want to create a function for it. We can define our predicate expression right in the comprehension. The following code selects all joints with a positive x translation:

>>> j1, j2 = pmc.joint(), pmc.joint()
>>> j2.translateX.set(10)
>>> [j for j in pmc.ls(type='joint') if j.translateX.get() > 0]
[nt.Joint(u'joint2')]

Though this code may be less familiar for a MEL guru, it is much more easily understandable for anyone used to Python. And more importantly, it is far easier to maintain, and especially compose.

Saying goodbye to map and filter

Instead of list comprehensions, it used to be popular to use the built-in map and filter functions. For example, the two preceding examples could be written as follows:

>>> map(lambda i: i + 1, [1, 2, 3])
[2, 3, 4]
>>> filter(lambda i: i > 2, [1, 2, 3])
[3]

In some cases, the map and filter form can actually be more concise than the list comprehension form, as demonstrated by finding all root joints.

>>> filter(is_root_joint, pmc.ls())
[nt.Joint(u'joint1')]
>>> [o for o in pmc.ls() if is_root_joint(o)]
[nt.Joint(u'joint1')]

In full disclosure, I sometimes use map and filter when it's more concise. But as a rule, use list comprehensions. We'll use list comprehensions exclusively instead of map and filter in this book, to reduce confusion and enforce style.

If you're interested in why this book and the Python community at large encourages list comprehensions of map and filter, a simple Internet search should turn up lots of good reading. List comprehensions are now Pythonic and map and filter are not.

Tip

Refer to Chapter 1, Introspecting Maya, Python, and PyMEL, for a discussion of what Pythonic means.

主站蜘蛛池模板: 丹江口市| 西宁市| 东台市| 舒兰市| 关岭| 安西县| 女性| 绥阳县| 上饶县| 海门市| 漾濞| 安岳县| 石首市| 丽水市| 平阴县| 巫溪县| 浠水县| 北宁市| 海南省| 凌源市| 六枝特区| 开化县| 九龙县| 阿尔山市| 新闻| 南昌市| 潞西市| 景宁| 胶州市| 峨眉山市| 怀安县| 巨野县| 许昌县| 泰州市| 乡城县| 民和| 长岭县| 济南市| 灵宝市| 卫辉市| 中阳县|