Python一些难以察觉的错误

今天把微博的收藏夹打开,发现以前很多收藏的好文章还没有细细研究,今天开始要慢慢研究总结总结。今天看的这篇文章地址:

http://blog.amir.rachum.com/blog/2013/07/06/python-common-newbie-mistakes-part-1/

http://blog.amir.rachum.com/blog/2013/07/09/python-common-newbie-mistakes-part-2/

关于作用域

这个实际上是上述链接中的第二篇文章中的内容,我之所以先拿出来说是因为最近在手写一个简单的Python解释器,突然看到这个点觉得非常好理解。

首先给出出错代码:

bar = 42
def foo():
    print bar
    if False:
        bar = 0
>>> foo()
Traceback (most recent call last):
  File "<pyshell#17>", line 1, in <module>
    foo()
  File "<pyshell#16>", line 3, in foo
    print bar
UnboundLocalError: local variable 'bar' referenced before assignment

我们可以看到,第3行的print bar出错了,可是明明有一个全局变量bar啊!实际上,Python在解释程序前会进行各种处理,其中有一个部分叫做【静态检查】,其部分作用就是建立一个作用域的栈(注意:此时代码并没有执行,解释器只是在扫描代码而已)。虽然,第3行执行时,局部变量bar = 0这句不会被执行,但是在静态检查阶段,依然会将局部变量bar压入作用域栈,因此在执行时,print bar先检查作用域栈,而此时的栈顶元素肯定是局部变量bar而非全局变量bar,而局部变量永远没有机会声明,所有这句会出错。实际上将代码变成下面这样也一样会出错:

bar = 42
def foo():
print bar
bar = 0

出错原因是局部变量bar先使用后再赋值。

那么如何避免这个问题呢?原文作者给出了两个解决方法:

  1. 使用global关键词,将局部变量明确声明为全局变量
  2. 将全局变量作为类的属性。

使用可变值类型作为函数默认参数

学过python都知道,可变值只list、dict等这类可以修改值的类型,而像元组、int等都是不可变的。

def foo(numbers=[]):
numbers.append(9)
print numbers

当函数foo调用时传入非空参数是,函数的动作非常正常,而当我们使用默认参数时就能发现问题:

>>> foo() # first time, like before
[9]
>>> foo() # second time
[9, 9]
>>> foo() # third time...
[9, 9, 9]
>>> foo() # WHAT IS THIS BLACK MAGIC?!
[9, 9, 9, 9]

我们的期望是每次调用foo()都只输出[9]啊!!!解释这个现象的关键点是:在Python里,函数的默认值是在函数定义的时候实例化的,而不是在调用的时候。而在每一次调用函数时,这个值都会存储起来,如果值没有变化,调用时也引用这个值。

类似情况,如果我们这样定义函数:

def print_now(now=time.time()):
    print now
    
>>> print_now()
1416878890.67
>>> print_now()
1416878890.67

每次调用的结果相同,因为time.time()的结果是可变的,因此now的默认值是声明时的结果。

Python一些难以察觉的错误的更多相关文章

  1. Python traceback 模块,追踪错误

    Python traceback 模块,追踪错误 import traceback try: your code except: traceback.print_exc()

  2. Python常见十六个错误集合,你知道那些?

    使用python会出现各种各样的错误,以下是Python常见的错误以及解决方法. 1.ValueError: 'Conv2d_1a_3×3' is not a valid scope name 这个是 ...

  3. python pip安装模块提示错误failed to create process

    python pip安装模块提示错误failed to create process 原因: 报这个错误的原因,是因为python的目录名称或位置发生改动. 解决办法: 1.找到修改python所在的 ...

  4. selenium(python)登录时账号密码错误提示语

    selenium(python)登录时账号密码错误提示语的获取 可以用text

  5. python基本使用时常见错误

    python基本使用时常见错误 字符编码错误 如果要学习计算机编程语言,首先就要搞懂字符编码,否则在以后的学习过程中,将会是一场噩梦.在一开始使用的时候,我就遇到了很多的关于字符编码的问题,做个简单的 ...

  6. python中常见的一些错误异常类型

    python提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误.你可以使用该功能来调试python程序. 什么是异常? 异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的 ...

  7. python 处理protobuf 接口常见错误

    python 处理protobuf 接口常见错误 1.问题 : Assignment not allowed to repeated field '> http://www.coin163.co ...

  8. Python初学的易犯错误

    当初学 Python 时,想要弄懂 Python 的错误信息的含义可能有点复杂.这里列出了常见的的一些让你程序 crash 的运行时错误. 1)忘记在 if , elif , else , for , ...

  9. Python开发最常犯错误总结10种

    不管是在学习还是工作过程中,人都会犯错.虽然Python的语法简单.灵活,但也一样存在一些不小的坑,一不小心,初学者和资深Python程序员都有可能会栽跟头.本文是Toptal网站的程序员梳理的10大 ...

随机推荐

  1. RGPJS 教程之八 创造场景

    开始画面 游戏画面 代码 <!DOCTYPE html> <html> <head> <script src="rpg-beta-2.js" ...

  2. button 禁止

    1.按钮的id为btnzhuce==> 控制按钮为禁用:  $("#btnzhuce").attr({"disabled":"disabled& ...

  3. Windows xp 重载内核(使用Irp进行文件操作)

    一.前言 最近在阅读A盾代码A盾电脑防护(原名 3600safe)anti-rootkit开放源代码,有兴趣的可以去看雪论坛下载,本文代码摘自其中的重载内核. 二.实现步骤 1.ZwQuerySyst ...

  4. Hadoop集群基准测试

    hadoop jar ./share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.2.0-tests.jar TestDFSIO -wri ...

  5. 导入flash 逐帧动画

    只要图片是一序列的,比如0001-0100,就可以使用导入素材功能,选择第一张图片,选中影片剪辑并编辑然后点击导入到舞台,然后FlashCS6工具就会问你,这是一序列图片,是否逐帧导入,点是,就ok了 ...

  6. 机器学习笔记之人工神经网络(ANN)

    人工神经网络(ANN)提供了一种普遍而且实际的方法从样例中学习值为实数.离散值或向量函数.人工神经网络由一系列简单的单元相互连接构成,其中每个单元有一定数量的实值输入,并产生单一的实值输出. 上面是一 ...

  7. c++课程实训 银行储蓄系统

    基本要求:定义了用户类(User)和银行类(Bank),用成员函数实现各种功能,多文件组织程序.能用文本文件存取数据(如演示样例中给出的技术): 拓展方向: 序号 加分项目 细       则 1 改 ...

  8. C#反射深入学习

    C#反射 反射(Reflection)是.NET中的重要机制,通过放射,可以在运行时获得.NET中每一个类型(包括类.结构.委托.接口和枚举等)的成员,包括方法.属性.事件,以及构造函数等.还可以获得 ...

  9. C++ Code_TabControl

    主题 1. 选项卡控件基础 2. 显示图标的选项卡 3. 选项卡控件高级 4. 5.      属性      选项卡控件基础 1.插入1个对话框,新建1个类 CCDialog1,1 个对话框对应一个 ...

  10. INDY idhttp Post用法

    http://www.cnblogs.com/tk-del/archive/2013/05/10/3071541.html function Post(AURL: string; ASource: T ...