zoukankan      html  css  js  c++  java
  • 编写高质量代码--改善python程序的建议(四)

    原文发表在我的博客主页,转载请注明出处!


    建议十八:有节制的使用from...import语句
    python提供了三种方式引入外部模块:

    • import语句
    • from...import...
    • __import__函数

    使用的时候需要注意以下几点:

    • 一般情况下尽量优先使用import a形式,如访问B时需要使用a.B的形式
    • 有节制地使用from a import B形式,可以直接访问B
    • 尽量避免使用from a import *,因为这会污染命名空间,并且无法清晰地表示导入了哪些对象

    首先简单的了解下python的import机制。python在初始化运行环境的时候会预先加载一批内建模块到内存中,这些模块相关的信息被存放在sys.modules中,当加载一个模块的时候,解释器世嘉尚要完成以下动作:

    • 在sys.modules中进行搜索看看该模块是否已经存在,如果存在,则将其导入到当前局部命名空间,加载结束
    • 如果在sys.modules中找不到对应模块的名称,则为需要导入的模块创建一个字典对象,并将该对象信息插入sys.modules中
    • 加载前确认是否需要对模块对应的文件进行编译,如果需要则先进行编译
    • 执行动态加载,在当前模块的命名空间中执行编译后的字节码,并将其中所有的对象放入模块对应的字典中。

    如果无节制的使用from a import ...会带来以下问题:

    • 命名空间冲突
      一般来说在非常明确不会造成明明冲突的前提下,以下几种情况下可以考虑使用from...import语句
    • 当只需要导入部分属性或方法时
    • 模块中的这些属性和方法访问频率较高导致使用“模块名.名称”的形式进行访问过于繁琐时
    • 模块的文档明确说明需要使用from..import形式,导入的是一个包下面的子模块,且能够更为简单和便利时
    • 循环嵌套导入的问题
    c1.py:
    from c2 import g
    def x():
    	pass 
    c2.py:
    from c1 import x
    def g():
    	pass
    

    有时间可以试试上面的导入,会抛出ImportError异常,但是直接使用import就可以。


    建议十九:优先使用absolute import来导入模块
    相对导入:在不指明package名的情况相爱导入自己这个package的模块
    绝对导入:指明顶层package名,python会在sys.path中寻找所有的顶层模块
    加入有如下文件结构,其中app/sub1/string.py中定义了一个lower()方法。

    app/
      __init__.py
      sub1/
    	__init__.py
    	mod1.py
    	string.py
      sub2/
    	__init__.py
    	mod2.py
    

    经验告诉我们,挡在mod1.py中import string之后,调用string.lower()方法时,会覆盖掉python自带的string模块中的方法。所以如果要使用python的String模块中的方法呢?
    python2.5后为absolute import提供了一种新的机制,在模块中使用from _future_ import absolute_import语句进行说明后再进行导入,会禁用implicit relative,但是并不会禁掉explicit relative import。同时类似于linux,它还通过点号提供了一种显式进行relative import的方法,“.”表示当前目录,“..”表示当前目录的上一层目录。
    相比于absolute import,relative import的问题比较多,因此推荐优先使用absolute import。


    建议二十:i+=1 不等于 ++i
    python的解释器会将++i操作解释为+(+i),其中+号表示证书符号,--i也类似。


    建议二十一:使用with自动关闭资源
    with语句的语法为:

    with exp1 [as target]:
    	code... 
    
    #嵌套
    with expr1 as e1:
    	with expr2 as e2
    等价于
    with expr1 as e1, expr2 as e2
    

    with语句可以在代码块执行完毕后进入该代码块时的现场,执行过程如下:

    • 计算表达式的值,返回一个上下文管理器对象
    • 加载上下文管理器对象的__exit__()方法以备后用
    • 调用上下文管理器对象的__enter__()方法
    • 如果with语句中设置了目标对象,则将__enter__()方法的返回值复制给目标对象
    • 执行with中的代码块
    • 如果步骤5中代码正常结束,调用上下文管理器对象的__exit__()方法,其返回值忽略
    • 如果步骤5中代码执行过程中发生异常,调用上下文管理器对象的__exit__()方法,并将异常类型、值及traceback信息作为参数传递给__exit__()方法,如果__exit__()返回值为false,则异常值会被重新抛出;否则挂起异常,程序继续执行。

    上下文管理器:用来创建一个运行时的环境,是一个对象,定义程序运行时需要建立的上下文,处理程序的进入和退出,实现了上下文管理协议,即在对象中定义了__enter__()和__exit__()方法:

    • enter():进入运行时的上下文,返回运行时上下文相关的对象
    • exit(exception_type, exception_value, traceback):退出运行时的上下文,定义在块执行(或终止)之后上下文管理器应该做什么。

    建议二十二:使用else子句简化循环(异常处理)
    在python中,不仅分支语句有else子句,循环语句和异常处理也有。
    首先看循环语句中的else,语法为:

    #while循环
    "while" expre ":" suite
    ["else" ":" suite]
    #for循环
    "for" target_list "in" expre_list ":" suite
    ["else" ":" suite]
    

    具体不再赘述,下面两端代码具有同样的功能,可以进行比较。

    def print_prime(n):
    	for i in xrange(2, n):
    		found = True
    		for j in xrange(2, i):
    			if i % j == 0:
    				found = False
    				break
    		if found:
    			print i
    
    def print_prime2(n):
    	for i in xrange(2, n):
    		for j in xrange(2, i):
    			if i % j == 0:
    				break
    		else:
    			print i
    

    和循环语句中的else相似,异常处理也提供了else子句语法,直接看例子

    def save(db, obj):
    	try:
    		db.execute('a sql stmt', obj.attr1)
    		db.execute('another sql stmt', obj.attr2)
    	except DBError:
    		db.rollback()
    	esle:
    		db.commit()
    
    def save(db, obj):
    	some_error_occured = False
    	try:
    		db.execute('a sql stmt', obj.attr1)
    		db.execute('another sql stmt', obj.attr2)
    	except DBError:
    		db.rollback()
    		some_error_occurred = True
    	if not some_error_occured:
    		db.commit()
    

    总结:本篇列举了python的一些基础语法使用建议和注意事项,慢慢消化

    参考:编写高质量代码--改善python程序的91个建议

  • 相关阅读:
    java使用google开源工具实现图片压缩
    MyBatis实现Mysql数据库分库分表操作和总结
    简单记录你博客园的访问人数
    细说spring事务配置属性
    hazelcast初探
    jstorm之于storm
    如何让其他机器访问你的oracle数据库
    问题解决:bash: fork: retry: Resource temporarily unavailable
    分布式锁的几种实现方式
    建立索引的原则总结
  • 原文地址:https://www.cnblogs.com/cotyb/p/5104034.html
Copyright © 2011-2022 走看看