什么是声明变量的pythonic方式?

时间:2010-02-06 15:09:32

标签: python

通常在赋值时声明变量被视为VBScript或JavaScript中的最佳实践,例如,尽管允许这样做。

为什么Python强制您仅在使用它时创建变量?由于Python区分大小写不能导致错误,因为你错误拼写了一个变量的名字?

你会如何避免这种情况?

8 个答案:

答案 0 :(得分:15)

这是“教学语言”对Python灵感的愚蠢神器,它通过完全消除“声明”的绊脚石,使语言更易于访问。无论出于何种原因(可能表示为“简单”),Python从未获得像VB的“Option Explicit”这样的可选限制来引入强制声明。是的,它可能是错误的来源,但正如其他答案所示,良好的程序员可以养成习惯,使他们能够弥补语言中的任何缺点 - 而且由于缺点,这是一个非常小的问题。

答案 1 :(得分:12)

如果你想要一个具有“锁定”实例属性的类,那就不难做出一个,例如:

class LockedDown(object):
  __locked = False
  def __setattr__(self, name, value):
    if self.__locked:
      if name[:2] != '__' and name not in self.__dict__:
        raise ValueError("Can't set attribute %r" % name)
    object.__setattr__(self, name, value)
  def _dolock(self):
    self.__locked = True

class Example(LockedDown):
  def __init__(self):
    self.mistakes = 0
    self._dolock()
  def onemore(self):
    self.mistakes += 1
    print self.mistakes
  def reset(self):
    self.mitsakes = 0

x = Example()
for i in range(3): x.onemore()
x.reset()

正如您所看到的,对x.onemore的调用工作正常,但reset因异常错误拼写mitsakes而引发异常。这里的参与规则是__init__必须将所有属性设置为初始值,然后调用self._dolock()以禁止任何进一步添加属性。我正在豁免“超私有”属性(以__开头的),这些属性在风格上应该很少使用,对于完全特定的角色,并且范围非常有限(使得在超级中发现拼写错误很容易)仔细检查,无论如何都需要确认超级私密的需要),但这是一种风格选择,容易扭转;类似地,选择使锁定状态“不可逆”(通过“正常”意味着 - 即需要非常明确的解决方法来绕过)。

这不适用于其他类型的名称,例如函数本地名称;再一次,没什么大不了的,因为每个函数都应该非常小,并且是一个完全独立的范围,很容易检查(如果你编写100行函数,你还有其他严重的问题; - )。

值得这么麻烦吗?不,因为半体面的单元测试显然应该最容易地捕获所有这样的拼写错误,作为彻底运用该类功能的自然副作用。换句话说,就好像你需要进行更多单元测试来捕获拼写错误一样:单元测试你无论如何都需要捕获琐碎的语义错误(逐个,+1在哪里 - 1表示等等,也已经记录了所有错别字。

罗伯特·马丁和布鲁斯·埃克尔7年前在单独和独立的文章中都阐述了这一点 - 埃克尔的博客现在暂时失效,但马丁的权利here,当埃克尔的网站恢复该文章应该是{{ 3}}。这篇论文是有争议的(例如,Jeff Attwood及其评论者对其进行辩论here),但有趣的是,Martin和Eckel都是C ++和Java等静态语言的知名专家(尽管有爱情事务)分别使用Ruby和Python),他们远远没有发现单元测试的重要性......以及良好的单元测试套件作为副作用如何使静态语言的冗余冗余

顺便说一下,检查测试套件的一种方法是“错误注入”:系统地检查你的代码库,引入一个错误的拼写 - 运行测试以确保它们确实失败,如果它们没有添加一个确实失败,纠正拼写错误,重复一遍。可以相当好地自动化(不是“添加测试”部分,而是查找套件未涵盖的潜在错误),以及一些其他形式的错误注入(将每个整数常量逐个更改为还有一个,少一个;将每个<更改为<=等;将每个ifwhile条件交换为反向; ...),而其他形式的错误注入还需要更多的人类悟性。不幸的是,我不知道公开可用的错误注入框架套件(对于任何语言) - 可能会成为一个很酷的开源项目; - )。

答案 2 :(得分:9)

