7个Python小坑,给新手党的福利

Python语言简单易用,但容易给新入门的朋友造成一些微妙的,难以捕捉的错误,稍不注意就入坑了。
因此,今天给大家总结一些易犯的小错误,让你轻松进行不踩坑的Python学习。

1、缩进,符号和空格不正确

写代码时大家会使用缩进、对齐、空格等,其目的是为了提高代码的可读性。
但在python语言中,许多功能都依赖于缩进。

比如在创建一个新类时,该类中的所有内容都在声明下缩进,决策、循环还有其它结构语句也会出现类似的情况,

如果你在代码执行时发现问题,可以查看一下是否使用了正确的缩进。

来看看下面的例子,在使用IF语句时,请确保使用正确且合适的冒号和缩进,因为它们会导致语法和缩进错误。

val = 500
if val > 100
print("value is grater then 100")

File "<ipython-input-1-a271e37c300f>", line 2
    if val > 100
                ^
SyntaxError: invalid syntax

在上面的代码当中,出现了两处错误:if语句后面的:缺失;下一行没有进行正确的缩进,执行代码出错。

val = 500
if val > 100:
 print("value is grater then 100")

value is grater then 100

当你更正上述代码中的两个问题后,你会发现整段代码能够很好的运行。

2、错误使用类变量

class A(object):x = 1class B(A):passclass C(A):passprint( A.x, B.x, C.x)1 1 1
这里输出的值都是1,然后我们试着来改变一下A.x和B.x的值看看有什么变化。

‘‘‘
遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,
互帮互助,群里还有不错的视频学习教程和PDF电子书!
‘‘‘
B.x = 2
print (A.x, B.x, C.x)
A.x = 3
print (A.x, B.x, C.x)
1 2 1
3 2 3

我们只改变了A.x,为什么C.x改变呢?

这里需要简单了解一下python的命名空间。

python中,命名空间是名字到对象映射的结合,不同命名空间中的名字是没有关联的,这种映射的实现有点类似于python中的字典。

当你名字访问一个对象的属性时,先从对象的命名空间寻找。如果找到了这个属性,就返回这个属性的值;如果没有找到的话,则从类的命名空间中寻找,找到了就返回这个属性的值,找不到则抛出异常。

在Python中,类变量在内部作为字典处理,并遵循通常称为方法解析顺序(MRO)的方法。

MRO:Method Resolution Order 方法解析顺序,Python支持多继承,该方法用于解决父类存在同名函数的时存在的二义性问题。

因此在上面的代码中,由于x在对象的命名空间中找不到该属性C,因此将在类中查找它。换句话说,C没有自己的x属性,独立于A。因此,引用C.x实际上是指A.x。

3、误解python范围规则

如果你不了解python的范围规则,那么你很容易犯错误,这是因为Python使用一种独有的范围规则来确定变量范围。
python范围解析是基于LEGB规则,以下是Python范围规则的概述:

  • ·L -代表Local。它包含在函数内指定的(标识符/变量)名称(使用def或lambda),而不是使用global关键字声明。
  • ·E -代表Enclosing function locals。它包含来自任何/所有封闭函数的本地范围的名称(例如,使用def或lambda)。
  • ·G -指全球实体。它包括在模块文件的顶层运行或使用global关键字定义的名称。
  • ·B -指内置插件。它跨越预先指定为内置名称的名称,如打印,输入,打开等。

LEGB规则指定名称空间的以下顺序,用于搜索名称:

Local - > Enclosed - > Global - > Built-in

考虑以下的例子:

‘‘‘
遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,
互帮互助,群里还有不错的视频学习教程和PDF电子书!
‘‘‘
x = 10
def foo():
  x += 1
 print(x)
foo()

UnboundLocalError Traceback (most recent call last):
<ipython-input-26-234e54482865> in <module>
<ipython-input-26-234e54482865> in foo()
UnboundLocalError: local variable ‘x‘ referenced before assignment

发生上述错误的原因是,对作用域中的变量进行赋值时,Python会自动将该变量视为该作用域的本地变量,并在外部作用域中隐藏任何类似命名的变量。
因此,许多人在代码提示出错并显示需要在函数中添加赋值语句而感到不解。
考虑一个在使用列表时遇到的例子:

lst = [1, 2, 3]
def foo1():
  lst.append(5)
foo1()
lst
[1, 2, 3, 5]
lst = [1, 2, 3]
def foo2():
   lst += [5]
foo2()

UnboundLocalError  Traceback (most recent call last):
<ipython-input-30-579469eed71a> in <module>
<ipython-input-30-579469eed71a> in foo2()
UnboundLocalError: local variable ‘lst‘ referenced before assignment

为什么foo2出错了但是foo1运行良好?

答案在前面就已经有所提示,在这个例子当中foo1()做一个分配到lst,而在foo2()当中lst += [5]其实只是lst = lst + [5]的简写,我们希望分配一个值给lst,但是分配的值lst是基于lst自身,但其尚未定义。

4、python闭包变量绑定

