我是Python的新手。因此,如果这是一个基本问题,请原谅我。我在Internet和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,上面的示例是从他的书中得到启发的。
答案 0 :(得分:1)
让我们来修改代码1:
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)
self._name = name
-这就是您的支持字段。def name(self)
-并使用@property
为其赋予属性。bob = Person('Bob Smith')
那你就print(bob.name)
-你在这里叫什么?
您的变量称为self._name
-bob.name()
会调用“非属性”方法。.为什么bob.name
仍然有效-由@property装饰器完成。
如果定义,会发生什么情况
def tata(self):
print(self.name) # also no () after self.name
bob = Person('Bob Smith')
bob.tata()
当您可以通过'fetch...'
输出进行检查时,它还会调用@property方法。因此,每次yourclassinstance.name
的调用都会通过@property访问器-这就是为什么您无法与self.name
一起使用的原因。
因此,如果您从def name(self)
内部访问self.name,则会导致堆栈溢出
这是纯粹的观察-如果您想查看实际发生的情况,则必须检查@property
的实现。您可能会在这里获得更多的见识:How does the @property decorator work?或How do Python properties work?