首页 > 编程知识 正文

奇怪的python行为,python容易犯的错误

时间:2023-12-27 22:27:32 阅读:326260 作者:RFUP

本文目录一览:

Python 很奇怪的问题,为什么会这样输出

你重写了__del__方法,还给它加了一个name参数,__del__是系统自行调用,默认只传一个对象,也就是self,自然就会报错

可以用 Python 编程语言做哪些神奇好玩的事情

机器学习,比如手写字识别,人脸识别,垃圾邮件处理等。 当然还可以画图,和matlab类似,不过是工业级的。

也许最初设计 Python 这种语言的人并没有想到今天Python 会在工业和科研上获得如此广泛的使用。著名的自由软件作者Eric Raymond 在他的文章《如何成为一名黑客》中,将Python 列为黑客应当学习的四种编程语言之一,并建议人们从Python 开始学习编程。这的确是一个中肯的建议,对于那些从来没有学习过编程或者并非计算机专业的编程学习者而言,Python 是最好的选择之一。Python 第一次学习Python,我只用了不到二十分钟的时间,站在书店里把一本教初学编程的人学习Python 的书翻了一遍。也是从那时起,我开始被这种神奇的语言吸引。 Python 可以用来开发symbian 上的东西。 易用与速度的完美结合Python 是一种用起来很方便的语言,很多初学Java 的人都会被 Java 的CLASSPATH 搞得晕头转向,花上半天的时间才搞明白原来是CLASSPATH 搞错了自己的 Hello World 才没法运行。用Python 就不会有这种问题,只要装上就能直接用。 Python 是一种脚本语言,写好了就可以直接运行,省去了编译链接的麻烦,对于需要多动手实践的初学者而言,也就是少了出错的机会。而且Python 还有一种交互的方式,如果是一段简单的小程序,连编辑器都可以省了,直接敲进去就能运行。Python 是一种清晰的语言,用缩进来表示程序的嵌套关系可谓是一种创举,把过去软性的编程风格升级为硬性的语法规定。再不需要在不同的风格间选择、再不需要为不同的风格争执。与 Perl 不同,Python 中没有各种隐晦的缩写,不需要去强记各种奇怪的符号的含义。Python 写的程序很容易懂,这是不少人的共识。Python 是一种面向对象的语言,但它的面向对象却不象C++那样强调概念,而是更注重实用。不是为了体现对概念的完整支持而把语言搞得很复杂,而是用最简单的方法让编程者能够享受到面向对象带来的好处,这正是 Python 能像 Java、C#那样吸引众多支持者的原因之一。 Python 是一种功能丰富的语言,它拥有一个强大的基本类库和数量众多的第三方扩展,使得Python 程序员无需去羡慕Java 的JDK。Python 为程序员提供了丰富的基本功能使得人们写程序时用不着一切最底层做起。说到这里,人们通常会用一种担心:脚本语言通常很慢。脚本语言从运行的速度讲的确会慢一些,但 Python 的速度却比人们想象得快很多。虽然 Python 是一种脚本语言,但实际上也可以对它进行编译,就象编译Java 程序一样将Python 程序编译为一种特殊的ByteCode,在程序运行时,执行的是ByteCode,省去了对程序文本的分析解释,速度自然提升很多。在用Java 编程是,人们崇尚一种Pure Java 的方式,除了虚拟机一切东西都用Java 编写,无论是基本的数据结构还是图形界面,而Pure Java 的SWING,却成为无数Java 应用开发者的噩梦。Python 崇尚的是实用,它的整体环境是用C 来编写的,很多基本的功能和扩展的模块都是用 C/C++来编写的,当执行这一部分代码时,它的速度就是C 的速度。用Python 编写的普通桌面程序,其启动运行速度与用C 写的程序差别不大。除了这些,通过一些第三方软件包,用Python 编写的源代码还可以以类似JIT 的方式运行,而这可以大大提高Python 代码的运行速度,针对不同类型的代码,会有2 倍至100 倍不等的速度提升。 Python 是我见到过的语言中,在易用性和速度上结合的最完美的一个,通过丧失一点点经常可以忽略不计的运行速度从而获得更高的编程效率,这就是我选择Python 的原因。把精力放在要解决的问题上选择一种合适的语言,才能让你把有限的精力放到最需要解决的问题上。不同的语言有不同的作用,C 和汇编适合编写系统软件,如果用它们来编写企业应用,恐怕没几个人能得心应手。我以前就碰到一个用汇编写数据库程序的哥,虽然最基本的功能完成了,但要增加个报表预览什么的,他就没法应付了。聪明的程序员是用合适的工具去完成任务,想找一把万能钥匙是不太可能的。Python 的自动的垃圾回收机制是高级的编程语言的一种基本特性,用拥有这一功能的语言编程,程序员们通常不用去关心内存泄漏的问题,而当我们用 C/C++写程序时,这却是最重要的需要认真考虑却又很容易出错的问题之一。数据结构是程序构成的重要部分,链表、树、图这些在用C 编程时需要仔细表达的问题在Python 中简单了很多。在Python 中,最基本的数据结构就是数组、序列和哈希表,用它们想要表达各种常见的数据结构是非常容易的。没了定义指针、分配内存的任务,编程变得有趣了。CORBA 是一种高级的软件体系结构,它是语言无关平台无关的。C++、Java 等语言都有CORBA 绑定,但与它们相比,Python 的 CORBA 绑定却容易很多,因为在程序员看来,一个 CORBA 的类和 Python 的类用起来以及实现起来并没有什么差别。没了复杂体系结构的困扰,用 Python 编写CORBA 程序也变得容易了。好钢要用在刀刃上,要想用有限的时间完成尽量多的任务,就要把各种无关的问题抛弃,而Python 恰恰提供了这种方法。跨平台又易扩展随着Linux 的不断成熟,越来越多的人转到Linux 平台上工作,软件的开发者自然就希望自己编写的软件可以在所有平台下运行。Java 一次编写处处运行的口号使它成为跨平台的开发工具的典范,但其运行速度却不被人们看好。实际上,几乎所有的著名脚本语言都是跨平台的,Python 也不例外。

