python常见错误2

2021-01-28  本文已影响0人  Chaweys

#coding=utf-8

#1、默认可变对象的赋值修改
def addElement(a,list1=[]):
    list1.append(a)
    return list1

print(addElement("菜鸟"))
print(addElement("菜鸟学python"))
'''
['菜鸟']
['菜鸟', '菜鸟学python']
'''


def addElement2(a,list1=""):
    list1=list1+a
    return list1
print(addElement2("菜鸟"))
print(addElement2("菜鸟学python"))
'''
菜鸟
菜鸟学python
'''

'''
总结:
上述两个函数addElement()和addElement2()得出的结果不同:
addElement():由于list1=[]属于python中的可变对象,因此只在函数被定义的时候才能被创建一次,所以在调用的时候都使用的创建好的同一个list列表
addElement2():由于list1=""属于python中的不可变对象,所以被调用时每次都是新的开辟内存地址存储该不可变对象

python不可变对象:int,string,float,tuple
python可变对象:  dict,list
'''



#2、浅拷贝和深拷贝
'''
浅拷贝只拷贝了父对象,子对象仍然引用同一个
深拷贝拷贝了父对象,子对象也一并拷贝
'''
import copy
dict1={"1":"a","2":["b1","b2","b3"],"3":"c","4":"d"}
dict2=copy.copy(dict1)
dict3=copy.deepcopy(dict1)

print("删除之前:")
print(dict1)
print(dict2)
print(dict3)
'''
{'2': ['b1', 'b2', 'b3'], '3': 'c', '1': 'a', '4': 'd'}
{'2': ['b1', 'b2', 'b3'], '3': 'c', '1': 'a', '4': 'd'}
{'2': ['b1', 'b2', 'b3'], '3': 'c', '1': 'a', '4': 'd'}
'''


print("删除之后:")
dict1["2"].remove("b1")
print(dict1)
print(dict2)
print(dict3)
'''
{'2': ['b2', 'b3'], '3': 'c', '1': 'a', '4': 'd'}
{'2': ['b2', 'b3'], '3': 'c', '1': 'a', '4': 'd'}
{'2': ['b1', 'b2', 'b3'], '3': 'c', '1': 'a', '4': 'd'}  因为dict3是子对象也进行了拷贝,所以删除原dict1的子对象值,dict3是不变的
'''



#3、善用迭代器
list1=[1,2,3,4,5]
list2=[]

def addlist(x):
    return x+1

#多行for循环实现
for i in range(len(list1)):
    list2.append(addlist(list1[i]))
print(list2)


#一行代码实现
print(list(addlist(i) for i in list1))
'''
因为列表是可迭代对象,所以可以直接for循环遍历
[2, 3, 4, 5, 6]
[2, 3, 4, 5, 6]
'''




#4、慎用全局变量-莫要随意修改
num=100
def changeNum():
    global num
    num += 23
changeNum()
print("全局变num:",num)
'''
结果:全局变num: 123
此时全局变量已被修改,此方式慎用,因为作为全局变量一般是可供其它函数共同使用,不可随意修改。
'''

num2=100
def changeNum2(n):
    num2=0
    num2+=n
    num2+=23
    return num2
num3=changeNum2(num2)
print("全局变量num2:",num2)
print(num3)
'''
结果:
全局变量num2: 100
123
此种方式全局变量并未更改,应该尽量使用传参的形式来使用全局变量,而不是直接修改全局变量
'''



#5、区分 is 和 == 的区别
# is看地址,=等号看值
list1=[1,2,3,4,5]
list2 = list1
print(list2 == list1)
print(list2 is list1)
print(id(list1))
print(id(list2))
'''
True
True
2152176174856
2152176174856
直接赋值,说明是两个对象list1和list2引用同一个内存地址
'''

list3=list1[:]
print(list3 == list1)
print(list3 is list1)
print(id(list3))
print(id(list1))
'''
True
False
2201184126728
2201184126536
先将list1切片再赋值给list3,中间过程是:
list1[:]切片后已经生成了新的对象开辟了新的内存地址,
此时赋值给list3就是新的内存地址
'''



