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

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.

主站蜘蛛池模板: 正镶白旗| 蓬溪县| 渭南市| 锡林郭勒盟| 淮北市| 泾源县| 都江堰市| 舒兰市| 永修县| 星子县| 武山县| 宜黄县| 平塘县| 海原县| 秦安县| 仁布县| 临漳县| 隆化县| 阿巴嘎旗| 方正县| 兖州市| 乐山市| 沅陵县| 团风县| 涪陵区| 澄迈县| 黑水县| 平顶山市| 瑞丽市| 栾城县| 湟中县| 错那县| 白朗县| 铁力市| 浑源县| 兴义市| 南昌市| 奇台县| 日喀则市| 五大连池市| 华亭县|