python出错,请问是什么问题

要把代码发现来才知道,以下是常见的错误

下面终于要讲到当你用到更多的Python的功能(数据类型,函数,模块,类等等)时可能碰到的问题了。由于篇幅有限,这里尽量精简,尤其是对一些高级的概念。要想了解更多的细节,敬请阅读Learning Python, 2nd Edition的“小贴士”以及“Gotchas”章节。

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

当你在Python中调用open()来访问一个外部的文件时,Python不会使用模块搜索路径来定位这个目标文件。它会使用你提供的绝对路径,或者假定这个文件是在当前工作目录中。模块搜索路径仅仅为模块加载服务的。

不同的类型对应的方法也不同

列表的方法是不能用在字符串上的,反之亦然。通常情况下,方法的调用是和数据类型有关的,但是内部函数通常在很多类型上都可以使用。举个例子来说,列表的reverse方法仅仅对列表有用,但是len函数对任何具有长度的对象都适用

不能直接改变不可变数据类型

记住你没法直接的改变一个不可变的对象(例如,元组,字符串):

T = (1, 2, 3)

T[2] = 4 # 错误

用切片,联接等构建一个新的对象,并根据需求将原来变量的值赋给它。因为Python会自动回收没有用的内存,因此这没有看起来那么浪费:

T = T[:2] + (4,) # 没问题了: T 变成了 (1, 2, 4)

使用简单的for循环而不是while或者range

当你要从左到右遍历一个有序的对象的所有元素时,用简单的for循环(例如,for x in seq:)相比于基于while-或者range-的计数循环而言会更容易写,通常运行起来也更快。除非你一定需要,尽量避免在一个for循环里使用range:让Python来替你解决标号的问题。在下面的例子中三个循环结构都没有问题,但是第一个通常来说更好;在Python里,简单至上。

S = "lumberjack"

for c in S: print c # 最简单

for i in range(len(S)): print S[i] # 太多了

i = 0 # 太多了

