Python Do And Dont(中文版)
2017-08-03
不应该的用法
from module import *
这种方式在python中一般是合法的, 但我们不推荐这么做, 为什么呢
- 运行更慢
因为编译器不确定哪些变量是local
的, 哪些是global
的, 而且在早期的python(2.1之前)版本里, 这种用法还会报错
- 不确定地函数,变量, 类等引入导致覆盖本地的原有定义
比如, 我们可以如果想打开一个文件
f = open("www")
f.read()
一般情况下, 以上代码是可以正常运行的(假设www
文件存在), 但如果在文件的头部添加from os import open
from os import *
f = open("www")
f.read()
这种情况下就有问题了, 因为os
模块内也有个open
函数, 而其返回的是一个整形, 并不是一个文件描述对象
这里可以看出内置的的open
定义已经被os
内的open
覆盖了
你永远无法确定一个模块内定义了什么名称的对象, 所以用你需要的from module1 import name1, name2
或者
import module1; print(module1.name1)
from module import name1, name2
这种用法虽然不推荐, 但没有像from module import *
那么强烈
为什么不推荐这种用法呢, 简单来说: 命名空间混乱
foo.py
:
a = 1
bar.py
from foo import a
print(a) # foo.a != a
foobar.py
from foo import a
a = 3
import bar
运行 foobar.py
foobar.py
中发生修改的是 foobar.a
, 并不是foo.a
,
因为 from foo import a
是将foo.py
模块命名空间内的a
引入 foobar.py
, a
就属于foobar.py
模块命名空间了, 与原有的模块命名空间就没有关系了
那该如何修改呢
foo.py
:
a = 1
bar.py
from foo import a
print(a) # foo.a == a
foobar.py
import foo
foo.a = 3
import bar
再运行foobar.py
, 可以看到, foo.a
也变了(1==>3)
except:
Python 有个能抓取所有异常的方式except:
, 但这是个很不好的习惯, 因为python中所有的错误都会以异常的方式跑出来, 如果使用except:
的方式获取异常, 可能会掩盖真实的错误信息, 给debug造成不便
如下
try:
foo = opne("file") # misspelled "open"
except:
sys.exit("could not open file!")
上面的第二行的open
函数拼写错误(写成了opne
), 但我们得到的异常输出却是could not open file!
比较好的方式是下面的方式
try:
foo = opne("file")
except IOError:
sys.exit("could not open file")
open
的拼写错误异常NameError
会被抛出,并显示调用栈, 方便调试
一般会尽量避免使用excpet
抓取异常, 但是在系统框架里可能需要抓取所有未被捕获的异常, 做一些回调处理
异常机制
python 中的发生错误时总会抛出异常, 可以通过抓取异常做响应的处理
以下是编程时的一个反例
def get_status(file):
if not os.path.exists(file):
print("file not found")
sys.exit(1)
return open(file).readline()
在第二行运行后到最后的return之间, 假如文件被删除了, 就可能抛出一个异常, 或者文件权限错误, 但文件还是存在的, 也会抛出一个异常以及相应的调用栈
这在开发环境还好, 上线后就在进程输出里就会看到比较难看的traceback调用栈
相对较好的方式如下
def get_status(file):
try:
return open(file).readline()
except EnvironmentError as err:
print("Unable to open file: {}".format(err))
sys.exit(1)
但上面的方式仅适用于单次运行脚本, 如果是以服务形式长时间运行呢, 如下形式(基于第一个版本)
try:
status = get_status(log)
except SystemExit:
status = None
但还有一个更好的方式
def get_status(file):
return open(file).readline()
我们应该认为在内部代码是可以正常运行, 尽量避免使用异常 然后在外部调用的地方由调用者进行抓取, 并进行处理
当然以上的代码最好的方式还是下面的方式
def get_status(file):
with open(file) as fp:
return fp.readline()
使用with
语法可以保证在退出with块后, 打开的文件资源总能被关闭, 即便是中间出现了异常
标准库
我们应该尽量使用python的标准库, 而不是自己再造轮子
比如
# ugh!
return dir+"/"+file
# better
return os.path.join(dir, file)
第二种目录拼接的方式, 能够根据所在系统进行正确的拼接, 比如Windows系统用\
分隔目录, 而Linux系统用/
换行
基于python使用换行符
表示一个语句的终结, 那么当我们的语句过长时怎么办呢
一般用\
的方式
if foo.bar()['first'][0] == baz.quux(1, 2)[5:9] and \
calculate_number(10, 20) != forbulate(500, 360):
pass
但这种方式只要\
后有空格就会报错, 而空格在编辑器中不容易被发下
最好的方式是
value = (foo.bar()['first'][0]*baz.quux(1, 2)[5:9]
+ calculate_number(10, 20)*forbulate(500, 360))
连\
都省了, 这是利用了括号内的隐式连续性,