代码之家  ›  专栏  ›  技术社区  ›  watchtower

属性修饰器的变量以下划线开头

  •  5
  • watchtower  · 技术社区  · 8 年前

    我是巨蟒的新手。所以,如果这是一个基本问题,请原谅我。我在网上研究过这个话题,但找不到解释。我用的是蟒蛇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) 并从中恢复变量名 名字 到 名称

    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所做的)来检查或纠正这种行为。

    所以,现在最大的问题是,为什么我需要用下划线来处理属性?我相信这些下划线前缀只是为了让用户知道这是一个私有变量。


    我正在用卢茨的书来学习Python,上面的例子是从他的书中得到启发的。

    1 回复  |  直到 8 年前
        1
  •  1
  •   Patrick Artner    8 年前

    让我们看一下代码修复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 decorator完成。

    如果你定义了:

    def tata(self):
        print(self.name)  # also no () after self.name
    
    bob = Person('Bob Smith') 
    bob.tata()
    

    它还将调用@property方法,因为您可以通过 'fetch...' 输出。所以每次呼叫 yourclassinstance.name 将通过@property访问器-这就是为什么您不能 self.name 和它在一起。

    所以如果你从内部访问self.name 定义名称(自身) -堆栈溢出

    这是纯粹的观察——如果你想知道到底发生了什么,你必须检查 @财产 实施。在这里你可能会获得更多的洞察力: How does the @property decorator work? 或 How do Python properties work?