【问题标题】:Accessing private class variable访问私有类变量
【发布时间】:2015-09-25 11:54:35
【问题描述】:

在学习 Python 时,我遇到了这种奇怪的行为:

考虑这个简单的类:

class Human(object):
  def __init__(self, name):
    self.__name = name

  def description(self):
    print("Hello, my name is %s" % self.__name)

我想避免在创建对象后更改名称。

如果我使用这个:

MyHuman = Human("Andy")
MyHuman.__name = "Arthur"
MyHuman.age = 23

MyHuman.description()
print MyHuman.age

它不会在对象实例化后更改名称,这很好,因为我希望实例变量是私有的。另一方面,我认为它会抱怨访问这个变量。它甚至不会抱怨访问一个神秘的“年龄”变量并在以后正确打印它。

我来自 C#,这对我来说似乎很奇怪。我的错在哪里?

【问题讨论】:

  • 您的错误在于认为 Python 中有私有变量。最接近隐私的模拟是“不要注意幕后的变量”。如果有人真的想看看幕后,那取决于他们。官方用语是“同意的成年人”。
  • 这里有一些关于 Python 对象和作用域的documentation
  • 好的,但是“年龄”变量呢?您可以即时创建变量(例如,如果我只是打错字)有点令人困惑,不是吗?
  • 拼写错误会导致计算机程序出现意外行为,这会让人感到困惑吗?
  • 你不能在 C#/Java/etc 中动态创建变量吗?与int age = 23;? Python 允许您将这些变量放入任何对象的命名空间中,因为它非常方便。

标签: python class python-2.7 properties scope


【解决方案1】:

你应该知道以下几点:

  1. 当你写入一个不存在的对象的属性时,python 系统通常不会报错,而只是创建一个新属性。
  2. 私有属性不受 Python 系统保护。这是设计决定的。
  3. 私有属性将被屏蔽。原因是,继承链中不应该有冲突。屏蔽是通过一些隐式重命名来完成的。私有属性将具有真实名称
  "_<className>__<attributeName>"

使用该名称,可以从外部访问它。从类内部访问时,名称将自动正确更改。

【讨论】:

  • 来自 C#,类成员的自动创建对我来说有点令人不安。我会习惯的:)谢谢你的解释和你的时间。
  • @AndyM:不客气。是的,Python 确实有一些奇怪之处,私有成员就是其中之一。你可以把它算作这样一个事实,Python 是一种脚本语言,也为它感到自豪;)设计者想要明确的东西,不想像其他语言那样拥有一个类型安全的系统——它只是依赖更多关于开放和清晰。它执行较少,但依赖于用户的“良好行为”。
【解决方案2】:

要在 Python 中使用模拟只读/私有变量,请使用property 语法。 (评论/其他答案指出,如果您知道如何访问该变量 - 感谢您的提醒)。这是一种方法:

>>> class Test:
        def __init__(self):
            self.__a = 1

        @property
        def a(self):
            return self.__a

>>> t = Test()
>>> t.a
1
>>> t.a = 2
AttributeError: cannot set attribute
>>> t.__a
AttributeError: 'Test' object has no attribute '__a'

【讨论】:

  • &gt;&gt;&gt; t._Test__a, 1.
  • 此示例在 python 2.7 和 3.0 上的行为是否可能不同?是我的 IDE,使用 python 2.7,我没有收到错误消息,并且允许 t.a = 2。在在线 3.0 解释器上测试它,我得到和你一样的错误......
  • @AndyM 是的,这似乎很有可能。您是否尝试过将您的 Python 2 类定义为新样式类class Classname(object)?那可能会有所作为。我不知道。
  • @Sam 绝对正确。在我的类声明中添加 (object) 会给我正确的行为。很有意思 !感谢您的精确!
  • @AndyM:我想,这就是问题所在。 Python 2 仍然支持“旧式类”——它们在某些属性领域具有完全不同的行为。不同之处在于旧式课程是像 Sam 一样开始的。据我所知,Python 3 仅支持新样式类,所以我猜它只是忽略了语法差异。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-05
  • 2012-06-04
  • 2013-08-06
  • 2014-02-09
  • 2015-11-27
  • 1970-01-01
相关资源
最近更新 更多