[maya] python で mel 変数の値を "より安全に" 取得する方法

```
※記事に関しましてご注意下さい
普段使用する手法を「よりシンプルで柔軟な方法がないか」調査した内容になります。
あくまでも個人調査のメモです。間違い・勘違いが含まれている可能性もありますので予めご了承ください。
```
※ 結論だけ見たい方は [最後尾](#トラブルを起こさない記述) へどうぞ。 

## 調査のきっかけ
maya 内の python で mel 変数の値を取得する場合、一時的な代入を使い

```python
from maya import mel
progress_bar = mel.eval('$tmp = $gMainProgressBar')
```
のように取得する方法がよく使われると思います。
ここで個人的にずっとモヤモヤしている箇所がありました。

```
1. $tmp という変数はどこに作成されるのか (global 変数か local 変数か)
2. 1 が global 変数の場合、既存変数との型違いでエラーは起きないのか
```
という疑問です。
この確認と、よりトラブルを起こさない記述について調べることにしました。

## 調べた結果
```
1. $tmp は global 変数として作成される（そのまま後に残される）
2. 別の型の $tmp 変数が既にあった場合にはエラーが起こる
```
そのままでした。
つまり、頭に書いた記述には使用条件があり、

```
・変数 $tmp が初めて作成される場合 (mel が型を振ってくれる)
・変数 $tmp が同じ型で宣言されている場合
```
のどちらかである必要があります。

この問題を起こさない記述は  [最後尾](#トラブルを起こさない記述)  にメモしています。

## トラブルが起こる場面
この穴をついてエラーが起きる・エラーを起こす方法は簡単です。
思いつく場面として以下があると思います。

### 型違いの同名変数を mel で "先に" 準備した場合

```mel
int $tmp = 1;
```
を mel で実行した後、python 文を実行すると

```python
from maya import mel
progress_bar = mel.eval('$tmp = $gMainProgressBar')

progress_bar
# Result: 0L # 
```

この場面では文字を変数に変換しようとして 0 という数字になります

上は `int $tmp;` でしたが、`int $tmp[];` のように配列だった場合など、
型変換すら行われずにエラーになる可能性大です。

### 型違いの同名変数を mel で "後から" 使用した場合
※こちらは python 側のエラーにはなりませんがのちの mel でエラーが起きます

```python
from maya import mel
progress_bar = mel.eval('$tmp = $gMainProgressBar')

progress_bar
# Result: MayaWindow|toolBar3|MainHelpLineLayout|helpLineFrame|formLayout16|mainProgressBar # 
```
を python で実行した後、mel 文を実行するとエラーがでます。

```mel
int $tmp = 1;
// Error: int $tmp; // 
// Error: Line 1.10: Invalid redeclaration of variable "$tmp" as a different type. // 
```

基本的に mel での global 変数使用は最小限にするのが暗黙のルールであるためおそらく頻発はしないとは思います。が、そうはいいつつも起きそうな場面としては scriptEditor でのテスト時、数行のスクリプトを Shelf などに登録している場合などがあると思います。

## 実際にトラブルが発生した例
[2022/12 追記]
身近でトラブルが起こる場面に遭遇したため例を追記しました。
公式ツール、有名ツールだとしても意識していないものが多いようです。
### MayaScanner + mgear を共に使用した場合
[2022/12 追記]
MayaScanner は Maya 起動時に発動し、File Open などでスクリプトが動作しますが、そこで以下のコードが実行されます。
```python:MayaScannerCleaner.py
232:        if (mel.eval('whatIs "$autoUpdateAttrEd_aoto_int"') != "Unknown"):
233:            a = int(mel.eval('$temp=$autoUpdateAttrEd_aoto_int'))
```
ここで `$temp` が global 変数として自動定義されることになりますが、この場合 `global int $temp` 相当だと意識しておく必要があります。

一方 Maya 起動後に File Open し、mgear を使用してSynoptic > Space Transfer などのツールを使用すると (一時的に再描画を止めるため) 以下のコードが実行されます。
```python:mgear4.0.9/release/scripts/mgear/core/utils.py
185:        gMainPane = mel.eval('global string $gMainPane; $temp = $gMainPane;')
```
ここで mgear としては `$temp` の想定は `global string $temp` ですが、事前に MayaScanner によって `global int $temp` で先に作られてしまっているため、エラーが発生します。

エラーメッセージ的にはこんな感じです。
```
# RuntimeError: paneLayout: Object '0' not found.
```
まさに上で書いたことがそのまま発生し、エラーが起こっています。

どう修正すべきかについては、
MayaScanner はこう ↓ するべきですし、
```python:MayaScannerCleaner.py
        if (mel.eval('whatIs "$autoUpdateAttrEd_aoto_int"') != "Unknown"):
            a = int(mel.eval('$autoUpdateAttrEd_aoto_int = $autoUpdateAttrEd_aoto_int'))
```
mgear はこう ↓ 書くべきだと思います。
```python:mgear4.0.9/release/scripts/mgear/core/utils.py
        gMainPane = mel.eval('$gMainPane = $gMainPane')
```

`$temp` は自分だけのものではない、と改めて感じる例です。

## トラブルを起こさない記述
いろいろ試しつつ情報収集していたところ、
studiolibrary 内になるほどの記述がありました。
https://github.com/krathjen/studiolibrary/blob/master/install.py#L68

それは `自分自身に代入する方法` です。

```python
from maya import mel
progress_bar = mel.eval('$gMainProgressBar = $gMainProgressBar')
```
 `先に変数の型を知る必要がなく、代入が自分自身なので型は当然同じ、そして代入で値を変化させず、かつ無駄な global 変数を作成しない` 、非常にスマートな方法です。

一方的に勉強になりました。。。感謝。

### この手法のもう一つの利点

頻繁に使用・問合せする以下はその多くが string ですが、

```mel
$gMainWindow
$gMainProgressBar
$gChannelBoxName
$gMainWindowMenu
$gMainPane
```
例えば以下は int の配列です。

```mel
$gCustomSelPriority
```
ですが、この場合もその型を事前に知る必要がなく

```python
from maya import mel
gCustomSelPriority = mel.eval('$gCustomSelPriority = $gCustomSelPriority')

gCustomSelPriority
# Result: [10, 10, 2, 9, 2, 2, 2, 2, 2, 2, 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 8, 10, 10, 9, 9, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 11, 11] # 
```

のように取得することができます。