1

考虑以下类:

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,是否可以在派生类中使用“受保护”变量?那是,

 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.att1python 会首先查看对象字典或插槽,如我正在使用的示例中。如果它在查找函数时不存在(如 的情况__getattr__)。在我的类定义中进行大量计算时,我宁愿访问位于字典或插槽中的东西,而不是我用装饰器定义的东西。这在 python 社区中被认为是不好的做法吗?我只是问这个,因为默认配置pylint告诉我否则我想继续工作,牢记良好的标准。

编辑:

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

4

3 回答 3

5

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

谈到性能。当然,属性访问比属性访问慢一点,只是因为它涉及到一个函数调用,但你不应该关心它。__getattr__顺便说一句,它与所有这些东西无关。属性也作为普通属性在字典中查找,它们只是实现描述符协议

于 2013-06-01T19:42:22.510 回答
4

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

相信皮林特。看看你是否真的有性能问题。如果是,请分析并解决瓶颈问题。更改循环或数据结构可能更有效。

于 2013-06-01T19:37:38.540 回答
1

Python 在私有和受保护的类成员之间没有正式的区别。甚至私人和公共之间的区别也很微弱,因为如果用户足够努力,任何东西都可以访问。如果私有与受保护的区别对您的应用程序有意义,您可以简单地记录_foo(或foo)不是公共用户界面的一部分,但子类可以依赖它以始终具有某些语义。(这些语义是什么取决于你。)

现在,我不知道是否真的值得为一个简单的只读属性执行此操作(函数调用开销可能还不错,因此子类可以像其他人一样使用该属性)。但是,如果您有一个正在做更多工作的属性,例如数据库查询或 HTTP 请求,那么将内部结构稍微暴露一下以使子类仅获取它们需要的部分可能是有意义的。

如果您确实认为公开“受保护”值是可取的,那么唯一的问题是您是否应该将下划线放在变量名的前面。下划线对诸如文档生成工具之类的东西有一些影响dir,但它不会改变代码的运行方式。

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

于 2013-06-02T06:48:09.223 回答