一半君的总结纸

听话只听一半君

#61 怎样让mel函数(proc)接受多个(或者可选)参数(flags or arguments)?

不幸的是, MEL 自身不支持重载函数声明(overloaded procedure declarations), 不确定个数的参数或者有默认值的参数,所以如果想要proc能够支持不定个数的参数,就得自己做些额外的工作(其实现在已经没意义了,因为现在可以用pyhon了),比如:

processPolys -planar;

processPolys -textured -triangles;

如果想像上面那样,让processPolys可以支持只使用数量不确定的flag,有两种方法可以做到. 但是, MEL 要求的对参数的用法比较“严格”.

Method #1: 拼长字符串当做唯一的参数

第一种方法是把所有想传递的参数拼成一个长的字符串,然后在待运行的proc里再将其分解然后解析.

global proc processPolys( string $argList )
{
// 设置参数的默认值
int $optionPlanar = false;
int $optionTriangles = false;

string $argData[];

// 把传进来的长字符串拆分成参数数组,分隔符是空格
tokenize $argList " " $argData;

for ( $arg in $argData )
{
switch( $arg )
{
case "-planar":
$optionPlanar = true;
break;
case "-triangles":
$optionTriangles = true;
break;
// A NULL string will parse to a single token?
case ""
break;
default:
error ( "Unsupported flag: " + $arg );
}
}

// 继续脚本运行.
}

Examples

processPolys "-planar -triangles";

// Single argument
processPolys "-planar";

// Nope, not this way...
processPolys;
// Error: Line 1.13: Wrong number of arguments on call to processPolys. //

// To use defaults, specify empty string to declare no options
processPolys "";

Method #2: 用字符串数组当参数

另一种达成”不确定个数的参数”效果的方法是用一个字符串数组当参数,解析方法和上面一模一样. 唯一不同就是用不着tokenize来拆分字符串了.

global proc processPolys( string $argData[] )
{
// 设置默认值
int $optionPlanar = false;
int $optionTriangles = false;

// 用不着把字符串变成数组了.

// 现在根据参数进行处理

// ... 和上面一样.
}

Examples

processPolys { "-planar", "-triangles" };

// Single argument
processPolys { "-planar" };

// Nope, not this way...
processPolys;
// Error: Line 1.9: Wrong number of arguments on call to processPolys. //

// To use defaults, specify empty array to declare no options
processPolys { };

Tuesday, March 27, 2001

加强版:

其实现在有了Python就完全用不着像上面那样了,经常见到*args **kwargs,至于为什么要这么缩写,因为他们的英语分别是arguments, 和keyword arguments,不是非要用这两个词,只是他们是习惯而已,你也可以*xyz,**myArgs.他们的用法简述如下
假设我们有下面的函数定义(function definition)

def func(a, b, c, d):
    print(a, b, c, d)

# 试用一下
>>> func(1,2,3,4)
(1, 2, 3, 4)

如果在函数定义里我们用*args,那么

def func(*args):
    print args

# 试用一下
>>> func(1,2,3)
(1, 2, 3)
>>> func(1,2)
(1, 2)
>>>

由此可见*args是可以接受不确定个数的参数的,然后把他们放在一个元组(tuple)里,这个功能叫做收集参数(collecting arguments)
而**args是unpacking dictionary的时候用的,比如

def func(a, b, c, d):
    print (a, b, c, d)

# 试用一下,此时虽然上面函数定义没用关键字参数(keywords arguments),但是我们下面调用函数的时候依然可以使用关键词参数
>>> func(b=3,c=2,a=3,d=5)
(3, 3, 2, 5)

# 下面意思是func可以接受可变个数的位置参数
def func(**kwargs):
    print kwargs

# 试用一下
>>> func(b=3,c=2,a=3,d=5)
{'a': 3, 'c': 2, 'b': 3, 'd': 5}
>>> func(b=3,c=2)
{'c': 2, 'b': 3}

由此可见**kwargs 出现在function definition里的时候,他可以接受任意个数的位置参数,并且放在一个字典(dictionary)里
此外 上面的两种方式是可以混合使用的,比如

def func(a,b=3,*args,**kwargs):
    print a,b
    print 'args:',args
    print 'kwargs:',kwargs

# 试用一下
>>> func(2)
2 3
args: ()
kwargs: {}
>>> func(2,4)
2 4
args: ()
kwargs: {}
>>> func(2,4,5)
2 4
args: (5,)
kwargs: {}
>>> func(2,4,5,7)
2 4
args: (5, 7)
kwargs: {}
>>> func(2,4,5,7,x=3)
2 4
args: (5, 7)
kwargs: {'x': 3}
>>> func(2,4,5,7,x=3,y=6)
2 4
args: (5, 7)
kwargs: {'y': 6, 'x': 3}

*args *kwargs 也可以出现在调用函数的时候,但作用就是和上面的例子恰好相反:解包参数(unpacking arguments)

def func(a, b, c, d):
    print (a, b, c, d)

# 试用一下 这里被传递给func的参数args是个tuple,他在被传递的时候会自动被解开成一系列的单独的参数
>>> args=(1,2)
>>> args+=(3,4)
>>> args
(1, 2, 3, 4)
>>> func(*args)
(1, 2, 3, 4)

def func(a, b=3, c=2, d=22):
    print (a, b, c, d)

# 试用一下 这里被传递给func的参数args是个dictionary,他在被传递的时候会自动被解开成key/value对
>>> kwargs={'a':1,'b':33,'c':44}
>>> func(**kwargs)
(1, 33, 44, 22)

ps: 此外有时候我们想拼一个长的字符串f_u_ck,在MEL里你可能会需要这样:

string $a="f";
string $b="u";
string $c="c";
string $d="k";
string $myObj = $a+"_"+$b+"_"+$c+$d;

但是在python里就不需要了

# 方法1
a,b,c,d = 'f','u','c','k'
myObj='%s_%s_%s%s' % (a,b,c,d)

# 方法2
myObj='%(name1)s_%(n2)s_%(anything)s%(something)s' % {'name1':a,'n2':b,'anything':c,'something':d}

# 方法3
myObj='{0}_{1}_{2}{3}'.format(a,b,c,d)

# 方法4
myObj='{name1}_{n2}_{anything}{something}'.format(name1=a,anyting=c,something=d,n2=b)

# 方法5 这才是我想说的,因为可以用**
myObj='{a}_{b}_{c}{d}'.format(**locals())

在最后一种方法里,因为format是一个函数,而locals()是一个builtin函数,他的返回值是一个所有当前namespace中已定义的变量和值组成的dictionary, 而**放在一个dictionary前面如上所述,可以将其unpack,并把对应的key/value告诉函数format, 虽然他多告诉了很多没用到的,不过没有关系,如果用到了的,那么他们就会替换前面字符串里的相应部分

Advertisements

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

%d 博主赞过: