关于如何在python中使用属性function的真实世界的例子?

我感兴趣的是如何在Python中使用@property 。 我读过python文档和那里的例子,在我看来,只是一个玩具代码:

 class C(object): def __init__(self): self._x = None @property def x(self): """I'm the 'x' property.""" return self._x @x.setter def x(self, value): self._x = value @x.deleter def x(self): del self._x 

我不知道从包装属性装饰器的_x可以得到什么好处。 为什么不只是实现为:

 class C(object): def __init__(self): self.x = None 

我认为,在某些情况下,属性function可能会有用。 但当? 有人能给我一些真实的例子吗?

谢谢。

其他的例子是集合属性的validation/过滤(迫使它们处于边界或可接受的范围内)以及对复杂或快速变化的术语的惰性评估。

隐藏在属性后面的复杂计算:

 class PDB_Calculator(object): ... @property def protein_folding_angle(self): # number crunching, remote server calls, etc # all results in an angle set in 'some_angle' # It could also reference a cache, remote or otherwise, # that holds the latest value for this angle return some_angle >>> f = PDB_Calculator() >>> angle = f.protein_folding_angle >>> angle 44.33276 

validation:

 class Pedometer(object) ... @property def stride_length(self): return self._stride_length @stride_length.setter def stride_length(self, value): if value > 10: raise ValueError("This pedometer is based on the human stride - a stride length above 10m is not supported") else: self._stride_length = value 

一个简单的用例就是设置一个只读实例属性,就像你知道在python中用一个下划线_x引用一个variables名通常意味着它是私有的 (内部使用),但是有时我们希望能够读取实例属性而不是写它,所以我们可以使用这个property

 >>> class C(object): def __init__(self, x): self._x = x @property def x(self): return self._x >>> c = C(1) >>> cx 1 >>> cx = 2 AttributeError Traceback (most recent call last) AttributeError: can't set attribute 

看看这篇文章是非常实用的。 简而言之,它解释了在Python中,通常可以使用明确的getter / setter方法,因为如果在某个阶段需要它们,可以使用property来实现无缝实现。

有一件事我用它caching缓慢查找,但不变,存储在数据库中的值。 这可以概括为任何需要计算或其他长时间操作(例如数据库检查,networking通信)的情况。

 class Model(object): def get_a(self): if not hasattr(self, "_a"): self._a = self.db.lookup("a") return self._a a = property(get_a) 

这是在一个Web应用程序中,任何给定的页面视图可能只需要一个这样的特定属性,但底层对象本身可能有几个这样的属性 – 初始化他们所有的build设将是浪费,属性让我灵活属性是懒惰的,哪些不是。

属性只是一个领域的抽象,它使您可以更好地控制特定领域的操作方式和中间件计算。 很less有用户想到的是validation和事先初始化和访问限制

 @property def x(self): """I'm the 'x' property.""" if self._x is None: self._x = Foo() return self._x 

你的问题的简短答案是,在你的例子中,没有任何好处。 您应该使用不涉及属性的表单。

属性存在的原因是,如果你的代码将来会改变,你突然需要做更多的事情:caching值,保护访问权限,查询一些外部资源…无论如何,你可以很容易地修改你的类来添加getters和设置数据而不改变接口,所以你不必在你的代码中find访问数据的地方,也可以改变它。

是的,对于最初的示例,该属性将与仅具有实例variables“x”的工作完全相同。

这是关于python属性的最好的东西。 从外部看,它们的工作方式与实例variables完全相同! 它允许你使用类之外的实例variables。

这意味着你的第一个例子可以实际使用一个实例variables。 如果事情发生了变化,然后你决定改变你的实现,并且属性是有用的,那么属性的接口仍然会和类之外的代码相同。 从实例variables到属性的更改对类外的代码没有影响。

许多其他语言和编程课程将指示程序员不应该公开实例variables,而是使用“getters”和“setter”来从课程外部访问任何值,即使是在问题中引用的简单情况。

使用多种语言(例如Java)使用类之外的代码

 object.get_i() #and object.set_i(value) #in place of (with python) object.i #and object.i = value 

而当实现这个类时,有许多“getters”和“setter”就像你的第一个例子一样:复制一个简单的实例variables。 这些getter和setter是必需的,因为如果类实现改变了,那么这个类之外的所有代码都需要改变。 但python属性允许类外的代码与实例variables相同。 所以,如果你添加一个属性或者有一个简单的实例variables,那么类外的代码就不需要改变。 因此,与大多数面向对象的语言不同的是,对于您的简单示例,您可以使用实例variables而不是实际不需要的“getters”和“setters”,因为知道如果将来更改属性,你的课不需要改变。

这意味着如果存在复杂的行为,则只需要创build属性;对于常见的简单情况,如问题中所述,只需要一个简单的实例variables,就可以使用实例variables。

起初没有注意到的是,你可以制造属于自己的子类。 这我发现非常有用的暴露只读对象的属性或属性,你可以读写,但不能删除。 这也是一个很好的方式来包装跟踪修改对象字段的function。

 class reader(property): def __init__(self, varname): _reader = lambda obj: getattr(obj, varname) super(reader, self).__init__(_reader) class accessor(property): def __init__(self, varname, set_validation=None): _reader = lambda obj: getattr(obj, varname) def _writer(obj, value): if set_validation is not None: if set_validation(value): setattr(obj, varname, value) super(accessor, self).__init__(_reader, _writer) #example class MyClass(object): def __init__(self): self._attr = None attr = reader('_attr') 

另一个使用setter和getters的属性,它允许你继续使用OP =操作符(例如+ =, – =,* = etc),同时仍然保留任何validation,访问控制,caching等制定者和获得者将提供。

例如,如果您使用setter setage(newage)和getter getage()编写了Person类,那么要增加您需要编写的年龄:

 bob = Person('Robert', 25) bob.setage(bob.getage() + 1) 

但是如果你把age变成财产,你可以写出更清洁的东西:

 bob.age += 1 

阅读答案和评论,主题似乎是答案似乎缺less一个简单而有用的例子。 我在这里包含了一个非常简单的@property ,演示了@property装饰器的简单使用。 这是一个允许用户使用各种不同的单位(即in_feetin_metres指定和获取距离测量值的in_metres

 class Distance(object): def __init__(self): # This private attribute will store the distance in metres # All units provided using setters will be converted before # being stored self._distance = 0.0 @property def in_metres(self): return self._distance @in_metres.setter def in_metres(self, val): try: self._distance = float(val) except: raise ValueError("The input you have provided is not recognised " "as a valid number") @property def in_feet(self): return self._distance * 3.2808399 @in_feet.setter def in_feet(self, val): try: self._distance = float(val) / 3.2808399 except: raise ValueError("The input you have provided is not recognised " "as a valid number") @property def in_parsecs(self): return self._distance * 3.24078e-17 @in_parsecs.setter def in_parsecs(self, val): try: self._distance = float(val) / 3.24078e-17 except: raise ValueError("The input you have provided is not recognised " "as a valid number") 

用法:

 >>> distance = Distance() >>> distance.in_metres = 1000.0 >>> distance.in_metres 1000.0 >>> distance.in_feet 3280.8399 >>> distance.in_parsecs 3.24078e-14