python编码错误_学习用Python编码时要避免的3个错误

python编码错误

做错事绝非易事,但犯错是任何学习过程的一部分,从学习走路到学习新的编程语言(例如Python)。

这里列出了我在学习Python时出错的三件事,以使新的Python程序员可以避免犯同样的错误。 这些错误或者是我很久以前就解决的,或者是造成了需要花费数小时才能解决的重大问题的错误。

请注意年轻的编码员,其中一些错误是浪费下午的时间!

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.' )
b = URLCatcher ( )
b. add_url ( 'http://www.bbc.co.' )

b.urls
[' http ://www.google.com,'http://www.bbc.co.uk ']

网址
[' http ://www.google.com,'http://www.bbc.co.uk ']

等等,什么? 我们没想到。 我们实例化了两个单独的对象ab为A提供了一个URL,为b提供了另一个URL。 两个对象都有两个URL怎么办?

事实证明,这与第一个示例有点相同。 创建类定义时,将实例化URL列表。 该类的所有实例都使用相同的列表。 现在,在某些情况下这是有利的,但是大多数时候您不想这样做。 您希望每个对象都有一个单独的存储。 为此,我们将修改如下代码:



   
   
class URLCatcher ( object ) :
    def __init__ ( self ) :
        self . urls = [ ]

    def add_url ( self , url ) :
        self . urls . append ( url )

现在,在创建对象时实例化URL列表。 当我们实例化两个单独的对象时,它们将使用两个单独的列表。

3.可变的分配错误

这使我困惑了一段时间。 让我们稍微改变一下齿轮,使用另一个可变的数据类型dict



   
   
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现在也是一个参考。 它们都指向Python内存中的同一对象。 听起来有点熟? 那是因为它与先前的问题相似。 实际上,该帖子实际上应该被称为“可变因素的麻烦”。

列表也会发生同样的事情吗? 是。 那么我们如何解决呢? 好吧,我们必须非常小心。 如果我们确实需要复制列表进行处理,则可以执行以下操作:


b = a [ : ] 

这将遍历并将引用复制到列表中的每个项目,并将其放置在新列表中。 但请注意:如果列表中的任何对象都是可变的,我们将再次获得对这些对象的引用,而不是完整的副本。

想象一下在一张纸上有一张清单。 在原始示例中,人员A和人员B看着同一张纸。 如果有人更改了该列表,则两个人都会看到相同的更改。 当我们复制引用时,每个人现在都有自己的列表。 但让我们假设此列表包含寻找食物的地方。 如果“冰箱”在列表中位于第一位,即使复制后,两个列表中的两个条目都指向同一台冰箱。 因此,如果人A修改了冰箱,比如说吃了一个大的奶油蛋糕,那么人物B也将看到奶油蛋糕丢失了。 解决这个问题没有简单的方法。 您只需要记住并以不会引起问题的方式进行编码即可。

Dicts的功能相同,您可以执行以下操作来创建此昂贵的副本:


b = a. copy ( ) 

同样,这只会创建一个新字典,指向与原始字典中相同的条目。 因此,如果我们有两个相同的列表,并且我们修改了字典'a'中的键所指向的可变对象,则字典'b'中存在的字典对象也将看到这些更改。

可变数据类型的麻烦在于它们功能强大。 以上都不是真正的问题; 他们是牢记防止问题的事情。 在第三项中作为解决方案提出的昂贵的复制操作在99%的时间中都是不必要的。 您的程序可以而且应该进行修改,这样一开始甚至不需要这些副本。

编码愉快! 并随时在评论中提问。

翻译自: https://opensource.com/article/17/6/3-things-i-did-wrong-learning-python

python编码错误

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值