何时使用“property”内置:辅助函数和生成器
我最近发现了Python的property
内置功能,它可以把类的方法(获取器和设置器)伪装成类的属性。现在我有点想用它,但我觉得这样做可能不太合适。
如果类A
有一个属性_x
,而你想限制它的可取值,那么使用property
这个关键词显然是正确的选择;也就是说,它可以替代在C++中可能写的getX()
和setX()
这类方法。
但是,除了这种情况,还有哪些地方适合把一个函数变成属性呢?比如,如果你有
class Vertex(object):
def __init__(self):
self.x = 0.0
self.y = 1.0
class Polygon(object):
def __init__(self, list_of_vertices):
self.vertices = list_of_vertices
def get_vertex_positions(self):
return zip( *( (v.x,v.y) for v in self.vertices ) )
那么加上
vertex_positions = property( get_vertex_positions )
这样做合适吗?
有没有可能让一个生成器看起来像一个属性?想象一下,如果我们的代码发生了变化,导致我们不再以同样的方式存储Polygon.vertices
,那这样加到Polygon
里可以吗?
@property
def vertices(self):
for v in self._new_v_thing:
yield v.calculate_equivalent_vertex()
2 个回答
使用属性有一个明显的限制:它不接受任何参数,而且将来也不会接受。
所以你必须确保你要转换成属性的那个函数,永远不会被改成一个带有额外默认参数的函数。
当你有一个普通的属性,并且获取或设置这个属性对使用这个类的人来说是有意义的,就直接暴露这个属性。某些语言中,公开成员被认为是不好的做法,主要是因为如果以后需要做更复杂的事情,就得改动API;而在Python中,你只需要定义一个属性就可以了。
如果你使用的东西应该抽象成属性访问,就用属性。如果你想让外部状态(比如你的图表、网站或其他东西)知道变化,或者你在封装某个直接使用成员的库,使用属性可能是个好主意。
如果某个东西不适合做成属性,就不要把它做成属性。创建一个方法没有坏处,反而可能更有利:它的功能更明显,如果需要,你可以传递一些绑定的方法,还可以在不改动API的情况下添加关键字参数。
很难想象有哪种情况会把生成器函数用作属性。要让一个普通属性表现得像属性那样,可能需要很多复杂的操作,所以这种情况和属性访问并不太像。
你提到可以使用
property
来限制对某个内部属性_x
的访问。这是对的,但要记住:如果你要做一些像清理输入以确保安全性或其他重要事情,明确比隐含更好。在这种情况下,你不想让代码看起来就能正常工作,因为那样你会遇到一些不正常的代码。
有时候人们使用
property
来实现只读属性。通常,直接使用普通属性更好,意识到你无法阻止用户做一些愚蠢和不被支持的事情。
一些你可能会觉得有趣的小细节:
property
不是一个关键字;它是一个普通的名称,你可以重新绑定。这个有点有趣,因为property
不是语法相关的东西:它是一个你可以在纯Python中自己实现的普通类。它使用了让方法在Python中工作的相同机制——描述符。你描述
property
的功能为“伪装成类方法的获取器和设置器”,这并不完全正确。property
接受的东西只是普通函数,实际上不需要在你的类中定义;property
会为你传递self
。函数实际上在你查找它们时才会变成方法,当Python动态创建方法对象时。在类定义期间,它们只是函数。当你有一个普通方法时,它被称为“实例方法”;在Python中,“类方法”指的是另一种特殊的东西,类似于属性,它改变了查找属性时发生的事情。