+-
Python-用super重新实现__setattr__
我知道之前已经讲过,也许不是构造类的最 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样式,或如this example),则没什么大不了的,因为或多或少可以保证时间成本和数据稳定性.但是,您希望避免在发布的示例代码中出现这种情况:可以很容易地假设将’translateX’设置为给定值将保持不变,实际上,有很多方法可以将其中的内容外部变量可能会引起混乱,从而使您无法在使用该类时知道不变量.如果该类旨在用于一次性使用(例如,它的语法糖用于在没有其他操作正在运行的as循环内进行许多快速重复处理),则可以避免使用它-否则,请将数据内部化到实例中.

最后一个问题:如果您有“很多课程”,那么您还必须做很多样板工作才能完成这项工作.如果要包装Maya场景数据,请阅读描述符(here’s a great 5-minute video).您可以包装典型的转换属性,例如,如下所示:

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启动搜寻的原因之一…)

点击查看更多相关文章

转载注明原文:Python-用super重新实现__setattr__ - 乐贴网