编辑:我之前的回答试图制作一个通用的 AutoProperties 元类,我希望它可以通用。正如@martineau 的回答所示,专门针对该Vector
课程的解决方案可以使事情变得更简单。
这是沿着这些思路的另一个想法(专门的简单性优于一般的复杂性)。它使用类装饰器(我认为它比元类更容易理解)和@martineau 使用默认值简化 getter 和 setter 的想法:
def AutoProperties(*props):
def _AutoProperties(cls):
for attr in props:
def getter(self,_attr='_'+attr):
return getattr(self, _attr)
def setter(self, value, _attr='_'+attr):
setattr(self, _attr, float(value))
setattr(cls,attr,property(getter,setter))
return cls
return _AutoProperties
@AutoProperties('x','y','z')
class Vector(object):
'''Creates a Maya vector/triple, having x, y and z coordinates as float values'''
def __init__(self, x=0, y=0, z=0):
self._x, self._y, self._z = map(float,(x, y, z))
原始答案:
这是一种在定义许多相似属性时避免重复样板代码的方法。
我试图使解决方案合理通用,因此它可能对除此特定情况之外的其他情况下的人们有用。
要使用它,您需要做两件事:
- 放
__metaclass__=AutoProperties(('x','y','z'))
在你的类定义的开头。您可以根据需要列出(作为字符串)任意数量的属性(例如x
, y
, z
)。AutoProperties
会将它们变成属性。
- 你的类,例如
Vector
,需要定义 staticmethods_auto_setter
和_auto_getter
. 它们接受一个参数,即作为字符串的属性名称,并分别为该属性返回 setter 或 getter 函数。
使用元类自动设置属性的想法来自 Guido Rossum 关于属性和元类的文章。他在那里定义了一个autoprop
类似于我在下面使用的元类。主要区别在于AutoProperties
期望用户定义 getter 和 setter工厂,而不是手动定义 getter 和 setter。
def AutoProperties(props):
class _AutoProperties(type):
# Inspired by autoprop (http://www.python.org/download/releases/2.2.3/descrintro/)
def __init__(cls, name, bases, cdict):
super(_AutoProperties, cls).__init__(name, bases, cdict)
for attr in props:
fget=cls._auto_getter(attr)
fset=cls._auto_setter(attr)
setattr(cls,attr,property(fget,fset))
return _AutoProperties
class Vector(object):
'''Creates a Maya vector/triple, having x, y and z coordinates as float values'''
__metaclass__=AutoProperties(('x','y','z'))
def __init__(self, x=0, y=0, z=0):
# I assume you want the initial values to be converted to floats too.
self._x, self._y, self._z = map(float,(x, y, z))
@staticmethod
def _auto_setter(attr):
def set_float(self, value):
setattr(self, '_'+attr, float(value))
return set_float
@staticmethod
def _auto_getter(attr):
def get_float(self):
return getattr(self, '_'+attr)
return get_float
if __name__=='__main__':
v=Vector(1,2,3)
print(v.x)
# 1.0
v.x=4
print(v.x)
# 4.0