Python编程者共性错误

引言

本篇博客为译文,翻译自Learning Python一书作者总结的Python编程者共性错误一文,原文英文网址为

http://www.onlamp.com/pub/a/python/2004/02/05/learn_python.html

第一次翻译这种技术博客,有错误之处请及时指出。

注意:不是按照原文一字一句翻译的,意译,因此只要保证技术细节对就行。


程序运行错误(Progmatic Mistakes)

在具体到具体程序语法之前,初学者可能遇到的错误,主要集中在运行程序可能会犯的一些错误。

在交互命令行输入python代码

区别系统命令行与python交互命令行的区别,在windows或linux系统命令行中输入“python”,回车后进入python 交互命令行(interactive prompt),此时命令行以“>>>”开头,可以输入python代码,不可以直接输入ls,emac,vim等系统命令,当然此时也可以调用这些命令,但不能直接调用,要是用python的package,“import os.system”,之后才能调用;在python交互命令行也不能直接运行python文件,在系统命令行可以,“python filename”即可,而在python交互命令行下,需要使用“import file”命令才能使用。

在文件中必须使用print语句

在交互命令行自动打印变量或表达式结果,但是在以文件形式运行python程序时(程序写在代码文件里),必须输入print语句才能打印结果。

在Windows系统中注意自动扩展名

在Windows系统中使用记事本等编辑文件中,默认保存为txt文件,此时使python解释器无法运行python代码,注意选择保存格式为all files,然后手动敲入文件名加文件扩展名,如“filename.py”,也可以使用特定的代码编辑软甲或集成开发环境。

Windows系统直接点击运行代码文件

Windows系统中双击运行代码文件,如果没有input()等语句,则程序运行时会一闪而过,基本无法看到运行结果,此时,要在系统命令行下python filename.py或import module或在集成开发环境中运行程序。

import只在第一次起作用

import语句用于导入其他模块,但如果你一直在输入程序,而没有关闭交互命令行,此前import的模块一直驻留在内存中,你对其他模块的更改不会作用到当前输入的程序中,需要重新载入(reload)模块,具体调用reload函数,如“ reload(module)”

在交互命令行中空白行有意义

在文件中,空白行没有任何意义,被解释器忽略,但是在交互命令行中,为了区分代码块是否完结,需要空白行来间隔其他代码来表示,因此对于for,while,等代码块结束时,需要额外输入至少一行空白行表示该代码块结束。

编码错误(Coding Mistakes)

不要忘记冒号

if、while、for等复合语句需要加冒号。

初始化变量

在python中,只有给一个变量指定一个值,才能在表达式中调用它,防止变量歧义问题,如默认赋值到底该赋值什么0,None,“”,[] ?,这是因为python是非强类型语言,必须通过赋值确定变量如何分配内存。

从第一列开始

顶层代码,都从最左侧第一列开始。

缩进一致

避免空格与Tab混合进行缩进。

调用函数总是使用括号语法

调用函数,为函数名加括号。

在import时不要加扩展名或路径

import时会在环境变量指定的路径下查找,因此不需要指定路径;import时不需要加文件扩展名。

不要在python中输入C代码

  • if,for,while 语句中不要加括号。
  • 不要以分号结束语句
  • 在while循环测试中,不能出现赋值语句

编程错误(Programming mistakes)

这部分设计数据类型、函数、模块、类等错误。

文件打开不调用模块搜索路径

使用文件打开函数时,不使用模块搜索的路径,而是参数给出的绝对当前目录相对路径。

方法是类型特定的

list的方法不能用于strings类型数据;len函数可以通用于任何带长度对象。

不可变类型不能原地改变

不可变类型如元祖、字符串不能原地改变。如

T = (1, 2, 3)
T[2] = 4 # Error

使用简单for循环代替while或range

当需要遍历序列对象是,直接使用for循环,而不是使用基于while或range的循环,避免使用range函数,除非必要,让python自己处理索引,如

S = 'lumberjack'

for c in S: # simplest
    print(c)

for i in range(len(S)): # too much
    print(S[i])

i = 0
while i < len(S): # too much
    print(S[i])
    i += 1

不要指望来自函数的结果改变对象

原地改变操作如list.append()和list.sort()改变对象,但是没有返回被修改的对象;如

mylist = mylist.append(X)

mylist将会被赋值为None而不是给修改的list。

D = {1:'a', 2:'b'}
for k in D.keys().sort():
    print(D[k])

上面代码出错,因为sort()函数返回None,不是序列变量不能进行循环遍历,正确的为

Ks = D.keys()
Ks.sort()
for k in Ks:
    print(D[k])

转换只发生在数字类型之间

默认自动转换只发生在数字类型之间,如果在数字类型与字符串类型则不能转换,这是因为非数字类型之间转换无法确定转为哪一种类型。

Cyclic数据结构可导致循环

集合对象包含对自身的引用称为cyclic object,python会打印为[ … ]当它发现对象存在循环时,而不是陷入无限循环。

赋值产生引用,不是拷贝

这个python的核心概念。

L = [1, 2, 3]
M = ['M', L, 'Y']
print(M) # ['X', [1, 2, 3], 'Y']
L[1] = 0
print(M) # ['X', [1, 0, 3], 'Y']

可以拷贝避免共享对象。

L = [1, 2, 3]
M = ['M', L[:], 'Y']
print(M) # ['X', [1, 2, 3], 'Y']
L[1] = 0
print(L) # [1, 0, 3]
print(M) # ['X', [1, 2, 3], 'Y']

局部变量被静态发现

python将函数内部赋值的变量默认为局部变量,存在于函数范围内,只在函数运行时。python静态发现局部变量。

X = 99
def func():
    print(X) # Does not yet exit
    X = 88   # Make X local in entire def

func() # Error!

会报错,编译这段代码时,python发现赋值语句,X在函数内部局部变量,实际函数运行时,赋值语句还没执行,python产生未定义名称错误(undefined name error)。
上述代码是歧义的:你是要打印全局变量X,然后创建一个局部变量X,还是这是一个编程错误?如果你要打印全局变量X,应该用global声明或通过模块名调用。

默认或可变对象

默认参数被存储一次,当def语句运行时,而不是每次调用,在改变可变对象时必须小心,如

def saver(x=[]):
    x.append(1)
    print(x)
saver([2]) # [2, 1], Default not used
saver() # [1], Default used
saver() # [1, 1], Grows on each call!
saver() # [1, 1, 1]

改变上述行为,可以通过在函数开始处拷贝默认值或移动默认值表达式到函数体中,只要保证赋值代码每次函数调用时执行即可。

def saver(x=None):
    if x is None: # No arg passed?
        x = []    # Changes new list
    x.append(1)
    print(x)
saver([2]) # [2, 1], Default not used
saver() # [1], Default used
saver() # [1], Doesn't grows now
saver() # [1]

其他错误

  • 文件从上到下读取,因此非递归代码调用在定义之下
  • reload不作用于from语句
  • 多继承时从左至右,最左类继承如果后面还有同名出现
  • 空except语句捕获所有类型异常
  • Bunnies can be more dangerous than they seem(不知道如何翻译)

你可能感兴趣的:(Python编程者共性错误)