何时使用“property”内置:辅助函数和生成器

11 投票
2 回答
6349 浏览
提问于 2025-04-15 22:20

我最近发现了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 个回答

3

使用属性有一个明显的限制:它不接受任何参数,而且将来也不会接受。

所以你必须确保你要转换成属性的那个函数,永远不会被改成一个带有额外默认参数的函数。

16
  • 当你有一个普通的属性,并且获取或设置这个属性对使用这个类的人来说是有意义的,就直接暴露这个属性。某些语言中,公开成员被认为是不好的做法,主要是因为如果以后需要做更复杂的事情,就得改动API;而在Python中,你只需要定义一个属性就可以了。

  • 如果你使用的东西应该抽象成属性访问,就用属性。如果你想让外部状态(比如你的图表、网站或其他东西)知道变化,或者你在封装某个直接使用成员的库,使用属性可能是个好主意。

  • 如果某个东西不适合做成属性,就不要把它做成属性。创建一个方法没有坏处,反而可能更有利:它的功能更明显,如果需要,你可以传递一些绑定的方法,还可以在不改动API的情况下添加关键字参数。

    很难想象有哪种情况会把生成器函数用作属性。要让一个普通属性表现得像属性那样,可能需要很多复杂的操作,所以这种情况和属性访问并不太像。

  • 你提到可以使用 property 来限制对某个内部属性 _x 的访问。这是对的,但要记住:

    • 如果你要做一些像清理输入以确保安全性或其他重要事情,明确比隐含更好。在这种情况下,你不想让代码看起来就能正常工作,因为那样你会遇到一些不正常的代码。

    • 有时候人们使用 property 来实现只读属性。通常,直接使用普通属性更好,意识到你无法阻止用户做一些愚蠢和不被支持的事情。

  • 一些你可能会觉得有趣的小细节:

    • property 不是一个关键字;它是一个普通的名称,你可以重新绑定。这个有点有趣,因为 property 不是语法相关的东西:它是一个你可以在纯Python中自己实现的普通类。它使用了让方法在Python中工作的相同机制——描述符

    • 你描述 property 的功能为“伪装成类方法的获取器和设置器”,这并不完全正确。property 接受的东西只是普通函数,实际上不需要在你的类中定义;property 会为你传递 self。函数实际上在你查找它们时才会变成方法,当Python动态创建方法对象时。在类定义期间,它们只是函数。当你有一个普通方法时,它被称为“实例方法”;在Python中,“类方法”指的是另一种特殊的东西,类似于属性,它改变了查找属性时发生的事情。

撰写回答