python的闭包变量问题也是新手们容易混淆的一个点,来看看下面的例子:

def create_multipliers():
   return [lambda x : i * x for i in range(5)]
for multiplier in create_multipliers():
    print (multiplier(2))
8
8
8
8
8

为什么结果是88888,和我所想的02468不一样呢?

这是由于Python的迟绑定(late binding)机制,闭包中内部函数的值只有在被调用时才会进行查询。

因此create_multipliers函数返回的lambda函数被调用时,会在附近的作用域中查询变量i的值,而在create_multipliers生成返回数组之后,整数i的值是4,不会再改变,因此返回数组中每个匿名函数实际上都是:lambda x: 4*x。、

解决办法是将临时值也保存在匿名函数的作用域内,在声明匿名函数时就查询变量的值。
了解原理之后,让我们来改一改代码,surprise!

‘‘‘
遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,
互帮互助,群里还有不错的视频学习教程和PDF电子书!
‘‘‘
def create_multipliers():
     return [lambda x, i=i : i * x for i in range(5)]
for multiplier in create_multipliers():
     print (multiplier(2))
0
2
4
6
8

5、名称与Python标准库模块发生冲突

Python拥有大量的库模块,开箱即用。但是,如果您遇到一个模块的名称与Python附带的标准库中具有相同名称的模块之间的名称冲突,则可能会出现问题。

例如导入另一个库,而这个库又会尝试导入模块的Python标准库版本,但由于你有一个同名的模块,另一个包会错误地导入你的版本而不是Python标准库。

因此,应该注意避免使用与Python标准库模块中相同的名称,并且更改包中的模块名称比提交Python Enhancement Proposal(PEP)以请求名称更改更容易。

6、is和==/=和==

Python中有很多运算符,例如is,=,==这三个,许多刚刚入门的新手会误解这三个运算符的意义和用法,以致于代码出错。

在 Python 中会用到对象之间比较,可以用 ==,也可以用 is,但对对象比较判断的内容并不相同,区别在哪里?

·is 比较两个对象的 id 值是否相等,是否指向同一个内存地址,== 比较的是两个对象的内容是否相等,值是否相等;

a = ["Python"]
b = a
b is a
True
id(a)
2222222
id(b)
2222222
b == a
True

可以发现上面的例子当中b和a的内存地址是相同的,它们指向同一块内存,因而 is 和 == 的结果都为True,这是因为直接赋值都是赋值的引用。如果新建对象之后,b 和 a 指向了不同的内存,那么 b is a 的结果为False,而 b==a的结果为True。

·小整数对象[-5,256]在全局解释器范围内被放入缓存供重复使用,例如:

a = 1
b = 1
a is b
True
a == b
True
a = 257
b = 257
a is b
False

Python仅仅对比较小的整数对象进行缓存(范围为范围[-5, 256])缓存起来,而并非是所有整数对象。需要注意的是,这仅仅是在命令行中执行,而在Pycharm或者保存为文件执行,结果是不一样的,这是因为解释器做了一部分优化。

=和==的含义不同:

=代表的含义是赋值,将某一数值赋给某个变量,比如a=3,将3这个数值赋予给a。
==是判断是否相等,返回True或False,比如1==1。他们是相等的,那么就返回true。1==2,他们是不相等的,那么就返回false。
例子:

a = [1,2]
b = [1,2]
c = a
a is b
False
a is c
true
a == b
true

7、滥用init

init方法在Python中用作构造函数,当Python将内存分配给新的类对象时,它会自动被调用。
首先,init并不相当于C#中的构造函数,在执行它的时候,实例已经构造出来。

‘‘‘
遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,
互帮互助,群里还有不错的视频学习教程和PDF电子书!
‘‘‘
class A(object):
   def __init__(self,name):
       self.name=name
   def getName(self):
       return ‘A ‘+self.name
执行代码:
a=A(‘hello‘)

可以理解为:

a=object.__new__(A)
A.__init__(a,‘hello‘)

init作用是初始化已实例化后的对象。

其次,子类可以不重写init,实例化子类时,会自动调用超类中已定义的init

class B(A):
    def getName(self):
        return ‘B ‘+self.name

if __name__==‘__main__‘:
    b=B(‘hello‘)
    print (b.getName())

但如果重写了init,实例化子类时,则不会隐式的再去调用超类中已定义的init

class C(A):
    def __init__(self):
        pass
    def getName(self):
        return ‘C  ‘+self.name

if __name__==‘__main__‘:
    c=C()
    print (c.getName())

此时执行代码则会报"AttributeError: ‘C‘ object has noattribute ‘name‘”错误,所以如果重写了init,为了能使用或扩展超类中的行为,最好显式的调用超类的init方法。

class C(A):
    def __init__(self,name):
        super(C,self).__init__(name)
    def getName(self):
        return ‘C  ‘+self.name

if __name__==‘__main__‘:
    c=C(‘hello‘)
    print (c.getName())

原文地址:https://blog.51cto.com/14246112/2445208

