何时使用“属性”内置:辅助功能和生成器

时间:2010-05-04 15:21:44

标签: python properties

我最近发现了Python的property built-in,它将类方法getter和setter伪装成类的属性。我现在很想以我认为不合适的方式使用它。

如果类property具有您想要限制的允许值的属性A,那么使用_x关键字显然是正确的做法。即,它将替换可能用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 个答案:

答案 0 :(得分:14)

  • 如果您拥有普通属性并且获取和/或设置它对于类的用户有意义,则直接公开该属性。公共成员在某些语言中诅咒的一个重要原因是,如果您以后需要做一些更复杂的事情,那么您需要进行API更改;在Python中你可以定义一个属性。

  • 如果您正在使用某些内容,则应将其抽象为属性访问,请使用property。如果你想让外部状态(你的情节或网站或其他东西)意识到这种变化,或者如果你要包装一些直接使用成员的库,那么属性可能就好了。

  • 如果某些内容不是属性-y,请不要将其设为属性。制作方法没有坏处,它可能是有利的:它的作用更明显,如果需要,可以传递一些绑定方法,可以在不更改API的情况下添加关键字参数。

    很难想象我会将生成器函数用作属性的情况。拥有一个行为相似的普通属性的唯一方法需要相当多的复杂性,因此这种情况不会让人联想到属性访问。

  • 您指出可以使用property来限制对某些内部属性_x的访问。这可能是真的,但请记住

    • 如果您要执行诸如清理输入以确保安全性或重要事项,显式优于隐式。当你遇到这样的事情时,你不希望感觉代码只是正常工作,因为那时你会遇到没有的代码。

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

  • 挑剔你可能会觉得有趣:

    • property不是关键字;这是你可以重新绑定的正常名称。这有点像 有趣的是,因为property不是语法或其他东西:它是一个普通的类,你可以用纯Python实现自己。它使用相同的机制使方法在Python中起作用 - descriptors

    • 您描述了property作为“伪装类方法getter和setter”的内容,但事实并非如此。 property所采取的只是正常的功能,根本不需要在你的班级中定义; property将为您传递self。在Python查找时,函数实际上不会成为方法,而Python会在运行时创建方法对象。在类定义期间,它们只是函数。当你有一个普通的方法时,它被称为“实例方法”;在Python中,“类方法”指的是another special thing类似的属性,它们会改变查找属性时发生的情况。

答案 1 :(得分:2)

使用属性有一个明显的限制:它不接受任何参数,它永远不会。

因此,您必须确保您正在转换为属性的函数永远不会被重构为具有例如额外默认参数的函数。