您的位置 首页 FPGA

Python编程经常见的3个过错

Python编程时常见的3个错误-以下列出了学习 Python 时犯的三种错误:
1.可变数据类型作为函数定义中的默认参数
2.可变数据类型作为类变量
3. 可变的分配错误

当你做错事时,承认过错并不是一件简略的事,可是犯错是任何学习过程中的一部分,无论是学习走路,仍是学习一种新的编程言语都是这样,比方学习 Python。

为了让初学 Python 的程序员避免犯相同的过错,以下列出了我学习 Python 时犯的三种过错。这些过错要么是我长期以来经常犯的,要么是形成了需求几个小时处理的费事。

年青的程序员们可要留意了,这些过错是会糟蹋一下午的!

Python编程经常见的3个过错

1、 可变数据类型作为函数界说中的默许参数

这似乎是对的?你写了一个小函数,比方,查找当前页面上的链接,并可选将其附加到另一个供给的列表中。

def search_for_links(page, add_to=[]):

new_links = page.search_for_links()

add_to.extend(new_links)

return add_to

从外表看,这像对错常正常的 Python 代码,事实上它也是,而且是能够运转的。可是,这儿有个问题。假如咱们给 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

这将在模块加载的时分移走实例化的内容,以便每次运转函数时都会产生列表实例化。请留意,关于不行变数据类型,比方元组、字符串、整型,是不需求考虑这种状况的。这意味着,像下面这样的代码对错常可行的:

def func(message=“my message”):

print message

2、 可变数据类型作为类变量

这和上面说到的最终一个过错很相像。考虑以下代码:

class URLCatcher(object):

urls = []

def add_url(self, url):

self.urls.append(url)

这段代码看起来十分正常。咱们有一个贮存 URL 的目标。当咱们调用 add_url 办法时,它会增加一个给定的 URL 到存储中。看起来十分正确吧?让咱们看看实践是怎样的:

a = URLCatcher()

a.add_url(‘http://www.google.com’)

b = URLCatcher()

b.add_url(‘http://www.bbc.co.hk’)

b.urls:

[‘http://www.google.com’, ‘http://www.bbc.co.uk’]

a.urls:

[‘http://www.google.com’, ‘http://www.bbc.co.uk’]

等等,怎么回事?!咱们想的不是这样啊。咱们实例化了两个独自的目标 a 和 b。把一个 URL 给了 a,另一个给了 b。这两个目标怎么会都有这两个 URL 呢?

这和第一个错例是相同的问题。创立类界说时,URL 列表将被实例化。该类一切的实例运用相同的列表。在有些时分这种状况是有用的,但大多数时分你并不想这样做。你期望每个目标有一个独自的贮存。为此,咱们修正代码为:

class URLCatcher(object):

def __init__(self):

self.urls = []

def add_url(self, url):

self.urls.append(url)

现在,当创立目标时,URL 列表被实例化。当咱们实例化两个独自的目标时,它们将别离运用两个独自的列表。

3、 可变的分配过错

这个问题困扰了我一段时间。让咱们做出一些改动,并运用另一种可变数据类型 – 字典。

a = {‘1’: “one”, ‘2’: ‘two’}

现在,假定咱们想把这个字典用在其他当地,且坚持它的初始数据完好。

b = a

b[‘3’] = ‘three’

简略吧?

现在,让咱们看看本来那个咱们不想改动的字典 a:

‘1’: “one”, ‘2’: ‘two’, ‘3’: ‘three’}

哇等一下,咱们再看看 b?

{‘1’: “one”, ‘2’: ‘two’, ‘3’: ‘three’}

等等,什么?有点乱……让咱们回想一下,看看其它不行变类型在这种状况下会产生什么,例如一个元组:

c = (2, 3)

d = c

d = (4, 5)

现在 c 是 (2, 3),而 d 是 (4, 5)。

这个函数成果如咱们所料。那么,在之前的比方中究竟产生了什么?当运用可变类型时,其行为有点像 C 言语的一个指针。在上面的代码中,咱们令 b = a,咱们真实表达的意思是:b 成为 a 的一个引证。它们都指向 Python 内存中的同一个目标。听起来有些了解?那是由于这个问题与从前的类似。其实,这篇文章应该被称为「可变引发的费事」。

列表也会产生相同的事吗?是的。那么咱们怎么处理呢?这有必要十分当心。假如咱们真的需求仿制一个列表进行处理,咱们能够这样做:

b = a[:]

这将遍历并仿制列表中的每个目标的引证,而且把它放在一个新的列表中。可是要留意:假如列表中的每个目标都是可变的,咱们将再次取得它们的引证,而不是完好的副本。

假定在一张纸上列清单。在本来的比方中相当于,A 某和 B 某正在看着同一张纸。假如有个人修正了这个清单,两个人都将看到相同的改变。当咱们仿制引证时,每个人现在有了他们自己的清单。可是,咱们假定这个清单包含寻觅食物的当地。假如“冰箱”是列表中的第一个,即便它被仿制,两个列表中的条目也都指向同一个冰箱。所以,假如冰箱被 A 修正,吃掉了里边的大蛋糕,B 也将看到这个蛋糕的消失。这儿没有简略的办法处理它。只需你记住它,并编写代码的时分,运用不会形成这个问题的方法。

字典以相同的方法作业,而且你能够经过以下方法创立一个贵重副本:

b = a.copy()

再次阐明,这只会创立一个新的字典,指向本来存在的相同的条目。因而,假如咱们有两个相同的列表,而且咱们修正字典 a 的一个键指向的可变目标,那么在字典 b 中也将看到这些改变。

可变数据类型的费事也是它们强壮的当地。以上都不是实践中的问题;它们是一些要留意避免呈现的问题。在第三个项目中运用贵重仿制操作作为处理方案在 99% 的时分是没有必要的。你的程序或许应该被改改,所以在第一个比方中,这些副本乃至是不需求的。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/fangan/fpga/340858.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部