下記のようなexcel-macroでxlwings経由でpython関数を実行しています。しかしどうあがいても、揮発性関数扱い（Open、Any-
cell変化時に再計算）されています。  
これまで確認した内容としては、

1) vba側でいきなり0などの値を返す。→これのみ非揮発性に変化

```

    MLMprdct = 0 'Py.CallUDF(Tar_pyfile, "MLMprdct", Array(Model, Labels, Xn,　OutRs, OutCs, enslst), ThisWorkbook, Application.Caller)
    
```

2) python側で、値をすぐ返す。 → 揮発性のまま

```

    return(Xn[:,:2])#(MLMprd_calc(Mdlfile, Labels, OutRs, OutCs, lst, Xn))
    
```

3) XnがRange渡し（python側でvalue化）をValue渡しにしてpython側では一切excelを触らない → 揮発性のまま

**vba:**

```

    MLMprdct = Py.CallUDF(Tar_pyfile, "MLMprdct", Array(Model, Labels, Xn.value,　OutRs, OutCs, enslst), ThisWorkbook, Application.Caller)
    
```

**python**

```

    ♯♯@xw.arg('rXn', xw.Range)
    ♯♯def MLMprdct(Mdlfile, Labels, rXn='', OutRs=1, OutCs=2, lst=''): 
    def MLMprdct(Mdlfile, Labels, Xn, OutRs=1, OutCs=2, lst=''): 
        Xn = np.array(Xn) #rXn.resize(OutRs).expand('right').options(np.array).value
    
```

「私のxlwings‐UDF関数は非揮発性ですよ」という方いらっしゃいますか？ いたら教えていただけないでしょうか？

**vba:**

```

    Public Function MLMprdct(Model As String, Labels As String, Xn As Range, Optional OutRs As Long = 1, Optional OutCs As Integer = 2, Optional enslst As String = "") 'Private
    Application.Volatile (False) 'don't work
    sta = Time()
    If TypeOf Application.Caller Is Range Then On Error GoTo failed
    MLMprdct = Py.CallUDF(Tar_pyfile, "MLMprdct", Array(Model, Labels, Xn,　OutRs, OutCs, enslst), ThisWorkbook, Application.Caller)
    Debug.Print "MLM:", Application.Caller.Address(, , , True), Time() - sta
    Exit Function
     failed:
    MLMprdct = Err.Description
     End Function
    
```

**python:(最上層のみ）**

```

    @xw.func
    @xw.arg('rXn', xw.Range)
    def MLMprdct(Mdlfile, Labels, rXn='', OutRs=1, OutCs=2, lst=''): 
        Xn = rXn.resize(OutRs).expand('right').options(np.array).value
        return(MLMprd_calc(Mdlfile, Labels, OutRs, OutCs, lst, Xn))
    
```
CC BY-SA 4.0
2019-01-30T14:57:40.717
52432
2019-07-07T13:02:35.343
2019-01-30T15:58:29.973
3060
31989
question
python vba
xlwingsのUDFは、エクセルでは必ず揮発性関数扱いになるのでしょうか？
自己回答です。単純でした。pythonは関係ないです。最終的に、以下のようなvba
Functionで、他セルを参照した場合、参照先（の参照先...）に、Offset等揮発性関数があると、どんなCellを更新しようが再計算が伝達して結局再計算します。すなわち、Book中のとあるSheetを更新しただけで、OffsetがはいっているSheetはすべて再計算されることになります。やっと納得できました。  
対策は、１）Offsetを使わない。か、２）Worksheets("Sheet1").EnableCalculation = False
で更新時の計算範囲を極力少なくするしかないようです。

=testudf(Z26)

Function testudf(ind)  
testudf = ind + 1  
Debug.Print "testudf", Application.Caller.Address, Now()  
End Function
CC BY-SA 4.0
2019-02-03T09:29:17.483
52511
2019-02-03T09:29:17.483
31989
52432
answer