何时以及如何在python中使用内置函数property()

ola*_*ndo 68 python properties

在我看来,除了一点点语法糖,property()没有任何好处.

当然,这是好的能够写a.b=2的不是a.setB(2),但隐瞒事实,即AB = 2不是一个简单的任务看起来像麻烦的前提,要么是因为一些意想不到的结果都可能发生,如a.b=2实际上导致a.b1.或者引发异常.或者性能问题.或者只是让人困惑.

你能给我一个具体的例子来好好利用它吗?(使用它修补有问题的代码不计算;-)

Ale*_*lli 129

在依赖于getter和setter的语言中,比如Java,除了他们所说的之外,他们不应该做任何事情也不应该做任何事情 - x.getB()除了返回逻辑属性的当前值b,或者x.setB(2)除了做什么之外做任何事情都会令人惊讶x.getB()回报需要少量的内部工作2.

但是,对于这种预期的行为,没有语言强加的保证,即对名称以get或开头的方法体的编译器强制约束set:相反,它留给常识,社会习俗,"风格指南"和测试.

x.b访问行为以及诸如x.b = 2具有属性的语言(包括但不限于Python的一组语言)之类的赋值的行为与例如Java中的getter和setter方法完全相同:相同的期望,同样缺乏语言强制保证.

属性的第一个胜利是语法和可读性.必须写,例如,

x.setB(x.getB() + 1)
Run Code Online (Sandbox Code Playgroud)

而不是显而易见的

x.b += 1
Run Code Online (Sandbox Code Playgroud)

呼吁向众神复仇.在支持属性的语言中,绝对没有充分的理由迫使类的用户经历这种拜占庭模板的旋转,从而影响他们的代码的可读性而没有任何上升空间.

特别是在Python中,使用属性(或其他描述符)代替getter和setter还有一个很大的好处:如果你重组你的类以便不再需要底层的setter和getter,你可以(不破坏类的发布的API)简单地消除那些方法和依赖它们的属性,使得类b的正常"存储"属性x而不是"逻辑" 属性获得并计算设置.

在Python中,直接(在可行时)而不是通过方法执行操作是一项重要的优化,并且系统地使用属性使您可以在可行时执行此优化(始终直接暴露"常规存储属性",并且仅在访问时需要计算和/或通过方法和属性设置).

因此,如果你使用getter和setter而不是属性,除了影响用户代码的可读性之外,你无意中浪费机器周期(以及在这些周期中流向他们计算机的能量;-),再次没有充分的理由任何.

你反对属性的唯一论据是"例如,"外部用户不会因为作业而产生任何副作用,通常是这样; 但是你错过了这样一个事实:同一个用户(用Java这样的语言,其中getter和setter是普遍存在的)不会因为调用setter而导致(可观察的)"副作用"(对于getter来说甚至更少) ;-).他们是合理的期望,作为班级作者,你可以尝试和容纳他们 - 无论你的制定者和吸气者是直接使用还是通过财产使用,都没有区别.如果你有一个重要的观察到的副作用的方法,也没有他们的名字getThis,setThat和不通过属性使用它们.

该属性"隐藏实现"的抱怨是没有道理的全资:大部分面向对象是有关实现信息隐藏-制造类负责提出一个逻辑接口与外部世界和内部实现它,因为它最能.吸气剂和制定者,就像属性一样,是实现这一目标的工具.属性只是做得更好(用支持它们的语言;-).

  • @Adam Parkin如果客户端程序调用'GetTaxRate()',则不再能够在不破坏向后可比性的情况下删除方法'GetTaxRate'.但是,您可以删除"@property"而不会破坏向后兼容性,因为直接访问和"@property"使用相同的语法. (8认同)
  • 另外,看看C++的运算符重载.相同的"外部用户不会期望..."的论点适用.在某些情况下,您只是不希望用户知道.在这些情况下,您可以确保不会让用户感到惊讶. (4认同)
  • @Oren,好点,Python的运算符重载很像C++(赋值不能重载,因为它不是运算符,&c,但一般概念类似).这取决于编码人员的礼貌,门训和常识,以避免例如"__add__"改变自我和/或做一些与添加没有任何关系的事情 - 这并不意味着操作员超载在使用时有品味和合理(虽然Java的设计者不同意,因为他们故意将它排除在_their_语言之外! - ). (4认同)

Dan*_*man 31

这个想法是为了避免在实际需要之前编写getter和setter.

所以,开始你写:

class MyClass(object):
    def __init__(self):
        self.myval = 4
Run Code Online (Sandbox Code Playgroud)

显然你现在可以写了myobj.myval = 5.

但是后来,你决定你确实需要一个二传手,因为你想要同时做一些聪明的事情.但是你不想改变使用你的类的所有代码 - 所以你将setter包装在@property装饰器中,这一切都正常.

  • 您的示例正是我所说的“使用它来修补有问题的代码”的意思……很可能“有问题的”不是在此处使用的正确词,而是IMO的补丁。 (2认同)

Lee*_*e B 14

但是隐藏ab = 2的事实并不是一个简单的任务看起来像是一个麻烦的方法

你并没有隐藏这个事实; 这个事实从来没有开始.这是python - 一种高级语言; 不装配.其中很少有"简单"的陈述归结为单CPU指令.将简单性理解为赋值是读取不存在的东西.

当你说xb = c时,你应该想到的是"无论发生什么,xb现在应该是c".

  • 那是真正的诺姆.在另一方面,虽然,面向对象是所有具有的黑盒子对象,但他们目前的接口,所以一个可能应该假设怪,神奇的事情会在表面之下;) (5认同)
  • ab = 2几乎不是一个赋值,而不是x = 2.如果它们的实现方式不同,那么就是这样,OOP的重点是隐藏实现细节.如果ab = 2将某些东西设置为490,那么这是一个令人讨厌的副作用,无论如何都不会被a.setB(2)解决.如果你隐含地认为ab = 2应该是一个非常快的操作,当你看到它,那么你应该意识到你是在Python中并且已经至少比C慢一个数量级. (2认同)

Rei*_*ees 5

一个基本原因很简单,它看起来更好.它更pythonic.特别是对图书馆.something.getValue()看起来不如something.value好

在plone(一个非常大的CMS)中,你曾经有过document.setTitle(),它可以执行很多操作,例如存储值,再次索引它等等.只是做document.title ='某事'更好.你知道无论如何在幕后发生了很多事情.