python调用java代码代码调错

扫一扫,访问微社区
只需一步,快速开始
请完成以下验证码
将RhinoPython代码修改为GHpython代码的简易教学
本帖最后由 Jorin 于
00:16 编辑
以该同学的的代码为例
第一步,把RhinoPython的交互函数去掉
此例中直接把第20行(让用户选取曲线的语句)删除。修改完以后的main函数如下:
[mw_shl_code=python,true]def main():
& & global t
& & while t &= 1:
& && &&&dividecurve(curve_id,t)
& && &&&t += 0.002[/mw_shl_code]
那么curve_id这个参数从哪里来呢?
第二步,修改GHpython元件的输入参数
默认情况下,GHpython元件的两个输入参数是x和y,输出参数是a
1.jpg (6.48 KB, 下载次数: 11)
15:58 上传
我们需要的是curve_id,所以删除一个参数,修改剩下一个参数的名称为curve_id,并从外部为curve_id输入一条曲线
修改后的应该是这样:
2.png (22.37 KB, 下载次数: 11)
16:10 上传
第三步,查错,并删除不能在GH中使用的函数
此例中删除第17行line = rs.ObjectColor(line,getcolor(parameter))为直线设置颜色的函数。
GH用自身的颜色显示方式覆盖了Rhino场景中的颜色显示方式,这个函数不能直接使用,之后可以通过GH显示颜色的原件去做。为了方便讲解修改代码的要点,我们直接删除此行和getcolor函数。
第四步,添加输出参数
不论GHpython中添加了多少物件,但只要不在原件的输出端做输出,都不会显示出来。
不同的代码,输出参数的设置方法不同,但只要记住上面这点,就很好设置了。
此例代码中产生了很多直线,我们要输出这些直线,就需要添加一个列表,来记录这些直线。
我们在main()函数中添加一个列表line,while循环每循环一次,line列表中就增加一条直线。
但是dividecurve函数并没有返回值,所以还需要把dividecurve函数中的line返回。
但此时main函数中的line列表同样是局部变量,不能直接用于输出,所以我们返回main函数中的line列表。
在执行main函数后,输出main函数的返回值,所以我们让输出参数a=main()
至此,整个代码修改过程完毕:[mw_shl_code=python,true]import rhinoscriptsyntax as rs
def dividecurve(curve_id,parameter):
& & domain = rs.CurveDomain(curve_id)
& & t_curve = domain[0] + (domain[1] - domain[0])*parameter
& & point = rs.EvaluateCurve(curve_id,t_curve)
& & if point:
& && &&&line = rs.AddLine(point,[0,0,0])
& && &&&return line
def main():
& & line=[]
& & global t
& & while t &= 1:
& && &&&line.append(dividecurve(curve_id,t))
& && &&&t += 0.002
& & return line
a=main()[/mw_shl_code]
最终效果如图:
4.jpg (286.14 KB, 下载次数: 14)
16:58 上传
为了讲解方法,我们修改中间牺牲了颜色变化的特性,现在大家了解方法以后,可以做一个练习,把颜色也输出出来,做成如下结果:
5.png (159.2 KB, 下载次数: 10)
18:11 上传
严重不懂,
本帖最后由 筑梦NARUTO 于
14:33 编辑
写了两种方法交个作业。就不发源码了。给别人思考空间
(299.44 KB, 下载次数: 3)
13:45 上传
(636.47 KB, 下载次数: 2)
14:33 上传
新手想请教一下,怎么写才能直接让颜色与Shader相连不发生错误或者怎么写直接生成gh接受的材质,怎么让IronPython.Runtime.List的原始的列表显示出来
(386.02 KB, 下载次数: 1)
20:33 上传
(101.81 KB, 下载次数: 1)
20:33 上传
(372.36 KB, 下载次数: 0)
20:33 上传
(333.99 KB, 下载次数: 0)
20:32 上传
新手想请教一下,怎么写才能直接让颜色与Shader相连不发生错误或者怎么写直接生成gh接受的材质,怎么让Iron ...
已经解决,python错误处理详解_python
作者:用户
本文讲的是python错误处理详解_python,
在程序运行的过程中,如果发生了错误,可以事先约定返回一个错误代码,这样,就可以知道是否有错,以及出错的原因。在操作系统提供的调用中,返回错误码非常常见。比如打开文件的函数open(),成功时返回文件描述符(就是一个整数),出错时返回-1。
在程序运行的过程中,如果发生了错误,可以事先约定返回一个错误代码,这样,就可以知道是否有错,以及出错的原因。在操作系统提供的调用中,返回错误码非常常见。比如打开文件的函数open(),成功时返回文件描述符(就是一个整数),出错时返回-1。
用错误码来表示是否出错十分不便,因为函数本身应该返回的正常结果和错误码混在一起,造成调用者必须用大量的代码来判断是否出错:
复制代码 代码如下:
def foo():
r = some_function()
if r==(-1):
return (-1)
# do something
def bar():
if r==(-1):
print 'Error'
一旦出错,还要一级一级上报,直到某个函数可以处理该错误(比如,给用户输出一个错误信息)。
所以高级语言通常都内置了一套try...except...finally...的错误处理机制,Python也不例外。
让我们用一个例子来看看try的机制:
复制代码 代码如下:
print 'try...'
r = 10 / 0
print 'result:', r
except ZeroDivisionError, e:
print 'except:', e
print 'finally...'
print 'END'
当我们认为某些代码可能会出错时,就可以用try来运行这段代码,如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即except语句块,执行完except后,如果有finally语句块,则执行finally语句块,至此,执行完毕。
上面的代码在10 / 0时会产生一个除法运算错误:
复制代码 代码如下:
except: integer division or modulo by zero
finally...
从输出可以看到,当错误发生时,后续语句print 'result:', r不会被执行,except由于捕获到ZeroDivisionError,因此被执行。最后,finally语句被执行。然后,程序继续按照流程往下走。
如果把除数0改成2,则执行结果如下:
复制代码 代码如下:
finally...
由于没有错误发生,所以except语句块不会被执行,但是finally如果有,则一定会被执行(可以没有finally语句)。
你还可以猜测,错误应该有很多种类,如果发生了不同类型的错误,应该由不同的except语句块处理。没错,可以有多个except来捕获不同类型的错误:
复制代码 代码如下:
print 'try...'
r = 10 / int('a')
print 'result:', r
except ValueError, e:
print 'ValueError:', e
except ZeroDivisionError, e:
print 'ZeroDivisionError:', e
print 'finally...'
print 'END'
int()函数可能会抛出ValueError,所以我们用一个except捕获ValueError,用另一个except捕获ZeroDivisionError。
此外,如果没有错误发生,可以在except语句块后面加一个else,当没有错误发生时,会自动执行else语句:
复制代码 代码如下:
print 'try...'
r = 10 / int('a')
print 'result:', r
except ValueError, e:
print 'ValueError:', e
except ZeroDivisionError, e:
print 'ZeroDivisionError:', e
print 'no error!'
print 'finally...'
print 'END'
Python的错误其实也是class,所有的错误类型都继承自BaseException,所以在使用except时需要注意的是,它不但捕获该类型的错误,还把其子类也“一网打尽”。比如:
复制代码 代码如下:
except StandardError, e:
print 'StandardError'
except ValueError, e:
print 'ValueError'
第二个except永远也捕获不到ValueError,因为ValueError是StandardError的子类,如果有,也被第一个except给捕获了。
Python所有的错误都是从BaseException类派生的,常见的错误类型和继承关系看这里:
https://docs.python.org/2/library/exceptions.html
使用try...except捕获错误还有一个巨大的好处,就是可以跨越多层调用,比如函数main()调用foo(),foo()调用bar(),结果bar()出错了,这时,只要main()捕获到了,就可以处理:
复制代码 代码如下:
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main():
except StandardError, e:
print 'Error!'
print 'finally...'
也就是说,不需要在每个可能出错的地方去捕获错误,只要在合适的层次去捕获错误就可以了。这样一来,就大大减少了写try...except...finally的麻烦。
如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出。来看看err.py:
复制代码 代码如下:
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main():
执行,结果如下:
复制代码 代码如下:
$ python err.py
Traceback (most recent call last):
File "err.py", line 11, in &module&
File "err.py", line 9, in main
File "err.py", line 6, in bar
return foo(s) * 2
File "err.py", line 3, in foo
return 10 / int(s)
ZeroDivisionError: integer division or modulo by zero
出错并不可怕,可怕的是不知道哪里出错了。解读错误信息是定位错误的关键。我们从上往下可以看到整个错误的调用函数链:
错误信息第1行:
复制代码 代码如下:
Traceback (most recent call last):
告诉我们这是错误的跟踪信息。
复制代码 代码如下:
File "err.py", line 11, in &module&
调用main()出错了,在代码文件err.py的第11行代码,但原因是第9行:
复制代码 代码如下:
File "err.py", line 9, in main
调用bar('0')出错了,在代码文件err.py的第9行代码,但原因是第6行:
复制代码 代码如下:
File "err.py", line 6, in bar
return foo(s) * 2
原因是return foo(s) * 2这个语句出错了,但这还不是最终原因,继续往下看:
复制代码 代码如下:
File "err.py", line 3, in foo
return 10 / int(s)
原因是return 10 / int(s)这个语句出错了,这是错误产生的源头,因为下面打印了:
复制代码 代码如下:
ZeroDivisionError: integer division or modulo by zero
根据错误类型ZeroDivisionError,我们判断,int(s)本身并没有出错,但是int(s)返回0,在计算10 / 0时出错,至此,找到错误源头。
如果不捕获错误,自然可以让Python解释器来打印出错误堆栈,但程序也被结束了。既然我们能捕获错误,就可以把错误堆栈打印出来,然后分析错误原因,同时,让程序继续执行下去。
Python内置的logging模块可以非常容易地记录错误信息:
复制代码 代码如下:
import logging
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main():
except StandardError, e:
logging.exception(e)
print 'END'
同样是出错,但程序打印完错误信息后会继续执行,并正常退出:
复制代码 代码如下:
$ python err.py
ERROR:root:integer division or modulo by zero
Traceback (most recent call last):
File "err.py", line 12, in main
File "err.py", line 8, in bar
return foo(s) * 2
File "err.py", line 5, in foo
return 10 / int(s)
ZeroDivisionError: integer division or modulo by zero
通过配置,logging还可以把错误记录到日志文件里,方便事后排查。
因为错误是class,捕获一个错误就是捕获到该class的一个实例。因此,错误并不是凭空产生的,而是有意创建并抛出的。Python的内置函数会抛出很多类型的错误,我们自己编写的函数也可以抛出错误。
如果要抛出错误,首先根据需要,可以定义一个错误的class,选择好继承关系,然后,用raise语句抛出一个错误的实例:
复制代码 代码如下:
class FooError(StandardError):
def foo(s):
n = int(s)
raise FooError('invalid value: %s' % s)
return 10 / n
执行,可以最后跟踪到我们自己定义的错误:
复制代码 代码如下:
$ python err.py
Traceback (most recent call last):
__main__.FooError: invalid value: 0
只有在必要的时候才定义我们自己的错误类型。如果可以选择Python已有的内置的错误类型(比如ValueError,TypeError),尽量使用Python内置的错误类型。
最后,我们来看另一种错误处理的方式:
复制代码 代码如下:
def foo(s):
n = int(s)
return 10 / n
def bar(s):
return foo(s) * 2
except StandardError, e:
print 'Error!'
def main():
在bar()函数中,我们明明已经捕获了错误,但是,打印一个Error!后,又把错误通过raise语句抛出去了,这不有病么?
其实这种错误处理方式不但没病,而且相当常见。捕获错误目的只是记录一下,便于后续追踪。但是,由于当前函数不知道应该怎么处理该错误,所以,最恰当的方式是继续往上抛,让顶层调用者去处理。
raise语句如果不带参数,就会把当前错误原样抛出。此外,在except中raise一个Error,还可以把一种类型的错误转化成另一种类型:
复制代码 代码如下:
except ZeroDivisionError:
raise ValueError('input error!')
只要是合理的转换逻辑就可以,但是,决不应该把一个IOError转换成毫不相干的ValueError。
Python内置的try...except...finally用来处理错误十分方便。出错时,会分析错误信息并定位错误发生的代码位置才是最关键的。
程序也可以主动抛出错误,让调用者来处理相应的错误。但是,应该在中写清楚可能会抛出哪些错误,以及错误产生的原因。
以上是云栖社区小编为您精心准备的的内容,在云栖社区的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索python
python 文本处理详解、python 错误处理、python3 错误处理、python装饰器详解、python self 详解,以便于您获取更多的相关知识。
稳定可靠、可弹性伸缩的在线数据库服务,全球最受欢迎的开源数据库之一
6款热门基础云产品6个月免费体验;2款产品1年体验;1款产品2年体验
弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率
开发者常用软件,超百款实用软件一站式提供
云栖社区()为您免费提供相关信息,包括
,所有相关内容均不代表云栖社区的意见!当前位置:&>&&>&
编写Python程序时10个常见的错误
发布时间:
来源:服务器之家
本文由 伯乐在线 - datorhjaelten 翻译自 toptal。欢迎加入技术翻译小组。转载请参见文章末尾处的要求。
关于Python
Python是一门解释性的,面向对象的,并具有动态语义的高级编程语言。它高级的内置数据结构,结合其动态类型和动态绑定的特性,使得它在快速应用程序开发(Rapid
Application
Development)中颇为受欢迎,同时Python还能作为脚本语言或者胶水语言讲现成的组件或者服务结合起来。Python支持模块(modules)和包(packages),所以也鼓励程序的模块化以及代码重用。
Python简单、易学的语法可能会误导一些Python程序员(特别是那些刚接触这门语言的人们),可能会忽略某些细微之处和这门语言的强大之处。
考虑到这点,本文列出了“十大”甚至是高级的Python程序员都可能犯的,却又不容易发现的细微错误。(注意:本文是针对比《Python程序员常见错误》稍微高级一点读者,对于更加新手一点的Python程序员,有兴趣可以读一读那篇文章)
常见错误1:在函数参数中乱用表达式作为默认值
Python允许给一个函数的某个参数设置默认值以使该参数成为一个可选参数。尽管这是这门语言很棒的一个功能,但是这当这个默认值是可变对象(mutable)时,那就有些麻烦了。例如,看下面这个Python函数定义:
&&&&def&foo(bar=[]):&&&&&&&&#&bar是可选参数,如果没有指明的话,默认值是[]
...&&&&bar.append("baz")&&&&#&但是这行可是有问题的,走着瞧…
...&&&&return&bar
人们常犯的一个错误是认为每次调用这个函数时不给这个可选参数赋值的话,它总是会被赋予这个默认表达式的值。例如,在上面的代码中,程序员可能会认为重复调用函数foo()
(不传参数bar给这个函数),这个函数会总是返回‘baz’,因为我们假定认为每次调用foo()的时候(不传bar),参数bar会被置为[](即,一个空的列表)。
那么我们来看看这么做的时候究竟会发生什么:
["baz",&"baz"]
["baz",&"baz",&"baz"]
嗯?为什么每次调用foo()的时候,这个函数总是在一个已经存在的列表后面添加我们的默认值“baz”,而不是每次都创建一个新的列表?
答案是一个函数参数的默认值,仅仅在该函数定义的时候,被赋值一次。如此,只有当函数foo()第一次被定义的时候,才讲参数bar的默认值初始化到它的默认值(即一个空的列表)。当调用foo()的时候(不给参数bar),会继续使用bar最早初始化时的那个列表。
由此,可以有如下的解决办法:
&&&&def&foo(bar=None):
...&&&&if&bar&is&None:&&&&&&&&&&#&或者用&if&not&bar:
...&&&&&&&&bar&=&[]
...&&&&bar.append("baz")
...&&&&return&bar
常见错误2:不正确的使用类变量
看下面一个例子:
&&&&class&A(object):
...&&&&&x&=&1
&&&&class&B(A):
...&&&&&pass
&&&&class&C(A):
...&&&&&pass
&&&&print&A.x,&B.x,&C.x
看起来没有问题。
&&&&B.x&=&2
&&&&print&A.x,&B.x,&C.x
嗯哈,还是和预想的一样。
&&&&A.x&=&3
&&&&print&A.x,&B.x,&C.x
我了个去。只是改变了A.x,为啥C.x也变了?
在Python里,类变量通常在内部被当做字典来处理并遵循通常所说的方法解析顺序(Method Resolution
(MRO))。因此在上面的代码中,因为属性x在类C中找不到,因此它会往上去它的基类中查找(在上面的例子中只有A这个类,当然Python是支持多重继承(multiple
inheritance)的)。换句话说,C没有它自己独立于A的属性x。因此对C.x的引用实际上是对A.x的引用。(B.x不是对A.x的引用是因为在第二步里B.x=2将B.x引用到了2这个对象上,倘若没有如此,B.x仍然是引用到A.x上的。――译者注)
常见错误3:在异常处理时错误的使用参数
假设你有如下的代码:
...&&&&&l&=&["a",&"b"]
...&&&&&int(l[2])
...&except&ValueError,&IndexError:&&#&想捕捉两个异常
...&&&&&pass
Traceback&(most&recent&call&last):
&&File&"&stdin&",&line&3,&in&&module&
IndexError:&list&index&out&of&range
这里的问题在于except语句不会像这样去接受一系列的异常。并且,在Python 2.x里面,语法except
Exception,
e是用来将异常和这个可选的参数绑定起来(即这里的e),以用来在后面查看的。因此,在上面的代码中,IndexError异常不会被except语句捕捉到;而最终ValueError这个异常被绑定在了一个叫做IndexError的参数上。
在except语句中捕捉多个异常的正确做法是将所有想要捕捉的异常放在一个元组(tuple)里并作为第一个参数给except语句。并且,为移植性考虑,使用as关键字,因为Python
2和Python 3都支持这样的语法,例如:
...&&&&&l&=&["a",&"b"]
...&&&&&int(l[2])
...&except&(ValueError,&IndexError)&as&e:
...&&&&&pass
常见错误4:误解Python作用域的规则
Python的作用域解析是基于叫做LEGB(Local(本地),Enclosing(封闭),Global(全局),Built-in(内置))的规则进行操作的。这看起来很直观,对吧?事实上,在Python中这有一些细微的地方很容易出错。看这个例子:
&&&&x&=&10
&&&&def&foo():
...&&&&&x&+=&1
...&&&&&print&x
Traceback&(most&recent&call&last):
&&File&"&stdin&",&line&1,&in&&module&
&&File&"&stdin&",&line&2,&in&foo
UnboundLocalError:&local&variable&'x'&referenced&before&assignment
这是怎么回事?
这是因为,在一个作用域里面给一个变量赋值的时候,Python自动认为这个变量是这个作用域的本地变量,并屏蔽作用域外的同名的变量。
很多时候可能在一个函数里添加一个赋值的语句会让你从前本来工作的代码得到一个UnboundLocalError。(感兴趣的话可以读一读这篇文章。)
在使用列表(lists)的时候,这种情况尤为突出。看下面这个例子:
&&&&lst&=&[1,&2,&3]
&&&&def&foo1():
...&&&&&lst.append(5)&&&#&这没有问题...
&&&&foo1()
[1,&2,&3,&5]
&&&&lst&=&[1,&2,&3]
&&&&def&foo2():
...&&&&&lst&+=&[5]&&&&&&#&...&这就有问题了!
&&&&foo2()
Traceback&(most&recent&call&last):
&&File&"&stdin&",&line&1,&in&&module&
&&File&"&stdin&",&line&2,&in&foo
UnboundLocalError:&local&variable&'lst'&referenced&before&assignment
嗯?为什么foo2有问题,而foo1没有问题?
答案和上一个例子一样,但是更加不易察觉。foo1并没有给lst赋值,但是foo2尝试给lst赋值。注意lst+=[5]只是lst=lst+[5]的简写,由此可以看到我们尝试给lst赋值(因此Python假设作用域为本地)。但是,这个要赋给lst的值是基于lst本身的(这里的作用域仍然是本地),而lst却没有被定义,这就出错了。
常见错误5:在遍历列表的同时又在修改这个列表
下面这个例子中的代码应该比较明显了:
&&&&odd&=&lambda&x&:&bool(x&%&2)
&&&&numbers&=&[n&for&n&in&range(10)]
&&&&for&i&in&range(len(numbers)):
...&&&&&if&odd(numbers[i]):
...&&&&&&&&&del&numbers[i]&&#&这不对的:在遍历列表时删掉列表的元素。
Traceback&(most&recent&call&last):
&&&&&&&&&&File&"&stdin&",&line&2,&in&&module&
IndexError:&list&index&out&of&range
遍历一个列表或者数组的同时又删除里面的元素,对任何有经验的软件开发人员来说这是个很明显的错误。但是像上面的例子那样明显的错误,即使有经验的程序员也可能不经意间在更加复杂的程序中不小心犯错。
所幸,Python集成了一些优雅的编程范式,如果使用得当,可以写出相当简化和精简的代码。一个附加的好处是更简单的代码更不容易遇到这种“不小心在遍历列表时删掉列表元素”的bug。例如列表推导式(list
comprehensions)就提供了这样的范式。再者,列表推导式在避免这样的问题上特别有用,接下来这个对上面的代码的重新实现就相当完美:
&&&&odd&=&lambda&x&:&bool(x&%&2)
&&&&numbers&=&[n&for&n&in&range(10)]
&&&&numbers[:]&=&[n&for&n&in&numbers&if&not&odd(n)]&&#&啊,这多优美
&&&&numbers
[0,&2,&4,&6,&8]
常见错误6:搞不清楚在闭包(closures)中Python是怎样绑定变量的
看这个例子:
&&&&def&create_multipliers():
...&&&&&return&[lambda&x&:&i&*&x&for&i&in&range(5)]
&&&&for&multiplier&in&create_multipliers():
...&&&&&print&multiplier(2)
期望得到下面的输出:
但是实际上得到的是:
这是由于Python的后期绑定(late
binding)机制导致的,这是指在闭包中使用的变量的值,是在内层函数被调用的时候查找的。因此在上面的代码中,当任一返回函数被调用的时候,i的值是在它被调用时的周围作用域中查找(到那时,循环已经结束了,所以i已经被赋予了它最终的值4)。
解决的办法比较巧妙:
&&& def create_multipliers(): ... return [lambda x, i=i :
i * x for i in range(5)] ... &&& for multiplier in
create_multipliers(): ... print multiplier(2) ...
这下对了!这里利用了默认参数去产生匿名函数以达到期望的效果。有人会说这很优美,有人会说这很微妙,也有人会觉得反感。但是如果你是一名Python程序员,重要的是能理解任何的情况。
常见错误7:循环加载模块
假设你有两个文件,a.py和b.py,在这两个文件中互相加载对方,例如:
在a.py中:
&&&&return&b.x
在b.py中:
&&&&print&a.f()
首先,我们试着加载a.py:
&&&&import&a
没有问题。也许让人吃惊,毕竟有个感觉应该是问题的循环加载在这儿。
事实上在Python中仅仅是表面上的出现循环加载并不是什么问题。如果一个模块以及被加载了,Python不会傻到再去重新加载一遍。但是,当每个模块都想要互相访问定义在对方里的函数或者变量时,问题就来了。
让我们再回到之前的例子,当我们加载a.py时,它再加载b.py不会有问题,因为在加载b.py时,它并不需要访问a.py的任何东西,而在b.py中唯一的引用就是调用a.f()。但是这个调用是在函数g()中完成的,并且a.py或者b.py中没有人调用g(),所以这会儿心情还是美丽的。
但是当我们试图加载b.py时(之前没有加载a.py),会发生什么呢:
&&&&import&b
Traceback&(most&recent&call&last):
&&&&&&&&&&File&"&stdin&",&line&1,&in&&module&
&&&&&&&&&&File&"b.py",&line&1,&in&&module&
&&&&import&a
&&&&&&&&&&File&"a.py",&line&6,&in&&module&
&&&&&&&&print&f()
&&&&&&&&&&File&"a.py",&line&4,&in&f
&&&&&&&&return&b.x
AttributeError:&'module'&object&has&no&attribute&'x'
恭喜你,出错了。这里问题出在加载b.py的过程中,Python试图加载a.py,并且在a.py中需要调用到f(),而函数f()又要访问到b.x,但是这个时候b.x却还没有被定义。这就产生了AttributeError异常。
解决的方案可以做一点细微的改动。改一下b.py,使得它在g()里面加载a.py:
&&&&import&a&&&&#&只有当g()被调用的时候才加载
&&&&print&a.f()
这会儿当我们加载b.py的时候,一切安好:
&&&&import&b
1&&&&&&&#&第一次输出,因为模块a在最后调用了‘print&f()’
1&&&&&&&#&第二次输出,这是我们调用g()
常见错误8:与Python标准库模块命名冲突
Python的一个优秀的地方在于它提供了丰富的库模块。但是这样的结果是,如果你不下意识的避免,很容易你会遇到你自己的模块的名字与某个随Python附带的标准库的名字冲突的情况(比如,你的代码中可能有一个叫做email.py的模块,它就会与标准库中同名的模块冲突)。
这会导致一些很粗糙的问题,例如当你想加载某个库,这个库需要加载Python标准库里的某个模块,结果呢,因为你有一个与标准库里的模块同名的模块,这个包错误的将你的模块加载了进去,而不是加载Python标准库里的那个模块。这样一来就会有麻烦了。
所以在给模块起名字的时候要小心了,得避免与Python标准库中的模块重名。相比起你提交一个“Python改进建议(Python
Enhancement Proposal
(PEP))”去向上要求改一个标准库里包的名字,并得到批准来说,你把自己的那个模块重新改个名字要简单得多。
常见错误9:不能区分Python 2和Python 3
看下面这个文件foo.py:
import&sys
def&bar(i):
&&&&if&i&==&1:
&&&&&&&&raise&KeyError(1)
&&&&if&i&==&2:
&&&&&&&&raise&ValueError(2)
def&bad():
&&&&e&=&None
&&&&&&&&bar(int(sys.argv[1]))
&&&&except&KeyError&as&e:
&&&&&&&&print('key&error')
&&&&except&ValueError&as&e:
&&&&&&&&print('value&error')
&&&&print(e)
在Python 2里,运行起来没有问题:
$&python&foo.py&1
$&python&foo.py&2
value&error
但是如果拿到Python 3上面玩玩:
$&python3&foo.py&1
Traceback&(most&recent&call&last):
&&File&"foo.py",&line&19,&in&&module&
&&File&"foo.py",&line&17,&in&bad
&&&&print(e)
UnboundLocalError:&local&variable&'e'&referenced&before&assignment
这是怎么回事?“问题”在于,在Python 3里,在except块的作用域以外,异常对象(exception
object)是不能被访问的。(原因在于,如果不这样的话,Python会在内存的堆栈里保持一个引用链直到Python的垃圾处理将这些引用从内存中清除掉。更多的技术细节可以参考这里。)
避免这样的问题可以这样做:保持在execpt块作用域以外对异常对象的引用,这样是可以访问的。下面是用这个办法对之前的例子做的改动,这样在Python
2和Python 3里面都运行都没有问题。
import&sys
def&bar(i):
&&&&if&i&==&1:
&&&&&&&&raise&KeyError(1)
&&&&if&i&==&2:
&&&&&&&&raise&ValueError(2)
def&good():
&&&&exception&=&None
&&&&&&&&bar(int(sys.argv[1]))
&&&&except&KeyError&as&e:
&&&&&&&&exception&=&e
&&&&&&&&print('key&error')
&&&&except&ValueError&as&e:
&&&&&&&&exception&=&e
&&&&&&&&print('value&error')
&&&&print(exception)
在Py3k里面运行:
$&python3&foo.py&1
$&python3&foo.py&2
value&error
(顺带提一下,我们的“Python招聘指南”里讨论了从Python 2移植代码到Python
3时需要注意的其他重要的不同之处。)
常见错误10:错误的使用__del__方法
假设有一个文件mod.py中这样使用:
import&foo
class&Bar(object):
&&&&&&&&&&&&...
&&&&def&__del__(self):
&&&&&&&&foo.cleanup(self.myhandle)
然后试图在another_mod.py里这样:
import&mod
mybar&=&mod.Bar()
那么你会得到一个恶心的AttributeError异常。
为啥呢?这是因为(参考这里),当解释器关闭时,模块所有的全局变量会被置为空(None)。结果便如上例所示,当__del__被调用时,名字foo已经被置为空了。
使用atexit.register()可以解决这个问题。如此,当你的程序结束的时候(退出的时候),你的注册的处理程序会在解释器关闭之前处理。
这样理解的话,对上面的mod.py可以做如下的修改:
import&foo
import&atexit
def&cleanup(handle):
&&&&foo.cleanup(handle)
class&Bar(object):
&&&&def&__init__(self):
&&&&&&&&...
&&&&&&&&atexit.register(cleanup,&self.myhandle)
这样的实现方式为在程序正常终止时调用清除功能提供了一种干净可靠的办法。显然,需要foo.cleanup决定怎么处理绑定在self.myhandle上的对象,但你知道怎么做的。
是一门非常强大且灵活的语言,它众多的机制和范式能显著的提高生产效率。不过,和任何一款软件或者语言一样,对它的理解或认识不足的话,常常是弊大于利的,并会处于一种“一知半解”的状态。
多熟悉Python的一些关键的细微的地方,比如(但不局限于)本文中提到的这些问题,可以帮你更好的使用这门语言的同时帮你避免一些常见的陷阱。
SQL Error: select * from ***_***_news where id in ()
Copyright © . 版权所有}

我要回帖

更多关于 python代码调试方法 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信