在python中,有必要考虑将变量声明为名称的绑定值。

尽量不要拼错它们,否则你会有新的拼写错误(假设你在谈论赋值语句 - 引用它们会引起异常)。

如果您正在谈论实例变量,那么之后您将无法使用它们。

例如,如果您有一个班级myclass并且在其__init__方法中写了self.myvar = 0,那么尝试引用self.myvare会导致错误,而不是给您默认值。

答案 3 :(得分:5)

Python只会在您使用它时强制您创建变量。您始终可以将None绑定到名称,然后在其他地方使用该名称。

答案 4 :(得分:4)

为了避免错误拼写变量名称的情况,我使用带有自动完成功能的文本编辑器并绑定

 python -c "import py_compile; py_compile.compile('{filename}')"

到保存文件时要调用的函数。

答案 5 :(得分:3)

测试。

示例,文件variable.py

#! /usr/bin/python

somevar = 5

然后,创建文件variable.txt(以进行测试):

>>> import variables
>>> variables.somevar == 4
True

然后做:

python -m doctest variable.txt

得到:

**********************************************************************
File "variables.txt", line 2, in variables.test
Failed example:
    variables.somevar == 4
Expected:
    True
Got:
    False
**********************************************************************
1 items had failures:
   1 of   2 in variables.test
***Test Failed*** 1 failures.

这表示变量声明不正确。

尝试:

>>> import variables
>>> variables.someothervar == 5
True

请注意,变量的名称不相同。

**********************************************************************
File "variables.test", line 2, in variables.test
Failed example:
    variables.someothervar == 5
Exception raised:
    Traceback (most recent call last):
      File "/usr/local/lib/python2.6/doctest.py", line 1241, in __run
        compileflags, 1) in test.globs
      File "<doctest variables.test[1]>", line 1, in <module>
        variables.someothervar == 5
    AttributeError: 'module' object has no attribute 'someothervar'
**********************************************************************
1 items had failures:
   1 of   2 in variables.test
***Test Failed*** 1 failures.

这显示拼写错误的变量。

>>> import variables
>>> variables.somevar == 5
True

然后返回没有错误。

我已经做了足够的VBScript开发,知道错别字是变量名中的问题,而且足够的VBScript开发知道Option Explicit充其量只是一个拐杖。 (&lt; - 12年的ASP VBScript经验告诉我艰难的方法。)

答案 6 :(得分:2)

如果您进行任何认真的开发,您将使用(集成)开发环境。 Pylint将成为其中的一部分,并告诉你所有的拼写错误。无需将这样的功能作为语言的一部分。

答案 7 :(得分:-1)

变量声明不会阻止错误。除了缺少变量声明之外,还会导致错误。

变量声明会阻止一种特定类型的错误,但会产生其他类型的错误。

<强>阻止即可。编写代码,尝试使用错误的数据类型设置(或更改)变量。

<强>原因即可。愚蠢的解决方法是将一些不相关的类型强制在一起,以便分配“正常工作”。示例:C语言union。此外,变量声明迫使我们使用强制转换。这也迫使我们在编译时抑制演员阵容的警告,因为我们“知道”它将“正常工作”。它没有。

缺少变量声明不会导致错误。最常见的“威胁情景”是对变量的某种“错误分配”。

  1. 变量是否被“重用”?这是愚蠢但合法且有效。

  2. 程序的某些部分是否错误地指定了错误的类型?

    这导致了一个微妙的问题“错误是什么意思?”在鸭式语言中,错误意味着“不提供正确的方法或属性”。这仍然模糊不清。具体来说,它意味着“将要求类型提供它没有的方法或属性。”这将引发异常,程序将停止。

  3. 在生产使用中提出未被捕获的异常是令人讨厌的并且显示缺乏质量。这是愚蠢的,但它也是一个检测到的,已知的故障模式,追溯到确切的根本原因。

    “不能因为拼写错误的名字错误导致错误”

    是。它可以。

    但请考虑这个Java代码。

    public static void maine( String[] argv ) {
        int main;
        int mian;
    }
    

    这里的拼写错误同样致命。静态类型的Java已经完成 nothing 以防止拼写错误的变量名称导致错误。