while i len(S): print S[i]; i += 1

不要试图从那些会改变对象的函数得到结果

诸如像方法list.append()和list.sort()一类的直接改变操作会改变一个对象,但不会将它们改变的对象返回出来(它们会返回None);正确的做法是直接调用它们而不要将结果赋值。经常会看见初学者会写诸如此类的代码:

mylist = mylist.append(X)

目的是要得到append的结果,但是事实上这样做会将None赋值给mylist,而不是改变后的列表。更加特别的一个例子是想通过用排序后的键值来遍历一个字典里的各个元素,请看下面的例子:

D = {...}

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

差一点儿就成功了——keys方法会创建一个keys的列表,然后用sort方法来将这个列表排序——但是因为sort方法会返回None,这个循环会失败,因为它实际上是要遍历None(这可不是一个序列)。要改正这段代码,将方法的调用分离出来,放在不同的语句中,如下:

Ks = D.keys()

Ks.sort()

for k in Ks: print D[k]

只有在数字类型中才存在类型转换

在Python中,一个诸如123+3.145的表达式是可以工作的——它会自动将整数型转换为浮点型,然后用浮点运算。但是下面的代码就会出错了:

S = "42"

I = 1

X = S + I # 类型错误

这同样也是有意而为的,因为这是不明确的:究竟是将字符串转换为数字(进行相加)呢,还是将数字转换为字符串(进行联接)呢?在Python中,我们认为“明确比含糊好”(即,EIBTI(Explicit is better than implicit)),因此你得手动转换类型:

X = int(S) + I # 做加法: 43

X = S + str(I) # 字符串联接: "421"

循环的数据结构会导致循环

尽管这在实际情况中很少见,但是如果一个对象的集合包含了到它自己的引用,这被称为循环对象(cyclic object)。如果在一个对象中发现一个循环,Python会输出一个[…],以避免在无限循环中卡住:

L = ['grail'] # 在 L中又引用L自身会

L.append(L) # 在对象中创造一个循环

L

['grail', [...]]

除了知道这三个点在对象中表示循环以外,这个例子也是很值得借鉴的。因为你可能无意间在你的代码中出现这样的循环的结构而导致你的代码出错。如果有必要的话,维护一个列表或者字典来表示已经访问过的对象,然后通过检查它来确认你是否碰到了循环。

赋值语句不会创建对象的副本,仅仅创建引用

这是Python的一个核心理念,有时候当行为不对时会带来错误。在下面的例子中,一个列表对象被赋给了名为L的变量,然后L又在列表M中被引用。内部改变L的话,同时也会改变M所引用的对象,因为它们俩都指向同一个对象。

L = [1, 2, 3] # 共用的列表对象

M = ['X', L, 'Y'] # 嵌入一个到L的引用

M

['X', [1, 2, 3], 'Y']

L[1] = 0 # 也改变了M

M

['X', [1, 0, 3], 'Y']

通常情况下只有在稍大一点的程序里这就显得很重要了,而且这些共用的引用通常确实是你需要的。如果不是的话,你可以明确的给他们创建一个副本来避免共用的引用;对于列表来说,你可以通过使用一个空列表的切片来创建一个顶层的副本:

L = [1, 2, 3]

M = ['X', L[:], 'Y'] # 嵌入一个L的副本

L[1] = 0 # 仅仅改变了L,但是不影响M

L

[1, 0, 3]

M

['X', [1, 2, 3], 'Y']

切片的范围起始从默认的0到被切片的序列的最大长度。如果两者都省略掉了,那么切片会抽取该序列中的所有元素,并创造一个顶层的副本(一个新的,不被公用的对象)。对于字典来说,使用字典的dict.copy()方法。

静态识别本地域的变量名

Python默认将一个函数中赋值的变量名视作是本地域的,它们存在于该函数的作用域中并且仅仅在函数运行的时候才存在。从技术上讲,Python是在编译def代码时,去静态的识别本地变量,而不是在运行时碰到赋值的时候才识别到的。如果不理解这点的话,会引起人们的误解。比如,看看下面的例子,当你在一个引用之后给一个变量赋值会怎么样:

