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的值看看有什么变化。

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

考虑以下的例子:

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!

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,比如11。他们是相等的,那么就返回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
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())

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

  1. python中关于传递参数模块argprase的一些小坑

    今天在写代码的时候遇到了一个关于parser的一些小坑,记录在此备用. 我们知道在python中可以用argprase来传递一些参数给代码执行,来看下面的例子,假设现在有一个test文件夹,下面有3个 ...

  2. Python中需要注意的一些小坑

    Python小知识 # a = a + b /a += b 有时是不一样的​ a=[1,2,3] b = a a = a + [4,5,6] ​ # a=[1,2,3] # b = a # a += ...

  3. python + lisp hy的新手注记1

    想在python里用lisp方言hy的目的: 1 用lisp去parse 包含 “数据+简单if控制流(代码.AST)”的配置文件,或者说用包含s-exp的.hy文件作为这类配置文件的实现(而不是用y ...

  4. Python小项目四:实现简单的web服务器

    https://blog.csdn.net/u010103202/article/details/74002538 本博客是整理在学习实验楼的课程过程中记录下的笔记形成的,参考:https://www ...

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

    目录 1.1 踩坑案例 1.2 填坑解法 1.3 坑位分析 1.4 技术关键字 1.5 坑后思考 下期坑位预告 代码示例支持 平台: Centos 6.3 Python: 2.7.14 代码示例: 菜 ...

  6. [代码修订版] Python 踩坑之旅进程篇其五打不开的文件

    目录 1.1 踩坑案例 1.2 填坑和分析 1.2.1 从程序优化入手 1.2.2 从资源软硬限入手 1.4.1 技术关键字 下期坑位预告 代码示例支持 平台: Centos 6.3 Python: ...

  7. 关于sqlmap的两个小坑

    i春秋作家:__LSA__ 0x00 概述 近日在利用sqlmap注入测试时遇到一个奇怪的现象,高版本sqlmap无法检测出注入,但是低版本的可以测出注入,并且能跑出数据不是误报,经过对比测试和查看s ...

  8. mciSendString 的两个小坑

    刚刚修正了自己用的小闹钟的代码. 坑1:REPEAT 选项的作用范围 原来用得好好的,之后选择 .wav 文件,居然不出声音了…… 诶,MCI 肯定支持 .wav 的啊…… 仔细想想,我以前都是选 . ...

  9. 注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式

    注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式 这个坑,必须要注意呀, 比如在用ListView的时候,如果在List_ ...

随机推荐

  1. Java,该学什么?

    本人大学学的是生物技术专业,毕业后入坑Java. 最近有人问我是如何转行的,需要学一些什么.我在网上看到一篇帖子,觉得写得很全.如果是我来写,可能还写不了这么全的.在此分享给网友. 2019秋招几个月 ...

  2. Spring 框架基础(02):Bean的生命周期,作用域,装配总结

    本文源码:GitHub·点这里 || GitEE·点这里 一.装配方式 Bean的概念:Spring框架管理的应用程序中,由Spring容器负责创建,装配,设置属性,进而管理整个生命周期的对象,称为B ...

  3. 基于SpringCloud实现Shard-Jdbc的分库分表模式,数据库扩容方案

    本文源码:GitHub·点这里 || GitEE·点这里 一.项目结构 1.工程结构 2.模块命名 shard-common-entity: 公共代码块 shard-open-inte: 开放接口管理 ...

  4. zookeeper的java问题

    执行bash ./bin/zkServer.sh statusZooKeeper JMX enabled by defaultUsing config: /data/zookeeper-3.4.9/b ...

  5. Display a Detail View with a List View 主子视图-列表视图与详细信息视图同时显示

    In this lesson, you will learn how to display a Detail View together with a List View. For this purp ...

  6. 【Visio流程图】借助redis来实现数据即时刷新

    [需求:]数据从竞品网站爬过来,经过分析处理之后,把结果通过网页实时反馈给业务人员. [应用:]2个应用: 一个是爬取数据的应用:不断从竞品网站爬数据,每次爬到的数据为一批.然后,对每一批爬到的数据进 ...

  7. SAP系统邮件功能配置

    相信SAP顾问或多或少都会接到用户要求SAP系统能够定时发送邮件的功能,定时将用户需要的信息已邮件的方式发送给固定的人员. 下面就来讲一下SAP发送邮件应该如何配置: 1.RZ10做配置: is/SM ...

  8. Android Gradle 学习笔记(三):Gradle 日志

    在第一节,我们使用到了gradle -q hello命令行来运行Hello World,并对Hello World进行了简单的分析,了解到 gradle -q hello 的意思是要执行的build. ...

  9. mysql中用命令行复制表结构(数据)

    mysql中用命令行复制表结构的方法主要有一下几种: 1.只复制表结构到新表 CREATE TABLE 新表 SELECT * FROM 旧表 WHERE 1=2; 或 CREATE TABLE 新表 ...

  10. iozone - a filesystem benchmark tool 主要是用来测试文件系统 性能

    简介:    磁盘设备之上是文件系统,测试磁盘的工具往往就是调用块设备驱动的接口进行读写测试.而文件系统的测试软件就是针对文件系统层提供的功能进行测试,包括文件的打开关闭速度以及顺序读写随机位置读写的 ...