Maya Python工具包开发:多行按钮命令格式化技巧问询
解决Maya Python按钮命令的缩进与可读性问题
嘿,我完全懂你现在的困扰——在写Maya工具的按钮命令时,用三引号包多行代码却不得不删掉所有缩进才能避免unexpected indentation错误,代码瞬间变得乱糟糟的,可读性大打折扣。别急,这里有几个实用的技巧帮你搞定这个问题:
技巧1:用textwrap.dedent()自动清理多余缩进
Python的textwrap模块里的dedent()方法可以自动移除所有代码行共同的前导空白,这样你就能在保持代码缩进格式的同时,避免Maya解析字符串时的缩进错误。
用法很简单,先导入模块,然后把你的三引号字符串用dedent()包裹,注意要在三引号前加一个反斜杠\来去掉第一行的空行:
import textwrap import maya.cmds as cmds form = cmds.formLayout(numberOfDivisions=3) add_button = cmds.button(label="Add Selected", command=textwrap.dedent("""\ selection = cmds.ls(sl=True) list_label = cmds.text('attachToList', query=True, label=True) split_list = list_label.split(', ') split_list[0] = split_list[0].replace('Attach to: ', '') list_items = split_list for each in selection: if not each in list_items: list_items.append(each) list_items = [item for item in list_items if item != ""] cmds.text('attachToList', edit=True, label='Attach to: ' + ', '.join(list_items)) """)) # 其他按钮同理处理 remove_button = cmds.button(label="Remove Selected", command=textwrap.dedent("""\ selection = cmds.ls(sl=True) list_label = cmds.text('attachToList', query=True, label=True) split_list = list_label.split(', ') split_list[0] = split_list[0].replace('Attach to: ', '') list_items = split_list for each in selection: if each in list_items: list_items.remove(each) cmds.text('attachToList', edit=True, label='Attach to: ' + ', '.join(list_items)) """)) clear_button = cmds.button(label="Clear", command="cmds.text('attachToList', edit=True, label='Attach to: ')") cmds.formLayout(form, edit=True, attachForm=[(add_button, "left", 5), (clear_button, "right", 5)], attachPosition=[(add_button, "right", 2, 1), (remove_button, "left", 2, 1), (remove_button, "right", 2, 2), (clear_button, "left", 2, 2)]) cmds.setParent("..")
技巧2:改用函数/ lambda(更推荐的最佳实践)
其实Maya的button命令的command参数不止能接受字符串,还能直接传入函数对象——这才是更规范、更易维护的写法,完全不用再纠结字符串缩进的问题,代码逻辑也更清晰。
比如把按钮的逻辑封装成独立的函数,然后直接把函数名传给command参数:
import maya.cmds as cmds def handle_add_selected(*args): # 这里保持正常的代码缩进,可读性拉满 selection = cmds.ls(sl=True) list_label = cmds.text('attachToList', query=True, label=True) split_list = list_label.split(', ') split_list[0] = split_list[0].replace('Attach to: ', '') # 建议用copy避免修改原列表,防止意外bug list_items = split_list.copy() for each in selection: if each not in list_items: list_items.append(each) # 用列表推导式简化空字符串过滤逻辑 list_items = [item for item in list_items if item] cmds.text('attachToList', edit=True, label='Attach to: ' + ', '.join(list_items)) def handle_remove_selected(*args): selection = cmds.ls(sl=True) list_label = cmds.text('attachToList', query=True, label=True) split_list = list_label.split(', ') split_list[0] = split_list[0].replace('Attach to: ', '') list_items = split_list.copy() for each in selection: if each in list_items: list_items.remove(each) cmds.text('attachToList', edit=True, label='Attach to: ' + ', '.join(list_items)) form = cmds.formLayout(numberOfDivisions=3) # 直接传入函数名即可,不用加引号 add_button = cmds.button(label="Add Selected", command=handle_add_selected) remove_button = cmds.button(label="Remove Selected", command=handle_remove_selected) clear_button = cmds.button(label="Clear", command=lambda *args: cmds.text('attachToList', edit=True, label='Attach to: ')) cmds.formLayout(form, edit=True, attachForm=[(add_button, "left", 5), (clear_button, "right", 5)], attachPosition=[(add_button, "right", 2, 1), (remove_button, "left", 2, 1), (remove_button, "right", 2, 2), (clear_button, "left", 2, 2)]) cmds.setParent("..")
这里要注意:Maya会在触发按钮时给回调函数传递一个参数(按钮的名称),所以我们的函数要加*args来接收这个参数,避免报错。对于简单的逻辑,也可以用lambda来快速定义(比如上面的Clear按钮)。
这种方式的优势很明显:代码结构清晰、缩进正常、逻辑可以复用(比如你可以提取出解析列表标签的公共函数),还能避免字符串解析带来的潜在问题(比如变量名冲突、特殊字符转义等)。
总结
- 如果只是临时快速调整,
textwrap.dedent()能快速解决缩进问题; - 长期来看,使用函数作为回调是Maya工具开发的最佳实践,代码更易维护和调试。
内容的提问来源于stack exchange,提问作者AndrewB
相关产品推荐
相关产品推荐

