python中更快的属性访问

时间:2013-06-01 19:29:30

标签: python pylint

考虑以下课程:

class MyObject(object):

    __slots__ = ('_att1', '_att2')

    def __init__(self):
        self._att1 = None
        self._att2 = None

    @property
    def att1(self):
        """READ-ONLY property. """
        return self._att1

    @property
    def att2(self):
        """att2 property description. """
        return self._att2

    @att2.setter
    def att2(self, val):
        self._att2 = val

使用属性装饰器的一个优点是我们可以添加一些文档

a = MyObject()
help(a)
Help on MyObject in module __main__ object:

class MyObject(__builtin__.object)
 |  Methods defined here:
 |  
 |  __init__(self)
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  att1
 |      READ-ONLY property.
 |  
 |  att2
 |      att2 property description.

如果该类要由最终用户使用,则可以访问这些属性 通过使用属性。

a.att2 = "new value"

但是,如果我要从MyObject派生一个类,在派生类中使用“protected”变量是否可以接受?也就是说,

 class Derived(MyObject):

     __slots__ = ()

     def __init__(self):
         self._att1 = 1
         self._att2 = 0

     @property
     def att2(self):
         """att2 adds 1 to itself in every call. """
         self._att2 += 1
         return self._att2

     @att2.setter
     def att2(self, val):
         self._att2 = val

我知道如果MyObject是来自第三方的对象,那么带有下划线的属性可能会发生变化,因此如果他们做了更改,我的代码就会中断。但是,由于我使用MyObject作为基类,我认为可以将它与我自己的派生类一起使用。

我最近开始使用pylint,这让我意识到我在派生类中使用“受保护”变量这一事实。我决定在这里发布一个问题的原因是要知道这是否可以接受,以便我可以在pylint中禁止这些警告。如果不是,那么处理这个问题的标准是什么?

我想提出的另一点是关于属性访问。什么会更快

a.att1

a._att1

我的印象是,通过执行a.att1 python,首先会查看对象字典,或插槽,就像我正在使用的示例中一样。如果在查找函数时没有找到它(就像__getattr__的情况那样)。在我的类定义中进行大量计算时,我宁愿访问位于字典或插槽中的内容,而不是我使用装饰器定义的内容。这在python社区中被认为是不好的做法吗?我只是问这个问题,因为pylint的默认配置告诉了我,我想继续努力保持良好的标准。

编辑:

让我们尽量不要讨论__slots__和过早优化。如果可能的话 假设在我的原始帖子中我没有使用__slots__并且所有内容都在对象的字典中。

3 个答案:

答案 0 :(得分:5)

带下划线的属性不是“受保护”,而是“私有” - 它们可能会发生变化。即使你的班级是从它衍生出来的。您应该使用父属性来访问此数据。

谈到表现。当然,属性访问比属性访问慢一点,因为它涉及函数调用,但您不应该关心它。顺便说一句,它与__getattr__和所有这些东西无关。在字典中也会将属性作为普通属性查找,它们只是实现descriptor protocol

答案 1 :(得分:4)

简短回答:“过早优化是万恶之源。”

信任pylint。看看你是否确实遇到了性能问题。如果是的话,配置文件,而不是瓶颈。更改循环或数据结构可能更有效。

答案 2 :(得分:1)

Python在私有和受保护的类成员之间没有正式的区别。即使私人和公共之间的区别也相当薄弱,因为如果用户努力尝试,任何东西都可以被访问。如果私有与受保护的区别对您的应用程序有意义,您可以简单地记录_foo(或foo)不是公共用户界面的一部分,但子类可以依赖它来始终拥有某些语义。 (那些语义是由你决定的。)

现在,我不知道为一个简单的只读属性执行此操作是否值得文档工作(函数调用开销可能不是太糟糕,因此子类可以像其他人一样使用该属性)。但是,如果你有一个属性做了很多工作,比如数据库查询或HTTP请求,那么为子类暴露一些内容以获得他们需要的部分可能会有一些意义。

如果您认为需要公开“受保护”值,唯一的问题是您是否应该将下划线放在变量名称前面。下划线对诸如dir之类的内容以及可能在文档生成工具中有一些影响,但它并没有改变代码运行的方式。

所以它确实是代码风格的问题,无论如何它都无关紧要。您可以关闭下划线并在文档中放置大警告文本,以便用户知道他们不应该弄乱内部,或者您可以使用下划线并使pylint警告静音(如果有必要,强制有一些警告)子类实现者的额外文档。)