pythonの引数をmaya.cmds風にしてみる。

これは Maya Advent Calendar 2018 12月21日の記事です。

こんなツイートを見かけたので 自分なりに仕組みを考えてみました

maya.cmds風の引数にしてみたい

maya.cmdsのソースを見てみよう

まずはmaya.cmdsのソースを見てみようと思ったのですが...

maya.cmds.__file__
// Result: <module 'maya.cmds' from 'C:\Program Files\Autodesk\Maya2018\Python\lib\site-packages\maya\cmds\__init__.pyc'> //

f:id:ryunnnu:20181219100903p:plain

ん?

f:id:ryunnnu:20181219100950p:plain

なんにも書いてないじゃん!?!?
どうやって読み込んでるの!?



cmdsのソースが見れない

調べたところmayapyで外部からcmdsを使うときなんかは

import maya.standalone
maya.standalone.initialize(name='python')

ってのを実行しないとcmdsコマンドが使えないそうです。 maya.standaloneもコンパイルされてたのでソースを見ること叶わず...

help(maya.standalone)
Help on module maya.standalone in maya:

NAME
    maya.standalone

FILE
    (built-in)

FUNCTIONS
    initialize(...)

スタンドアロン アプリケーション ( Maya Python - 07AA )

引数の優先度を調べてみる

仕方ないので自分で調査することに
Mayaコマンドのショートとロングの引数の優先度を調べてみました。

True/False

cmds.ls(sl=True,selection=True)
# Result: [u'pSphere1', u'pCube1', u'pCylinder1'] #
#選択しているものがリストアップされた

cmds.ls(sl=False,selection=False)
# Result: [u'time1',u'sequenceManager1',u'hardwareRenderingGlobals',u'renderPartition',u'renderGlobalsList1',u'defaultLightList1',u'defaultShaderList1',u'postProcessList1',u'defaultRenderUtilityList1',u'defaultRenderingList1',u'lightList1',u'defaultTextureList1',u'lambert1',u'particleCloud1',u'initialShadingGroup',u'initialParticleSE',u'initialMaterialInfo',u'shaderGlow1',u'dof1',u'defaultRenderGlobals',u'defaultRenderQuality',u'defaultResolution',u'defaultLightSet',u'defaultObjectSet',u'defaultViewColorManager',u'defaultColorMgtGlobals',u'hardwareRenderGlobals',u'characterPartition',u'defaultHardwareRenderGlobals',u'ikSystem',u'hyperGraphInfo',u'hyperGraphLayout',u'globalCacheControl',u'strokeGlobals',u'dynController1',u'lightLinker1',u'persp',u'perspShape',u'top',u'topShape',u'front',u'frontShape',u'side',u'sideShape',u'shapeEditorManager',u'poseInterpolatorManager',u'layerManager',u'defaultLayer',u'renderLayerManager',u'defaultRenderLayer',u'polySphere1',u'pSphere1',u'pSphereShape1',u'polyCube1',u'pCube1',u'pCubeShape1',u'polyCylinder1',u'pCylinder1',u'pCylinderShape1'] #
#シーン内のすべてが返された

cmds.ls(sl=True,selection=False)
# Result: [u'pSphere1', u'pCube1', u'pCylinder1'] #
#選択しているものがリストアップされた

cmds.ls(sl=False,selection=True)
# Result: [u'pSphere1', u'pCube1', u'pCylinder1'] #
#選択しているものがリストアップされた
  • True/FalseはショートとロングのどちらかがTrueになるとTrueとなるようです。
  • any関数で処理されているのだと思う。
any([True,True])
# Result: True #

any([False,False])
# Result: False #

any([True,False])
# Result: True #

List

for x in cmds.ls(typ="mesh",type=["transform","camera"]):
    print(x,cmds.nodeType(x)) 
// Result: (u'pSphereShape1', u'mesh')
(u'front', u'transform')
(u'nurbsCircle1', u'transform')
(u'nurbsSphere1', u'transform')
(u'pSphere1', u'transform')
(u'persp', u'transform')
(u'side', u'transform')
(u'top', u'transform')
(u'frontShape', u'camera')
(u'perspShape', u'camera')
(u'sideShape', u'camera')
(u'topShape', u'camera') //
  • typ type どちらも処理される。
  • 文字列,リストの両方が使える。
  • 文字列を一旦リストに格納してから処理を行っているのだと思う。

Num

polySmooth = cmds.polySmooth(divisions=2,dv=0)
cmds.getAttr("%s.divisions" % polySmooth[0])
# Result: 0 #

f:id:ryunnnu:20181218004514p:plain:w400

  • 数値で値を入力するものはショートフラグが優先される。
  • ショートとロングをリストにショート引数が優先になるように格納してからリストの0番を取れば良さそう

実装

とりあえず上記3つの条件を元に関数を作ってみた。

multiArgFunc

sl/selection
False
--------------------------------------------------------------------------------
typ/type
[u'mesh', u'transform', u'camera']
--------------------------------------------------------------------------------
idx/index
[1, 5]
--------------------------------------------------------------------------------
h/help
True
--------------------------------------------------------------------------------
ls
[u'pCubeShape1', u'pCylinderShape1', u'pSphereShape1', u'lambert1', u'frontShape', u'perspShape', u'sideShape', u'topShape']
--------------------------------------------------------------------------------
  1. メインとなる関数側で引数と値を指定
  2. 予めショート/ロング引数とデフォルト値を決めておいてメイン関数で受け取った辞書を処理する
  3. いい感じに値が返ってくる
  4. いい感じに返ってきた値を好き勝手に料理する

こんな感じ

ヘルプやドキュメントが不可欠になると思いますが、cmdsコマンドと似たような事が出来るようになりました。

書いてみたもののあまり使う機会は多くなさそう...?
classで書くともう少し拡張性は高くなるのですかね...?あまり書かないのでよくわからないですが...
help()で返ってくる簡易ヘルプみたいなのが設定出来たら良いかもしれません。

おわり

最後投げやりになってしまいましたが、可変長引数を利用して面白いものが出来たのではと思います。

明日はPatriotさんの記事です。 「ワークフローについて書きます。」とのこと、楽しみです。

qiita.com