環境
- Windows
- Autodesk Maya 2025.3
前処理、後処理の再利用
DCCツールで前処理・後処理をパターン化して再利用できるようにするためには、with文に渡すためのコンテキストマネージャを作成すると便利です。
コンテキストマネージャの作成について
コンテキストマネージャ型
コンテキストマネージャは __enter__
メソッドと __exit__
メソッドを持つクラスを定義することで作成可能です。
class SampleContext:
def __init__(self, s):
self._s = s
def __enter__(self):
print("enter")
return self._s # as キーワードで参照できる
def __exit__(self, exc_type, exc_val, exc_tb):
print("exit")
def sample(s):
with SampleContext(s) as f:
print(f)
with文実行時には下記の順番で実行されます。
-
__enter__
メソッドの処理 - withブロック内の処理
-
__exit__
メソッドの処理
出力結果
>>> sample("sample")
enter
sample
exit
@contextlib.contextmanager
標準ライブラリにある @contextlib.contextmanager
デコレータを使用すると簡潔に定義できます。
from contextlib import contextmanager
@contextmanager
def sample_context(s):
print("enter")
try:
yield s # as キーワードで参照できる
finally:
print("exit")
def sample(s):
with sample_context(s) as f:
print(f)
yield文より前に書かれたコードが前処理として、yield文より後に書かれたコートが後処理として実行されます。
出力結果
>>> sample("sample")
enter
sample
exit
@contextlib.contextmanager
で作成するその他のメリットとしてデコレータとしての利用も可能な点が挙げられます。
from contextlib import contextmanager
@contextmanager
def sample_context():
print("enter")
try:
yield
finally:
print("exit")
@sample_context()
def sample_deco():
print("sample_deco")
出力結果
>>> sample_deco()
enter
sample_deco
exit
似たようなものとしてクラスベースのコンテキストマネージャをデコレータとして使用できるようにする基底クラス ContextDecorator
などもあります。
Maya での利用例
DCCツールでの利用例として、Mayaの例を下記に記載します。
mayapy での初期化
バッチ処理での利用例です。
from contextlib import contextmanager
import maya.standalone
@contextmanager
def mayapy_initialize():
maya.standalone.initialize()
try:
yield
finally:
maya.standalone.uninitialize()
利用例
if __name__ == "__main__":
import maya.cmds as cmds
with mayapy_initialize():
print(cmds.polyCube())
undo/redo
Qt for Python で実装したGUIのコールバック関数にデコレートする例です。
from contextlib import contextmanager
from maya import cmds
@contextmanager
def undoredo():
cmds.undoInfo(ock=True)
cmds.refresh(su=True)
try:
yield
finally:
cmds.refresh(su=False)
cmds.undoInfo(cck=True)
利用例
from PySide6 import QtWidgets
from maya import cmds
from maya.app.general.mayaMixin import MayaQWidgetBaseMixin
class Window(MayaQWidgetBaseMixin, QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
widget = QtWidgets.QWidget()
self.setCentralWidget(widget)
layout = QtWidgets.QVBoxLayout()
widget.setLayout(layout)
self._button = QtWidgets.QPushButton("Apply")
self._button.clicked.connect(self._button_clicked)
layout.addWidget(self._button)
@undoredo()
def _button_clicked(self, *args):
cmds.polySphere()
cmds.polyCube()
cmds.polyCylinder()