【发布时间】:2018-12-22 19:20:45
【问题描述】:
我是 Python 新手。所以,如果这是一个基本问题,请原谅我。我在互联网和SO上研究了这个话题,但我找不到解释。我正在使用 Anaconda 3.6 发行版。
我正在尝试为属性创建一个简单的 getter 和 setter。我将引导您解决我遇到的错误。
class Person:
def __init__(self,name):
self.name=name
bob = Person('Bob Smith')
print(bob.name)
这会打印我同意我没有覆盖 print 或 getattribute 方法的名字。此外,这里没有财产。这是为了测试基本代码是否有效。
让我们修改代码以添加属性:
class Person:
def __init__(self,name):
self.name=name
@property
def name(self):
"name property docs"
print('fetch...')
return self.name
bob = Person('Bob Smith')
print(bob.name)
当我在 PyCharm 中编写上述代码时,我会看到一个黄色灯泡图标,说明该变量必须是私有的。我不明白其中的道理。
忽略上面,如果我运行上面的代码,我会得到:
Traceback (most recent call last): File "C:\..., in run_code exec(code_obj, self.user_global_ns, self.user_ns) File "<ipython-input-25-62e9a426d2a9>", line 2, in <module> bob = Person('Bob Smith') File "<ipython-input-24-6c55f4b7326f>", line 4, in __init__ self.name=name AttributeError: can't set attribute
现在,我研究了这个主题,发现有两个修复(不知道为什么会这样):
修复 #1: 将变量 name 更改为 _name
class Person:
def __init__(self,name):
self._name=name #Changed name to _name
@property
def name(self):
"name property docs"
print('fetch...')
return self._name #Changed name to _name
bob = Person('Bob Smith')
print(bob.name)
这很好,因为它可以正确打印输出。
修复 #2: 将属性名称从 name(self) 更改为 _name(self) 并将变量名称从 _name 恢复为 name
class Person:
def __init__(self,name):
self.name=name #changed to name
@property
def _name(self): #Changed to _name
"name property docs"
print('fetch...')
return self.name #changed to name
bob = Person('Bob Smith')
print(bob.name)
现在,这可以按预期打印。
下一步,我使用装饰器创建了setter、getter 和deleter 属性。它们遵循与上述类似的命名约定——即变量名或方法名的前缀_:
@_name.setter
def _name(self,value):
"name property setter"
print('change...')
self.name=value
@_name.deleter
def _name(self):
print('remove')
del self.name
bob = Person('Bob Smith')
print(bob.name)
bob.name = 'Bobby Smith'
print(bob.name)
del bob.name
问题:我不太确定为什么 Python 3.x 强制将 _ 添加到变量名或方法名。
根据Python property with public getter and private setter、What is the difference in python attributes with underscore in front and back 和https://www.python.org/dev/peps/pep-0008/#naming-conventions,下划线前缀对于用户来说是一个弱指标,表明此变量是私有变量,但没有额外的机制到位(通过 Python,类似于Java 做了什么)来检查或纠正这种行为。
那么,手头的大问题是,为什么我需要使用下划线来处理属性?我相信那些下划线前缀只是为了让用户知道这是一个私有变量。
我正在使用 Lutz 的书来学习 Python,以上示例的灵感来自他的书。
【问题讨论】:
-
如果你有一个名为
foo的属性,你认为当它的实现访问foo时会发生什么? -
为什么你会同时拥有一个“公共”属性和一个getter/setter?如果您不需要额外的逻辑,我只会使用该属性并访问它。如果您有其他逻辑,我会将其创建为“私有”并将 getter/setter 作为封装我的附加逻辑的入口点。我永远不会将 both 呈现给外部,这只是令人困惑,并提供了一种从外部规避我的 getter/setter 逻辑的方法。这与创建它们的初衷背道而驰……您为什么要这样做?
-
@PatrickArtner - 我不知道为什么普通的
name变量或方法不起作用。事实上,如果我删除所有_,那么代码会编译,但我会得到 stackoverflow 错误。我真的不确定。我在 Internet 和 Lutz 的书中看到的所有示例都使用以_作为前缀的变量或以_作为前缀的方法。我不知道为什么。 -
下划线没有什么特别之处。编辑可能会建议它,但 python 本身并不关心。正在发生的事情是“名称”访问将获取所谓的“名称”。如果那是财产,那就太好了。如果该属性然后尝试访问“名称”,它会命中任何名称。即本身。该属性需要自行完全计算。或者它需要访问其他一些实例变量。可能是“NAME”,大写。但是,Python conventions 通常说 _ 表示私有,因此 _name 是一个很好的缓存。编辑警告说这是个傻瓜,但也太规范了。
-
在 Chandler(一个失败的开源 PIM)时代,有人写了一篇文章 Python is not Java- getter 和 setter 是 Python 的反模式,除非他们主动做某事。这可能是从所有奥斯卡奖得主中随机选择一个名字。它可能会阻止名称被更改。但是直接获取/设置本身没有什么理由,包括离开公开课以进行进一步的私人修改
标签: python python-3.x properties decorator python-decorators