时间: 2024-10-08 15:30:04

7个Python小坑,给新手党的福利的相关文章

Python小爬虫-自动下载三亿文库文档

新手学python,写了一个抓取网页后自动下载文档的脚本,和大家分享. 首先我们打开三亿文库下载栏目的网址,比如专业资料(IT/计算机/互联网)http://3y.uu456.com/bl-197?od=1&pn=0,可以观察到,链接中pn=后面的数字就是对应的页码,所以一会我们会用iurl = 'http://3y.uu456.com/bl-197?od=1&pn=',后面加上页码来抓取网页. 一般网页会用1,2,3...不过机智的三亿文库用0,25,50...来表示,所以我们在拼接ur

python 小技巧

英文出处:sahandsaba.欢迎加入翻译组. 从我开始学习python的时候,我就开始自己总结一个python小技巧的集合.后来当我什么时候在Stack Overflow或者在某个开源软件里看到一段很酷代码的时候,我就很惊讶:原来还能这么做!,当时我会努力的自己尝试一下这段代码,直到我懂了它的整体思路以后,我就把这段代码加到我的集合里.这篇博客其实就是这个集合整理后一部分的公开亮相.如果你已经是个python大牛,那么基本上你应该知道这里面的大多数用法了,但我想你应该也能发现一些你不知道的新

python小游戏之一--------猜数字

看了一下python的入门书,拿个小游戏来练练手,其实就几行代码,也只有新手和脸皮厚的吊丝才好意思拿出来献丑 就好像张X忠一样,来,上海带,天朝海军天下无敌了 这里主要是一个random函数和 while 循环语句的使用,没了 #-*- encoding: utf-8 -*- ''' Created on 2014年5月8日 @author: Administrator ''' import random keys = random.randint(1,100)    #这个函数的作用是给一个随

Python 踩坑之旅进程篇其四一次性踩透 uid euid suid gid egid sgid的坑坑洼洼

目录 1.1 踩坑案例 1.2 填坑解法 1.3 坑位分析 1.4 技术关键字 1.5 坑后思考 下期坑位预告 代码示例支持 平台: Centos 6.3 Python: 2.7.14 代码示例: 菜单 - Python踩坑指南代码示例 1.1 踩坑案例 小明是个服务器管理员, 他从老管理员手里接手了一个非常繁琐的运维工作: 短暂授权root 账号给不同的 team 接口人运行备份任务 该运维任务有几个特点: 任务需且仅需运行在 root 下 root 账号只能短暂授权给各个小组 通过账号管理平

python小游戏之课堂提问器

今天,接着前边的python小游戏,又写了个课堂提问器小程序.供大家一乐! #coding:utf-8 from random import randint print '\033[1;32;40m', print '你好,请选择需要几位作答者?\n' print '请输入作答者的人数:', t=1 i=input() data=[] while t<=i:     r=randint(0,32)    # print m[r],     data.append(m[r])     t+=1 p

支付宝集成的小坑--集成支付宝集成总结(1)

现在很多公司的APP都会有支付环节,特别是现在的O2O项目,我参与过的近两个项目都有集成支付宝对两次集成做一下总结: 第一次集成支付宝,由于我们的做后台的大牛写了十几年代码,而且以前是银行项目的总监,整个支付流程基本上一切听大牛的,我按照做就行.基本上按照支付宝的流程走,支付环节没怎么出问题,总体来说支付流程比较perfect. 第一次集成的小坑: 1)无非就是支付宝里面使用了一些框架如SBJson 等常用的开源框架,而我们项目中也会用到SBJson类似的框架,估计会出现冲突 冲突的解决办法:A

一个关于Windows下SetCursorPos和GetCursorPos的小坑

这两天在做一个编辑特定格式Mesh的小工具,需要检查鼠标的移动,一般来说可以用WM_MOUSEMOVE事件解决的,但是我为了省事用了定时查询+设置的方式,也就是: 1 void Frame(void) 2 { 3 //do something else... 4 5 POINT cursorPos; 6 GetCursorPos(&cursorPos); 7 curMoveX = cursorPos.x - cursorBaseX; 8 curMoveY = cursorPos.y - curs

python小程序之一

来个Python小程序 #输入年月日确定这个日期是一年中的第多少天# -*- coding: UTF-8 -*-y=int(raw_input("请输入年:"))m=int(raw_input("请输入月份:"))d=int(raw_input("请输入日期:"))a=(0,31,28,31,30,31,30,31,31,30,31,30,31)if m>12: raise ValueError("输入月份错误")if

C#中的Infinity有个小坑

(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 昨天家里有事,上网也不方便,就没有推送文章.今天很累,也不长篇大论了.简单介绍一下最近遇到的一个小坑. 我们知道,在C#中主要有如下几种数值类型:int.long.decimal.float和double.对于前三种,如果除零,那么会提示表达式错误(直接书写数字)或报DivideByZeroException异常(使用变量):对于后面两种,除零会得到正负无穷大,除非你是0.0/0.0那么会得到NaN