错误地没有将值设置为self.foo

时间:2013-03-08 20:17:56

标签: python

我只是把我的脚趾浸入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 "

事后看来,我的错误是显而易见的:在我的方法(构造函数,特别是这里)中,我为__name而不是__self.name分配了一个值(顺便说一下,它应该被修改为私有)。

我甚至理解它的工作原理和原因 - 它有点像Java / C#中的静态范围。

我不明白的是如何避免这些棘手的错误。这很明显,很容易,结果是,在我的情况下,没有任何事情 - 事情应该有效但没有任何事情发生。

Python开发人员如何避免这个问题?似乎很常见。

2 个答案:

答案 0 :(得分:2)

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

e.g:

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)上设置self.__name = newName。在您的代码中,您通过在课堂上设置__name来提供“安全网”。在python中,如果在实例上找不到属性,则会在该类上查找该属性。但是,在这种情况下,这个“安全网”实际上是一件坏事 - 你得到的行为与你预期的不同,而不是可以用来帮助你追踪错误的异常。


作为旁注,实例上的属性访问方式(对__getattribute__这样有趣的事情)是python首先在实例上查找属性,然后搜索类然后它按照它的方式工作该类的方法解析顺序(对于旧式和新式类而言不同)。

答案 1 :(得分: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

但没有什么能比tests更好。毋庸置疑,如果你对Cat.meow的测试合理地涵盖了它的功能范围,你就会发现这个问题right meow