python的坑--你知道吗?
python的坑--你知道吗?
1.列表的坑
坑的地方是:因为列表用pop之后,后面的索引都会自动减一
# 列表的坑之一
list1 = ['python','java','php','c','c++','c#','ruby']
# 将索引为奇数的元素删除 ['java','c','c#']
list2 = []
for item in list1:
if list1.index(item) % 2 != 1:
list1.pop(list1.index(item))
print(list1) # ['java', 'php', 'c++', 'c#']
# 这是因为列表用pop之后,后面的索引都会自动减一
# 正确的操作如下:
# 切片
list1 = ['python','java','php','c','c++','c#','ruby']
list2 = list1[1::2]
print(list2) #['java','c','c#']
# 赋值到其他的空列表
list1 = ['python','java','php','c','c++','c#','ruby']
list2 = []
for i in list1:
if list1.index(i)%2==0:
list2.append(i)
print(list2) # ['java','c','c#']
# 倒序删除
list1 = ['python','java','php','c','c++','c#','ruby']
for i in range(len(list1)-1,-1,-1):
if i % 2 == 0:
del li[i]
print(list1) # ['java','c','c#']
2.默认参数的陷阱
# def func(name, sex='男'):
# print(name)
# print(sex)
#
#
# func('zhouqian')
# 输出的结果为:
# zhouqian
# 男
上面的代码是运行正常的,仿佛默认参数并没有什么坑。但是我们用下面的例子就知道了。默认参数的陷阱只针对默认参数是可变的数据类型。
# def func(name, alist=[]):
# alist.append(name)
# return alist
#
#
# ret = func('zhouqian')
# print(ret, id(ret)) # ['zhouqian'] 2135732081224
# ret2 = func('太白金星')
# print(ret2, id(ret2))# 按理说是['太白金星'],但是实际上输出['zhouqian', '太白金星'] 2135732081224
# print(func('zhouqian'))
# ['zhouqian'] 2135732081224
# ['zhouqian', '太白金星'] 2135732081224
通过id可知,默认参数是列表的话在内存中是共用同一个地址。只要调用了这个函数,那么就会在同一个地址后面操作这个元素。如果你的默认参数是可变的数据类型,那么无论你调用多少次函数,这个默认参数指向的都是同一个地址。如果你给可变的数据类型传一个值,那么就不会用原来默认的,就用这个传值的。
下面我们用两个python的面试题来讲解默认参数是可变数据类型的坑。
面试题1:
def func(a, alist=[]):
alist.append(a)
return alist
print(func(10, )) # [10]
print(func(20, [])) # [20]
print(func(100, )) # [10,100]
# 上面的类似于下面的代码:
# l1 = []
# l1.append(10)
# print(l1) # [10]
# l2 = []
# l2.append(20)
# print(l2) # [20]
# l1.append(100)
# print(l1) # [10,100]
面试题2:
def func(a, alist=[]):
alist.append(a)
return alist
ret1 = func(10, ) # 这里的值是alist(id 1564531154864)
ret2 = func(20, []) # 这里的值是alist (id 4648456151995)
ret3 = func(100, ) # 这里的值是alist (id 1564531154864)
print(ret1) # [10, 100]
print(ret2) # [20]
print(ret3) # [10, 100]
# 上面的类似于下面的代码:
# l1 = []
# l1.append(10)
# l2 = []
# l2.append(20)
# l1.append(100)
# ret1 = l1
# ret2 = l2
# ret3 = l1
# print(ret1) # [10,100]
# print(ret2) # [20]
# print(ret3) # [10,100]
3.局部作用域的陷阱
# count = 1
# def func():
# count += 1
# print(count)
# # UnboundLocalError: local variable 'count' referenced before assignment
# func()
# 解释:2.局部作用域不能改变全局作用域的变量。当python解释器读取到局部作用域时,发现你对一个变量进行了修改的操作,解释器会认为你在局部作用域已经定义过这个局部变量,他就从局部找这个局部变量,报错了。
# 局部和全局作用域的详细解析
# 1.局部作用域可以获得到全局作用域中使用变量,重新创建变量,操作变量的赋值,可以用来对变量进行操作,改变变量的值。
# 2.局部作用域不能改变全局作用域的变量。当python解释器读取到局部作用域时,发现你对一个变量进行了修改的操作,解释器会认为你在局部作用域已经定义过这个局部变量,他就从局部找这个局部变量,报错了。
# 3.但是全局作用域不可以获得局部作用域,不能操作局部作用域的变量,不能操作局部作用域的变量值。
# count = 1
#
# 在函数中,如果你定义了一个变量,但是在定义这个变量之前对其引用了,那么解释器认为语法问题。
# 你应该使用之前的先定义后引用。
# def func():
# # 先引用后定义。报错
# print(count) # UnboundLocalError: local variable 'count' referenced before assignment
# count = 3
#
# func()
# 解释:在函数中,如果你定义了一个变量,但是在定义这个变量之前对其引用了,那么解释器认为语法问题,你应该使用之前的先定义后引用。
# 以下两个代码是不会报错的。可以正常运行输出结果。
# count = 1
#
#
# def func():
# print(count) # 1
# # count = 3 # 将count=3删除/注释掉就不会报错
#
#
# func()
# count = 1
#
#
# def func():
# count = 3
# print(count) # 3
#
#
# func()
4.补充知识点:global和nonlocal
# global和nonlocal
# 1.在局部作用域声明一个全局变量
# name = 'alex'
# def func():
# name = 'AndreasZhou'
# print(name)
# func()
# print(name)
# 输出的结果为:
# AndreasZhou
# alex
# 解析:全局变量是从全局名称空间和内置名称空间中取值。局部变量是从局部名称作用域、全局名称作用域和内置名称作用域取值。
# 局部名称作用域---》全局名称作用域---》内置名称作用域取值,单向不可逆。
# def func():
# name = 'AndreasZhou'
# print(name)
# func() # AndreasZhou
# print(name) # NameError: name 'name' is not defined
# 输出的结果为:
# AndreasZhou
# NameError: name 'name' is not defined
# name = 'zhouqian'
# def func():
# global name
# name = 'AndreasZhou'
# print(name)
# func()
# print(name)
# 输出的结果为:
# AndreasZhou
# AndreasZhou
# def func():
# global name
# name = '太白金星'
# print(name)
# print(name)
# func()
# 输出的结果为:
# NameError: name 'name' is not defined
# # 2.修改一个全局变量
# count = 1
# def func():
# # print(count) SyntaxError: name 'count' is used prior to global declaration
# global count
# count += 1
# print(count) # 1
# func()
#
# print(count) # 2
# nonlocal
# 1.不能够操作全局变量
# count = 1
# def func():
# nonlocal count # SyntaxError: no binding for nonlocal 'count' found
# count += 1
# func()
# 2.局部作用域:内层函数对外层函数的局部变量进行修改
# def wrapper():
# count = 1
# def inner():
# count+=1 # UnboundLocalError: local variable 'count' referenced before assignment
# inner()
# wrapper()
def wrapper():
count = 1
def inner():
nonlocal count
count += 1
print(count) # 1
inner()
print(count) # 2
wrapper()
python的坑--你知道吗?的更多相关文章
- 杂记:Python 两坑
近日写代码又遇到两个 Python 的坑,觉得值得记录. 递归传参问题 Python 里传参的实现是 assignment,但由于 Python 里都是对象,除了几个基本类型,assignment 基 ...
- Python踩坑之旅其一杀不死的Shell子进程
目录 1.1 踩坑案例 1.2 填坑解法 1.3 坑位分析 1.4 坑后扩展 1.4.1 扩展知识 1.4.1 技术关键字 1.5 填坑总结 1.1 踩坑案例 踩坑的程序是个常驻的Agent类管理进程 ...
- 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 踩坑案例 1.2 填坑和分析 1.2.1 从程序优化入手 1.2.2 从资源软硬限入手 1.4.1 技术关键字 下期坑位预告 代码示例支持 平台: Centos 6.3 Python: ...
- Python 踩坑之旅文件系统篇其一文件夹也是个文件
目录 1.1 案例 1.2 分析 1.3 扩展 1.4 技术关键字 下期预告 代码示例支持 平台: Mac OS Python: 2.7.10 代码示例: - wx: 菜单 - Python踩坑指南代 ...
- python踩坑系列之导入包时下划红线及报错“No module named”问题
python踩坑系列之导入包时下划红线及报错“No module named”问题 使用pycharm编写Python时,自己写了一个包(commontool),在同级另一个路径下(fileshand ...
- [Python]Python入坑小项目推荐- Flask example minitwit
知乎上看到的Python练手项目推荐,链接见:https://www.zhihu.com/question/29372574,不知道是我自己懒得看还是理解力不行,这些项目真的是...太大了呀~~~~ ...
- python跳坑---生成器
贵有恒,何必三更眠五更起,最无益,只怕一日曝十日寒. 好多东西要写下来一是方便自己,二可以分享给大家,我却一拖再拖. 工作的时候看别人代码中间结果,跳了个坑,关于python generator类型: ...
- Python踩坑:类与类对象类型参数传递与使用
前言 对初学者来说,Python确实简单好用,毕竟动态类型语言,不用定义就可以拿来用,类型之间随意转换简直不要太方便,因此Python用来写写小脚本,爬虫程序什么的,没什么问题. 不过,一旦用来开发稍 ...
随机推荐
- C语言数据类型整理
基本类型: 它们是算术类型,包括两种类型:整数类型和浮点类型. 枚举类型: 它们也是算术类型,被用来定义在程序中只能赋予其一定的离散整数值的变量. void 类型: 类型说明符 void 表明没有可用 ...
- PHP 连接数据库基础操作
<?phpheader('Content-type:text/html;charset=utf-8');//1建立 或者 关闭mysql服务器 @符号用于屏蔽错误信息$link=@mysql ...
- 虚拟机配置JAVA_HOME
1.cp home/fan-vm2/es/tools/jdk-8u111-linux-x64.tar.gz usr/java2.tar -zxvf jdk-8u111-linux-x64.tar.gz ...
- python中几个双下划线用法的含义
_ _ init() _ _(self[,...]) 我们有时在类定义写__init()__方法,但是有时又没有.__init()__方法相当于其他面向对象的编程语言中的构造方法,也就是类在实例化成对 ...
- Linux操作系统分析 | 深入理解系统调用
实验要求 1.找一个系统调用,系统调用号为学号最后2位相同的系统调用 2.通过汇编指令触发该系统调用 3.通过gdb跟踪该系统调用的内核处理过程 4.重点阅读分析系统调用入口的保存现场.恢复现场和系统 ...
- React Router简单Demo
简介 react router是使用react的时候首选的一个路由工具. 安装 react router包含react-router,react-router-dom和react-router-nat ...
- 求最长非降(递增)子序列LIS的长度,及注意事项
非降序列(Increasing Sequence)例如: (1) 完全递增型序列:S={1,3,6,7,9} (2) 部分存在等于的序列:S={1,3,3,6,9} S的非降子序列:由原序列S的元素组 ...
- 【Java8新特性】关于并行流与串行流,你必须掌握这些!!
写在前面 提到Java8,我们不得不说的就是Lambda表达式和Stream API.而在Java8中,对于并行流和串行流同样做了大量的优化.对于并行流和串行流的知识,也是在面试过程中,经常被问到的知 ...
- 记一次使用windbg排查内存泄漏的过程
一.背景 近期有一个项目在运行当中出现一些问题,程序顺利启动,但是观察一阵子后发现内存使用总量在很缓慢地升高, 虽然偶尔还会往下降一些,但是总体还是不断上升:内存运行6个小时候从33M上升到80M: ...
- PAT1080 MOOC期终成绩 (25分) ——同样参考了柳婼大神的代码及思路,在自己的代码上做了修改,还是很复杂
1080 MOOC期终成绩 (25分) 对于在中国大学MOOC(http://www.icourse163.org/ )学习“数据结构”课程的学生,想要获得一张合格证书,必须首先获得不少于200分 ...