【问题标题】:Should we use a decorator or a context manager to handle undo queues in Maya?我们应该使用装饰器还是上下文管理器来处理 Maya 中的撤消队列?
【发布时间】:2021-08-10 15:41:29
【问题描述】:

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

假设我想在 undo 块打开时执行以下代码:

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()

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

【问题讨论】:

    标签: python decorator maya undo contextmanager


    【解决方案1】:

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

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

    另一个额外的好处是您无需定义在 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> 将它发送回调用上下文。

    【讨论】:

    • 感谢您的回答!它确实让我更清楚一点!我使用课堂方式进行上下文管理,因为我认为对于不熟悉上下文并且想了解这里发生了什么的人来说更清楚。
    • 我认为这是完全正确的,而且我敢打赌,很多人更喜欢通过contextlib 进行的自动魔术方法的显式声明。就我个人而言,我认为 yield 语句比“enterexit 之间可能发生的事情更具可读性,但这只是因为与其他语言的相似之处。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-30
    • 2021-08-24
    • 2010-12-19
    • 2019-05-09
    相关资源
    最近更新 更多