#6、规避++和— —
num1=3
#num1++  SyntaxError: invalid syntax
#num2--  SyntaxError: invalid syntax
'''
因为python中整型是不可变对象,而++和--就是改变其自身的值,这与python的不可变对象原则不一致,所以语法错误
'''
num1+=1
num1-=1
'''
此种方式:先执行num1+1操作生成了新的对象开辟了新的内存地址,然后再赋值给原对象变量名num1,这样就达到了"修改"自身值的效果
'''


#7、作用域
li=[lambda :x for x in range(10)]
print(li[0]())
print(li[2]())
print(li[4]())
print(li[9]())
'''
9
9
9
9
解释:为什么结果都是9?
1、列表里是lambda匿名函数表达式,所以列表的每个元素都是一个函数
2、基本知识解释:函数在定义的时候并未分配内存空间来保存变量的值,只有在执行的时候才会分配空间保存标量的值。
3、所以该例子中没有执行print(li[0]())等时,变量x是没有值的,所以当去执行的时候才会为x赋值,但请注意:
   在执行函数是的时候,for寻循环其实早已结束,只是未给x变量赋值,所以当执行函数的时候才会为x变量赋值,此时x已经循环变成9
4、所以最后执行的结果都是9

作用域的基础知识:
python中遇到变量寻找作用域的顺序为:
本地作用域->外围作用域(函数体内)->全局作用域(单一文件内)->内置作用域
def class lambda等才会产生作用域
if for try等不会产生作用域
'''
#再例如:
li2=[lambda x:x+i for i in range(3)]
for f in li2:
    print(f(1))
'''
3
3
3
'''

#改进版:将自有参数i赋值,这样定义的i变量拥有变量值i
li3=[lambda x,i=i:x+i for i in range(3)]
for f in li3:
    print(f(1))
'''
1
2
3
'''

#8、列表删除
list1=[1,5,5,5,7]
def remove_list(n,li):
    for x in li:
        if x==n:
            li.remove(n)
    return li
print(remove_list(5,list1))
'''
结果:为什么删除5未删干净?
[1, 5, 7]
解释:
首先明确一点:列表元素被删除,列表是动态变化的。
第一次循环未匹配成功,列表仍为[1,5,5,5,7]
第二次循环索引1的值匹配成功并删除,列表变为[1,5,5,7],注意此时索引是循环到1
第三次循环索引2的值(注意此时用的列表是[1,5,5,7]),且从索引2开始的,所以索引2的值匹配成功删除
最后结果就变成[1,5,7]循环结束
'''
#改进:
list2=[1,5,5,5,7]
def remove_list2(n,li):
    length=len(li)
    dict1=dict(zip(range(length),li))            #将列表的每个值做一个标记形成字典{'0':'1','1':'5',...}
    return [v for k,v in dict1.items() if v!=n]  #dict1.items()为{(0,1),(1,5),...}
print(remove_list2(5,list2))

#9、字符串驻留
x='helloword'
y='hello'+'word'
print(id(x)==id(y))
#结果:True
详见:Python内置数据类型-字符串的驻留机制

#10、for循环的误区
for i in range(4):
    print(i)
    i=5
'''
结果:
0
1
2
3
i=5并不会影响循环,python中的for循环是如此工作的:range(4)生成的下一个元素被解包并赋值给目标列表变量i
'''

#11、生成器的执行时机
nums=[4,5,6]
g=(n for n in nums if nums.count(n)>0)
print(list(g))
#结果:[4, 5, 6]


nums=[4,5,6]
g=(n for n in nums if nums.count(n)>0)
nums=[6,7,8]
print(list(g))
'''
结果:[6]
为什么结果不能?
1、生成器中的in子句是在定义的时候执行
2、生成器中的if条件子句是在运行的时候执行
所以可以理解为:
g=(n for n in [4,5,6] if [6,7,8].count(n)>0)
'''
上一篇下一篇

猜你喜欢

热点阅读