繁体   English   中英

Python对象属性 - 访问方法

[英]Python object attributes - methodology for access

假设我有一个具有某些属性的类。 访问这些属性最好(在Pythonic-OOP中)意义如何? 就像obj.attr 或者也许写get accessors? 这些东西的接受命名风格是什么?

编辑:您能详细说明使用单个或双前导下划线命名属性的最佳实践吗? 我在大多数模块中看到使用单个下划线。


如果这个问题已经被提出(我有预感,虽然搜索没有带来结果),请指出它 - 我将关闭这个。

关于单引号和双引号下划线:两者都表示“私有性”的相同概念。 也就是说,人们会知道属性(无论是方法还是“普通”数据属性或其他任何东西)都不是对象的公共API的一部分。 人们会知道直接触摸它是为了引发灾难。

最重要的是,双引导下划线属性(但不是单引导下划线属性)是名称错误的 ,以便从子类或当前类之外的任何其他位置偶然访问它们可能性较小。 你仍然可以访问它们,但不是那么简单。 例如:

>>> class ClassA:
...     def __init__(self):
...         self._single = "Single"
...         self.__double = "Double"
...     def getSingle(self):
...         return self._single
...     def getDouble(self):
...         return self.__double
... 
>>> class ClassB(ClassA):
...     def getSingle_B(self):
...         return self._single
...     def getDouble_B(self):
...         return self.__double
... 
>>> a = ClassA()
>>> b = ClassB()

您现在可以a._single访问a._singleb._single并获取ClassA创建的_single属性:

>>> a._single, b._single
('Single', 'Single')
>>> a.getSingle(), b.getSingle(), b.getSingle_B()
('Single', 'Single', 'Single')

但是尝试直接访问ab实例上的__double属性将不起作用:

>>> a.__double
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: ClassA instance has no attribute '__double'
>>> b.__double
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: ClassB instance has no attribute '__double'

虽然ClassA定义的方法可以直接获取它(当在任一实例上调用时):

>>> a.getDouble(), b.getDouble()
('Double', 'Double')

ClassB定义的方法不能:

>>> b.getDouble_B()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in getDouble_B
AttributeError: ClassB instance has no attribute '_ClassB__double'

就在那个错误中,你会得到关于正在发生的事情的暗示。 __double属性名称,一个类的内部访问时,正在名称错位,包括它被访问的类的名称。 ClassA尝试访问self.__double ,它实际上 - 在编译时 - 变为self._ClassA__double的访问,同样对于ClassB (如果ClassB中的方法要分配给__double ,为了简洁不包含在代码中,那么就不会触及ClassA__double但是会创建一个新属性。)此属性没有其他保护,所以你仍然可以访问如果你知道正确的名字就直接:

>>> a._ClassA__double, b._ClassA__double
('Double', 'Double')

那为什么这是一个问题呢?

好吧,只要你想继承并改变处理这个属性的任何代码的行为,这就是一个问题。 您必须重新实现直接触及此双下划线属性的所有内容,或者您​​必须猜测类名并手动修改名称。 当这个双下划线属性实际上是一个方法时问题变得更糟:覆盖方法或在子类中调用方法意味着手动执行名称修改,或者重新实现调用方法的所有代码以不使用双下划线名称。 更不用说使用getattr()动态访问属性了:你也必须在那里手动修改。

另一方面,由于该属性只是简单地重写,它只提供表面的“保护”。 任何一段代码仍然可以通过手动修改来获取属性,尽管这会使他们的代码依赖于您的类的名称,并且您可以努力重构代码或重命名您的类(同时仍保持相同的用户可见名称,Python中的常见做法)将不必要地破坏他们的代码。 他们还可以通过命名类似于你的类来“欺骗”Python为它们进行名称修改:注意在受损的属性名称中没有包含模块名称。 最后,双下划线属性仍然可以在所有属性列表和所有形式的内省中看到,这些内省不需要跳过以( 单个 )下划线开头的属性。

因此, 如果您使用双下划线名称,请极其谨慎地使用它们,因为它们可能会非常不方便,并且永远不会将它们用于方法或其他任何子类可能想要重新实现,覆盖或直接访问的内容 并意识到双重领先的下划线名称 - 错误提供没有真正的保护 最后,使用单个前导下划线同样可以赢得你,并为你提供更少(潜在的,未来的)痛苦。 使用单个前导下划线。

普遍接受的做事方式就是使用简单的属性,就像这样

>>> class MyClass:
...     myAttribute = 0
... 
>>> c = MyClass()
>>> c.myAttribute 
0
>>> c.myAttribute = 1
>>> c.myAttribute
1

如果你确实发现自己需要能够编写getter和setter,那么你想要寻找的是“python类属性”,而Ryan Tomayko关于Getters / Setters / Fuxors的文章是一个很好的起点(尽管有点长)

编辑:您能详细说明使用单个或双前导下划线命名属性的最佳实践吗? 我在大多数模块中看到使用单个下划线。

单下划线并不意味着python有什么特别之处,这只是最好的做法,告诉“嘿,你可能不想访问它,除非你知道你在做什么”。 然而,双下划线使python mangle成为内部名称,只能从定义它的类中访问它。

双前导和尾随下划线表示一个特殊函数,例如__add__ ,在使用+运算符时调用。

阅读PEP 8中的更多内容,尤其是“命名约定”部分。

我认为大多数只是直接访问它们,不需要get / set方法。

>>> class myclass:
...     x = 'hello'
...
>>>
>>> class_inst = myclass()
>>> class_inst.x
'hello'
>>> class_inst.x = 'world'
>>> class_inst.x
'world'

顺便说一下,你可以使用dir()函数来查看你的实例附加了哪些属性/方法:

>>> dir(class_inst)
['__doc__', '__module__', 'x']

两个主要的下划线“__”用于使属性或函数私有。 有关其他惯例,请参阅PEP 08: http//www.python.org/dev/peps/pep-0008/

Python不需要从一开始就定义访问器,因为将属性转换为属性是快速而轻松的。 请参阅以下内容以获得生动的演示:

从成瘾中恢复

在python中没有真正意义上的getter / setter,你无论如何都无法保护东西,如果在获取/设置属性时需要执行一些额外的代码,请查看属性()内置(python -c'help(属性) )“)

有些人使用getter和setter。 根据您使用的编码样式,您可以将它们命名为getSpam和seteggs。 但您也可以只读取属性或仅指定属性。 这有点尴尬。 一种方法是压倒一切

> __getattr__

> __setattr__

方法。

编辑:

虽然我的回答仍然是正确的,但是当我意识到这一点时,这是不对的。 有更好的方法在python中创建访问器并且不是很尴尬。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM