少儿学习Python编程必须要杜绝的3个错误
少儿学习Python编程
必须要杜绝的3个错误
2017.11.19
承认自己的犯错永远不是一件简单的事情,然而人们往往得从犯错中学习知识,无论是学习不行乃至学习编程,我们就以Python为例。
下面是我在学习Python时犯过的3个错误,写下来给新学习Python的朋友们,避免和我一样犯下同样的错误。这些错误包括了我侥幸避免的以及花了长时间才修复的问题。接下来就让我们来看看是哪几个错误。
1.在函数定义中,将可变数据类型作为默认参数
现在让我们来看一下这个简单的函数,我们将从当前页面抓取连接并将其添加到另一个列表中。
def search_for_links(page,add_to=[]):
new_links =page.search_for_links()
add_to.extend(new_links)
return add_to
从表面来看,运行的很好,而事实也的确如此,它的确能运行。然而其中却有许多问题,如果我们用add_to作为参数,它可以如我们所想一样运行。然而如果我们使用默认参数,那么就会发生一些有趣的事情。
以下面的代码为例
def fn(var1,var2=[]):
var2.append(var1)
print var2
fn(3)
fn(4)
fn(5)
你可能以为我们能看到这样的结果
[3]
[4]
[5]
然而事实却是这样的
[3]
[3, 4]
[3, 4, 5]
为什么?你可以看到同样的列表被调用了三次,而在Python中,我们写出那样的函数,列表将实例化并作为函数定义的一部分,而并不是在每次函数运行的时候实例化。这说明了函数将会使用同样的列表内对象一遍又一遍,除非我们将函数修改成这样
fn(3,[4])
[4, 3]
如我们所想的,正确的方式是这样的:
def fn(var1,var2=None):
if not var2:
var2 =[]
var2.append(var1)
或者以我们第一个例子为例:
def search_for_links(page,add_to=None):
if not add_to:
add_to =[]
new_links =page.search_for_links()
add_to.extend(new_links)
return add_to
这一步将实例化从模块读取的时间中移出,这样实例化才能在每次函数运行的时候同步发生。而对于不可变数据类型则没有必要,只要做以下两步即可
2.将可变数据类型作为变量
紧随其后的错误就很普遍了,让我们来看一下:
class URLCatcher(object):
urls =[]
def add_url(self,url):
self.urls.append(url)
代码看起来没有任何问题是不是?这段代码将调用add_url来把连接储存到urls列表里去,那么接下来让我们来看下一步
a =URLCatcher()
a.add_url('http://www.google.')
b =URLCatcher()
b.add_url('http://www.bb
c.co.')
b.urls
['https://www.360docs.net/doc/a39022928.html,', 'https://www.360docs.net/doc/a39022928.html,']
a.urls
['https://www.360docs.net/doc/a39022928.html,', 'https://www.360docs.net/doc/a39022928.html,']
等等!为什么两个列表都有2个链接?我们不是分别将他储存进不同的列表了吗?
看起来其实和之前的问题有一点像,同样是将url列表编入了类的定义里,所以为了避免这种情况,我们可以通过这种方式来分别储存。
class URLCatcher(object):
def__init__(self):
self.urls=[]
def add_url(self,url):
self.urls.append(url)
现在我们就可以将两个链接分别储存了。
3.用可变数据类型来赋值
这个问题困扰我许久,现在让我们看一下如果使用字典会产生什么问题吧。
a ={'1': "one",'2': 'two'}
现在假设我们要将字典用在其他地方并且保留原字典内容
b = a
b['3']='three'
是不是很简单?
那么回过头来再让我们看一下字典a里的内容
{'1': "one",'2': 'two','3': 'three'}
现在字典a和字典b完全一样了,而如果我们用不可变数据类型来做结果就完全不同,以元组为例:
c =(2,3)
d = c
d =(4,5)
现在c是:
(2, 3)
元组d是:
(4, 5)
这次就成功地达到了我们的目的。那么为什么在例子中我们会失败?因为对于Python 来说,当我们输入b=a,那么a与b之间会形成一个相互引用的关系,这其实就和我们之前的2个问题非常相似,这也是所有可变数据类型最可能造成的麻烦。
如果我们真的很需要将部分列表调用出来来处理的话,那么我们可以用以下方法来做:b =a[:]
通过这行代码,我们可以得到一个崭新的列表,但是如果在列表中的对象是可变数据类型而不是单纯的数据,那么同样会造成相同的问题。
正如A和B同时看着一份列表,而通过这行代码,A和B可以拥有各自的列表,然而如果列表中含有可变的数据类型,那么当A修改这个对象时,B同样会看到数据的改变。
字典也可以通过这行代码来实现这个目的。
b = a.copy()
同样的,如果按照刚刚的问题来修改的话,也会得到相同的结果。可变数据类型的麻烦的确很大,所以我们在平时编程时更要注重细节,避免类似错误的发生。