我们应该使用装饰器还是上下文管理器来处理 Maya 中的撤消队列?

问题描述

我知道上下文管理器和装饰器在 Python 中是两个完全不相关的概念,但两者都可以用来实现相同的目标。有时可能会混淆哪一种是最佳实践。 在 Maya 中,如果您希望将操作列表分组为撤消队列的单个元素,则需要打开和关闭块。这是相当危险的,因为如果在块打开时引发异常,它可能会完全破坏撤消队列。

假设我想在撤销块打开时执行以下代码

def do_stuff():
    print("I do stuff...")

一种方式是写:

cmds.undoInfo(openChunk=True)
try:
    do_stuff()
finally:
    cmds.undoInfo(closeChunk=True)

这显然是一种一次性的解决方案,不太实用。我知道我可以将它自动化为装饰器:

def open_undo_chunk(func):
    def wrapper():
        cmds.undoInfo(openChunk=True)
        print("chunck opened")
        func()
        cmds.undoInfo(closeChunk=True)
        print("chunck closed")
    return wrapper
    

@open_undo_chunk
def do_stuff():
    print("I do stuff...")
    
do_stuff()

但另一种方法是使用上下文管理器。

class Open_undo_chunk():
    def __enter__(self):
        cmds.undoInfo(openChunk=True)
        print("chunck opened")
        return
    
    def __exit__(self,exec_type,exec_val,traceback):
        cmds.undoInfo(closeChunk=True)
        print("chunck closed")

with Open_undo_chunk():
    do_stuff()

在这种情况下,哪个是最佳实践,为什么?

解决方法

我认为最佳实践通常归结为最适合您的风格。我并不特别认为这两种方法之间存在明显的性能差异,但也许有人可以为我们做一些简单的基准测试。

在对您问题的非常主观的回答中,我个人更喜欢 with 语句。它表明您正在使用资源执行代码,该资源将在完成后自行处理。这通常也是您在打开文件等时执行内置上下文的方式。

另外一个好处是您无需定义在 with-语句中运行的方法。

但是,您可以通过使用 contextlib 生成上下文来节省一些精力:

import contextlib
import maya.cmds as cmds

@contextlib.contextmanager
def undoable():
    '''Insert undo chunk'''

    try:
        cmds.undoInfo(openChunk=True)
        yield
    finally:
        cmds.undoInfo(closeChunk=True)


# Simple example of invocation
with undoable():
    print("I'm doing stuff")
    cmds.polySphere(name='I_Am_Undoable')

Here's a thread with more information on the yield statement。上面我实际上是在执行 yield None,这意味着您不能真正对资源 undoable() 返回做任何事情。例如,如果您有一个文件指针或类似的东西,您可以yield <resource> 将其发送回调用上下文。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...