X = 99

def func():

... print X # 这个时候还不存在

... X = 88 # 在整个def中将X视作本地变量

...

func( ) # 出错了!

你会得到一个“未定义变量名”的错误,但是其原因是很微妙的。当编译这则代码时,Python碰到给X赋值的语句时认为在这个函数中的任何地方X会被视作一个本地变量名。但是之后当真正运行这个函数时,执行print语句的时候,赋值语句还没有发生,这样Python便会报告一个“未定义变量名”的错误。

事实上,之前的这个例子想要做的事情是很模糊的:你是想要先输出那个全局的X,然后创建一个本地的X呢,还是说这是个程序的错误?如果你真的是想要输出这个全局的X,你需要将它在一个全局语句中声明它,或者通过包络模块的名字来引用它。

默认参数和可变对象

在执行def语句时,默认参数的值只被解析并保存一次,而不是每次在调用函数的时候。这通常是你想要的那样,但是因为默认值需要在每次调用时都保持同样对象,你在试图改变可变的默认值(mutable defaults)的时候可要小心了。例如,下面的函数中使用一个空的列表作为默认值,然后在之后每一次函数调用的时候改变它的值:

def saver(x=[]): # 保存一个列表对象

... x.append(1) # 并每次调用的时候

... print x # 改变它的值

...

saver([2]) # 未使用默认值

[2, 1]

saver() # 使用默认值

[1]

saver() # 每次调用都会增加!

[1, 1]

saver()

[1, 1, 1]

有的人将这个视作Python的一个特点——因为可变的默认参数在每次函数调用时保持了它们的状态,它们能提供像C语言中静态本地函数变量的类似的一些功能。但是,当你第一次碰到它时会觉得这很奇怪,并且在Python中有更加简单的办法来在不同的调用之间保存状态(比如说类)。

要摆脱这样的行为,在函数开始的地方用切片或者方法来创建默认参数的副本,或者将默认值的表达式移到函数里面;只要每次函数调用时这些值在函数里,就会每次都得到一个新的对象:

def saver(x=None):

... if x is None: x = [] # 没有传入参数?

... x.append(1) # 改变新的列表

... print x

...

saver([2]) # 没有使用默认值

[2, 1]

saver() # 这次不会变了

[1]

saver()

[1]

其他常见的编程陷阱

下面列举了其他的一些在这里没法详述的陷阱:

在顶层文件中语句的顺序是有讲究的:因为运行或者加载一个文件会从上到下运行它的语句,所以请确保将你未嵌套的函数调用或者类的调用放在函数或者类的定义之后。

reload不影响用from加载的名字:reload最好和import语句一起使用。如果你使用from语句,记得在reload之后重新运行一遍from,否则你仍然使用之前老的名字。

在多重继承中混合的顺序是有讲究的:这是因为对superclass的搜索是从左到右的,在类定义的头部,在多重superclass中如果出现重复的名字,则以最左边的类名为准。

在try语句中空的except子句可能会比你预想的捕捉到更多的错误。在try语句中空的except子句表示捕捉所有的错误,即便是真正的程序错误,和sys.exit()调用,也会被捕捉到。

python多线程运行过程中出现奇怪的等待行为

你这个程序问题在new = Thread( self.subfunc(i) ) 传进去的时候就已经调用了self.subfunc

改成 new = Thread( target=self.subfunc, args=(i,) )

另外i 数字太小也看不出来,因为工作量太小,在线程的一个时间片内函数就执行完了,看不到切换的过程,设成if i10000就明显了

Python正则表达式奇怪现象

因为你的正则表达式写的有问题。

你写的是r'[0-9]*'其中这个*表示是匹配0个或0个以上,对于hu这也是符合0个的。所以什么都没有打印,至于空格则是print ,这个逗号自动产生的。

最后为什么是15个,这个是英文字母含有11个,另外3个连续数字,最后加一个空串,最后总共就是15个了。。

如果你要只匹配数字部分应该用r'[0-9]+'或r'd+',+号表示至少匹配1个

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。