我应该如何使用 python 中的闭包创建属性?
How should I create properties using a closure in python?
我正在使用 PyMel 为 Maya 编写一些代码,我正在尝试在我的装备中创建一些属性 class 以包装一些 PyMel 代码。所有属性的代码都非常相似,所以我认为这是使用闭包的好地方。
import pymel.core as pm
import riggermortis.utils as utils
class RigModule(object):
def __init__:
# blah blah irrelevant code here
pass
def createRootProperty(attrName):
def getter(self):
return pm.getAttr(self.root+'.'+attrName)
def setter(self, nodeToLink):
if self.root.hasAttr(attrName):
pm.setAttr(self.root+'.'+attrName, nodeToLink)
else:
utils.linkNodes(self.root, nodeToLink, attrName)
return property(fget=getter,fset=setter)
hookConstraint = createRootProperty('hookConstraint')
unhookTarget = createRootProperty('unhookTarget')
moduleGrp = createRootProperty('moduleGrp')
hookGrp = createRootProperty('hookGrp')
在功能上它有效,但是 Eclipse/PyDev 告诉我我的 'createRootProperty' 函数需要 'self' 作为它的第一个参数,所以我想知道我在做什么是不是不正确。
对于你正在做的事情,除了清洁之外,并不真正需要关闭。 linter 认为它是一个格式不正确的成员函数,即使它正在做你想要的。
您只需移动 class 作用域的函数,linter 就会停止抱怨——您可以用下划线重命名该函数,这样就不会有人意外地认为它是一个工具而不是一个基础设施。
如果您希望经常这样做,您可以将其自动化到元class 中,该元class 从class 字段中读取名称列表并根据需要创建属性。该策略有一个更详细的示例 here,但本质上,元 class 将在定义 class 时获得 class 字典的副本,并且它有机会在编译之前弄乱定义。您可以在该步骤轻松创建 属性:
def createRootProperty(name):
# this is a dummy, but as long as
# the return from this function
# is a property descriptor you're good
@property
def me(self):
return name, self.__class__
return me
class PropertyMeta(type):
# this gets called when a class using this meta is
# first compiled. It gives you a chance to intervene
# in the class creation project
def __new__(cls, name, bases, properties):
# if the class has a 'PROPS' member, it's a list
# of properties to add
roots = properties.get('PROPS', [])
for r in roots:
properties[r] = createRootProperty(r)
print ("# added property '{}' to {}".format(r, name))
return type.__new__( cls, name, bases, properties)
class RigModule(object):
__metaclass__ = PropertyMeta
PROPS = ['arm', 'head', 'leg']
def __init__(self):
pass
test = RigModule()
print test.arm
class Submodule(RigModule):
# metaclass added properties are inheritable
pass
test2 = Submodule()
print test2.leg
class NewProperties(RigModule):
# they can also be augmented in derived classes
PROPS = ['nose', 'mouth']
print NewProperties().nose
print NewProperties().arm
# added property 'arm' to RigModule
# added property 'head' to RigModule
# added property 'leg' to RigModule
# ('arm', <class '__main__.RigModule'>)
# ('leg', <class '__main__.Submodule'>)
# added property 'nose' to NewProperties
# added property 'mouth' to NewProperties
# ('nose', <class '__main__.NewProperties'>)
# ('arm', <class '__main__.NewProperties'>)
Metaclasses 因增加复杂性而声名狼藉——有时是当之无愧的。当更简单的方法可行时,不要使用它们。但是对于在这种情况下减少样板文件,它们是一个很好的工具。
我正在使用 PyMel 为 Maya 编写一些代码,我正在尝试在我的装备中创建一些属性 class 以包装一些 PyMel 代码。所有属性的代码都非常相似,所以我认为这是使用闭包的好地方。
import pymel.core as pm
import riggermortis.utils as utils
class RigModule(object):
def __init__:
# blah blah irrelevant code here
pass
def createRootProperty(attrName):
def getter(self):
return pm.getAttr(self.root+'.'+attrName)
def setter(self, nodeToLink):
if self.root.hasAttr(attrName):
pm.setAttr(self.root+'.'+attrName, nodeToLink)
else:
utils.linkNodes(self.root, nodeToLink, attrName)
return property(fget=getter,fset=setter)
hookConstraint = createRootProperty('hookConstraint')
unhookTarget = createRootProperty('unhookTarget')
moduleGrp = createRootProperty('moduleGrp')
hookGrp = createRootProperty('hookGrp')
在功能上它有效,但是 Eclipse/PyDev 告诉我我的 'createRootProperty' 函数需要 'self' 作为它的第一个参数,所以我想知道我在做什么是不是不正确。
对于你正在做的事情,除了清洁之外,并不真正需要关闭。 linter 认为它是一个格式不正确的成员函数,即使它正在做你想要的。
您只需移动 class 作用域的函数,linter 就会停止抱怨——您可以用下划线重命名该函数,这样就不会有人意外地认为它是一个工具而不是一个基础设施。
如果您希望经常这样做,您可以将其自动化到元class 中,该元class 从class 字段中读取名称列表并根据需要创建属性。该策略有一个更详细的示例 here,但本质上,元 class 将在定义 class 时获得 class 字典的副本,并且它有机会在编译之前弄乱定义。您可以在该步骤轻松创建 属性:
def createRootProperty(name):
# this is a dummy, but as long as
# the return from this function
# is a property descriptor you're good
@property
def me(self):
return name, self.__class__
return me
class PropertyMeta(type):
# this gets called when a class using this meta is
# first compiled. It gives you a chance to intervene
# in the class creation project
def __new__(cls, name, bases, properties):
# if the class has a 'PROPS' member, it's a list
# of properties to add
roots = properties.get('PROPS', [])
for r in roots:
properties[r] = createRootProperty(r)
print ("# added property '{}' to {}".format(r, name))
return type.__new__( cls, name, bases, properties)
class RigModule(object):
__metaclass__ = PropertyMeta
PROPS = ['arm', 'head', 'leg']
def __init__(self):
pass
test = RigModule()
print test.arm
class Submodule(RigModule):
# metaclass added properties are inheritable
pass
test2 = Submodule()
print test2.leg
class NewProperties(RigModule):
# they can also be augmented in derived classes
PROPS = ['nose', 'mouth']
print NewProperties().nose
print NewProperties().arm
# added property 'arm' to RigModule
# added property 'head' to RigModule
# added property 'leg' to RigModule
# ('arm', <class '__main__.RigModule'>)
# ('leg', <class '__main__.Submodule'>)
# added property 'nose' to NewProperties
# added property 'mouth' to NewProperties
# ('nose', <class '__main__.NewProperties'>)
# ('arm', <class '__main__.NewProperties'>)
Metaclasses 因增加复杂性而声名狼藉——有时是当之无愧的。当更简单的方法可行时,不要使用它们。但是对于在这种情况下减少样板文件,它们是一个很好的工具。