0

我刚刚将脚趾浸入 Python 池中。我了解类和命名空间如何交互,del只是从范围中删除东西,以及所有这些好处。

我的问题很简单。我做了一个简单的“hello world”(Pygame)应用程序,但犯了一个严重错误(下面的简单案例):

class Cat:
  __name = ""
  def __init__(self, newName):
    __name = newName
  def meow(self):
    print "Hi from {0}".format(self.__name)

c = Cat("Mittens")
c.meow(); # prints: "Hi from "

事后看来,我的错误很明显:在我的方法(构造函数,特别是这里)中,我分配了一个值 to__name而不是 to __self.name(顺便说一下,它应该是损坏的和私有的)。

我什至了解它的工作原理和原因——它有点像 Java/C# 中的静态作用域。

我不明白的是如何避免这些棘手的错误。这很明显,很容易,而在我的情况下,结果是什么都没有——事情应该会奏效,但什么也没发生。

Python 开发者如何避免这个问题?似乎它会很常见。

4

2 回答 2

2

在这种情况下,我肯定会避免添加__name到类命名空间。由于__name(应该是)由初始化程序(__init__)无条件地设置,因此没有必要设置类级别__name

例如:

class Cat:
  def __init__(self, newName):
    __name = newName
  def meow(self):
    print "Hi from {0}".format(self.__name)

c = Cat("Mittens")
c.meow() # prints: "Hi from "

现在运行代码,你会得到一个AttributeError有助于捕捉这些错误的代码。

换句话说,__init__在您的代码中的目的是设置__name正在初始化的新实例 ( self) via self.__name = newName。在您的代码中,您通过设置__name类来提供“安全网”。在 python 中,如果在实例上找不到属性,则在类中查找它。但是,在这种情况下,这个“安全网”实际上是一件坏事——您会得到与预期不同的行为,而不是可以用来帮助您追踪错误的异常。


作为旁注,实例上的属性访问的工作方式(排除有趣的事情,例如__getattribute__)是python首先在实例上查找属性,然后搜索类,然后按照类的方法解析顺序(其中新旧类不同)。

于 2013-03-08T20:21:48.327 回答
1

pep8pylintpyflakesflake8等静态分析工具可以在一定程度上提供帮助。例如,pyflakes会抱怨您的代码(放在名为 的文件中stack_overflow-2013-03-08.py):

$ pyflakes stack_overflow-2013-03-08.py
stack_overflow-2013-03-08.py:8: local variable '__name' is assigned to but never used

但是没有什么比一组好的测试更好的了。不用说,如果你有一个Cat.meow合理覆盖其功能范围的测试,你就会发现这个问题

于 2013-03-08T20:34:58.297 回答