2017年03月15日
modo10.2v1のスクリプトについて調べてみた その66
引き続き「TD SDK」について調べてみたい。
今回も「modo.util.makeQuickCommand()」ファンクション内の「CmdMyCustomCommand」クラスの「basic_Execute()」メソッドの続きだ。
def basic_Execute(self, msg, flags): kwargs = {} if self._argumentList is not None: if not all([self.dyna_IsSet(i) for i in range(self._numArgs)]): raise ValueError('Missing argument') for i, pair in enumerate(self._argumentList.iteritems()): name, defaultValue = pair if isinstance(defaultValue, basestring): value = self.dyna_String(i, defaultValue) kwargs[name] = value elif isinstance(defaultValue, (int, long)): value = self.dyna_Int(i, defaultValue) kwargs[name] = value func(**kwargs)
「_argumentList」は「collections.OrderedDict」オブジェクトで、「iteritems()」メソッドによってジェネレータオブジェクトが取得出来て、そのオブジェクトに対して「next()」メソッドを実行するたびにコレクション内の要素が1つずつ取り出される。
このジェネレータを使って「enumerate」オブジェクトを作って、そのオブジェクトに対して「next()」メソッドを実行すると、「enumerate」オブジェクト内部の「_argumentList」のジェネレータに対して「next()」が実行されて、「_argumentList」から要素が1つ取り出され、通し番号とセットにした値が順次出力される。
これをfor文で使うと、内部で「next()」メソッドが呼び出されて生成された通し番号と「_argmentList」に入ってる要素が次々呼び出されて、通し番号は変数「i」に、要素は「pair」にセットされ、「_argmentList」の要素が尽きるまで繰り返される。
for i, pair in enumerate(self._argumentList.iteritems()):
「_argmentList」に格納されてる要素は「makeQuickCommand()」ファンクションで与えた(パラメータ名,デフォルト値)のペアになっている。
def makeQuickCommand(name, func, arguments=None, userName='myCmdName', description='This command ...', toolTip='Tooltip'): : for arg in arguments: argName, defaultValue = arg self._argumentList[argName] = defaultValue
それを分解して2つの変数に振り分けて代入して、
name, defaultValue = pair
デフォルト値のタイプを判定して、文字列なら「dyna_String()」でmodoから渡された値を取得し、整数なら「dyna_Int()」でそれをする。そして辞書オブジェクトに「名前」をキーにして値をセットする。
if isinstance(defaultValue, basestring): value = self.dyna_String(i, defaultValue) kwargs[name] = value elif isinstance(defaultValue, (int, long)): value = self.dyna_Int(i, defaultValue) kwargs[name] = value
「CmdMyCustomCommand」クラスの「__init__()」メソッドの中の「dyna_Add()」でデフォルトの値を整数にしても文字列にしても値のタイプは「sTYPE_STRING」にするようになっていたので、ここらへんで支障が出るかなと思ったんだけど、
if isinstance(defaultValue, basestring): self.dyna_Add(argName, lx.symbol.sTYPE_STRING) elif isinstance(defaultValue, (int, long)): self.dyna_Add(argName, lx.symbol.sTYPE_STRING)
文字列のデータが入っていながら整数値を取得するために呼び出される「syna_Int()」は下のコードになっていて、
def dyna_Int(self,index,value=0): if not self.dyna_IsSet(index): return value return self.attr_GetInt(index)
この中で呼び出される「attr_GetInt()」は下の通り。
def attr_GetInt(self,index):
return self.attr_Value(index,0).GetInt()
この中で出てくる「attr_Value()」は下の通りで、パラメータ登録で出て来たお馴染みの「(パラメータ名,デフォルト値,None)」のタプルの3つ目の値がNoneではなくて「Value」オブジェクトになってるものを「_attrs」から取得して、その3番目の「Value」オブジェクトを返すものだ。そして上の「attr_GetInt()」でこの「Value」オブジェクトに対して「GetInt()」メソッドを実行して「Value」オブジェクトに格納されている整数値を得ている。
def attr_Value(self,index,writeOK): """Get value object for an attribute. If writeOK is true the value will be created if it doesn't exist. """ t = self._attrs[index] v = t[2] if v == None: if writeOK: v = self.val_svc.CreateValue(t[1]) self._attrs[index] = (t[0], t[1], v) else: lx.throw(lx.result.NOTFOUND) return v
どうやら文字列データでも整数に変換できる場合はこの「GetInt()」で整数に変換されるようで、下のようにプログラムを書いて実行してみたら、
import lx val = lx.service.Value() v=val.CreateValue(lx.symbol.sTYPE_STRING) v.SetString("10") print type(v.GetInt()),v.GetInt()
このようになった。よってパラメータのタイプが整数でも文字列でも結果的に問題なく処理される事になったようだ(いいのか?)。
# Result:
<type 'long'> 10
ちなみに整数に変換出来ない文字列の場合は0に変換されるようだ。
続きはまた次回。