Python - 用 super 重新实现 __setattr__

2023-12-05

我知道这个以前已经介绍过,也许不是构建类的最Pythonic方式,但我有很多不同的maya节点类,其中有很多用于检索/设置节点数据的@properties,我想看看如果按程序构建属性可以减少开销/维护。

我需要重新实现 __setattr__ 以便维持标准行为,但对于某些特殊属性,该值被获取/设置为外部对象。

我见过在堆栈溢出时重新实现 __setattr__ 的示例,但我似乎遗漏了一些东西。

我认为我没有维护默认功能setAttr

这是一个例子:

externalData = {'translateX':1.0,'translateY':1.0,'translateZ':1.0}
attrKeys = ['translateX','translateY','translateZ']


class Transform(object):

    def __getattribute__(self, name):
        print 'Getting --->', name
        if name in attrKeys:
            return externalData[name]
        else:
            raise AttributeError("No attribute named [%s]" %name)

    def __setattr__(self, name, value):
        print 'Setting --->', name
        super(Transform, self).__setattr__(name, value)
        if name in attrKeys:
            externalData[name] = value


myInstance = Transform()
myInstance.translateX
# Result: 1.0 # 
myInstance.translateX = 9999
myInstance.translateX
# Result: 9999 # 
myInstance.name = 'myName'
myInstance.name
# AttributeError: No attribute named [name] #

!


这对我有用:

class Transform(object):

    def __getattribute__(self, name):
       if name in attrKeys:
           return externalData[name]
       return super(Transform, self).__getattribute__(name)

    def __setattr__(self, name, value):
        if name in attrKeys:
            externalData[name] = value
        else:
            super(Transform, self).__setattr__(name, value)

但是,我不确定这是一条好路线。

如果外部操作非常耗时(例如,您使用它来伪装对数据库或配置文件的访问),您可能会给代码用户带来关于成本的错误印象。在这种情况下,您应该使用一种方法,以便用户了解他们正在发起操作,而不仅仅是查看数据。

OTOH,如果访问速度很快,请注意类的封装不要被破坏。如果您这样做是为了获取 Maya 场景数据(pymel 样式,或如这个例子)这没什么大不了的,因为时间成本和数据的稳定性或多或少得到了保证。但是,您希望避免您发布的示例代码中的情况:很容易假设将“translateX”设置为给定值后它会保持不变,实际上有很多方法可以将外部变量可能会被弄乱,从而阻止您在使用该类时了解您的不变量。如果该类旨在一次性使用(例如,它的语法糖用于在循环内进行大量快速重复处理,而没有其他操作正在运行),那么您可以摆脱它 - 但如果不是,请将数据内部化到您的实例中。

最后一个问题:如果你有“很多类”,你还必须做很多样板文件才能完成这项工作。如果您尝试包装 Maya 场景数据,请阅读描述符 (这是一个精彩的 5 分钟视频)。您可以包装典型的转换属性,例如,如下所示:

import maya.cmds as cmds

class MayaProperty(object):
    '''
    in a real implmentation you'd want to support different value types, 
    etc by storing flags appropriate to different commands.... 
    '''
    def __init__(self, cmd, flag):
        self.Command = cmd
        self.Flag = flag

    def __get__(self, obj, objtype):
            return self.Command(obj, **{'q':True, self.Flag:True} )

    def __set__(self, obj, value):
        self.Command(obj, **{ self.Flag:value})

class XformWrapper(object):

    def __init__(self, obj):
        self.Object = obj

    def __repr__(self):
        return self.Object # so that the command will work on the string name of the object

    translation = MayaProperty(cmds.xform, 'translation')
    rotation = MayaProperty(cmds.xform, 'rotation')
    scale = MayaProperty(cmds.xform, 'scale')

在实际代码中,您需要错误处理和更清晰的配置,但您已经看到了这个想法。

上面链接的示例讨论了当您有大量属性描述符需要配置时使用元类来填充类,如果您不想担心所有样板文件,那么这是一个很好的方法(尽管它确实有一个小的启动时间损失) - 我认为这是臭名昭著的 Pymel 启动爬行的原因之一......)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python - 用 super 重新实现 __setattr__ 的相关文章

随机推荐