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()
posted @ 2020-06-18 18:49  AndreasZhou  阅读(519)  评论(3编辑  收藏  举报