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用来写写小脚本,爬虫程序什么的,没什么问题. 不过,一旦用来开发稍 ...
随机推荐
- Magicodes.IE 2.2发布
Magicodes.IE 导入导出通用库,支持Dto导入导出以及动态导出,支持Excel.Word.Pdf.Csv和Html.已加入NCC开源组织. Magicodes.IE 2.0发布 Magico ...
- 关于VMware问题:无法获得 VMCI 驱动程序的版本: 句柄无效。驱动程序“vmci.sys”的版本不正确
有的童鞋可能安装虚拟机时出现了下边这样的错误,莫慌,下面咋们来解决!!! 1.首先,找到你的安装虚拟机的目录下有一个.vmx的文件 找到这个文件,用编辑器打开,将该值改为FALSE即可!
- 要小心 JavaScript 的事件代理
我们知道,如果给 form 里面的 button 元素绑定事件,需要考虑它是否会触发 form 的 submit 行为.除此之外,其它场合给 button 元素绑定事件,你几乎不用担心这个事件会有什么 ...
- [Unity2d系列教程] 001.引用外部DLL - C#
众所周知,Unity可以支持多种语言开发, C#, JS, Boo三种方式的开发, 能够很方便的集成一些外部插件,以便调用现有的动态链接库.学过C#的都知道C#可以生成一个dll供给其他的程序调用.那 ...
- 深入浅出Spring MVC
摘要 本文旨在详细分析SpringMVC工作原理以及作为开发者如何基于SpringMVC做扩展.因为SpringMVC分析的文章比较多,所以本文重点讲解如何利用SpringMVC的扩展点实现我们的需求 ...
- JS代码静态分析及挖掘
JavaScript 已经成为现代 Web 浏览器开发中最普遍的技术之一.使用客户端 JavaScript 框架(如 AngularJS,ReactJS 和 Vue.js)构建的应用程序已向前端输送了 ...
- 舵机MX-64AR与MX-28AR驱动
背景:硬件采用485通信,在tb上采购的无需收发控制的串口转RS485模块(485通信为半双工,一般情况需要控制收发模式).在使用该模块后,即可完全使用一个普通地串口来对485通信的舵机进行操作. 模 ...
- Rocket - tilelink - AtomicAutomata
https://mp.weixin.qq.com/s/O7VTHqpCFNJQi3EpucXkIw 简单介绍AtomicAutomata的实现.(细节问题太多,恕不完全表述.) 1. ...
- 集合遍历元素的3种方法:for、foreach、迭代器iterator
1.for循环方式(Set集合不能使用,因为Set是无序的没有索引) for (int i = 0; i < list.size(); i++) { Object o = list.get(i) ...
- Java实现 LeetCode 365 水壶问题
365. 水壶问题 有两个容量分别为 x升 和 y升 的水壶以及无限多的水.请判断能否通过使用这两个水壶,从而可以得到恰好 z升 的水? 如果可以,最后请用以上水壶中的一或两个来盛放取得的 z升 水. ...