python3--中一些常见的坑(机制上的问题)

发布时间:2018-03-26 19:28:04编辑:Run阅读(3557)

    python中

    is,==,id 的意思

    == :数值的比较

    is :内存地址的比较

    id :查看内存地址


    list(列表)中存在的一些坑

    重点:在循环一个列表时,最好不要进行删除的动作(一旦删除,索引会随之改变),容易错误。


    将下面列表中索引为奇数的元素删除

    li = ['python', 'php', 'java', 'ios', 'C++', 'C', 'Go']

    错误的方法

    li = ['python', 'php', 'java', 'ios', 'C++', 'C', 'Go']
    for i in li:
        s = li.index(i)
        if s % 2 == 1:
            li.pop(s)
    print(li)

    执行结果

    ['python', 'java', 'ios', 'C', 'Go']

    很明显,这结果跟我们想的不一样

    正确的方法:

    1.利用切片的方式

    del li[1::2]
    print(li)

    执行结果为

    ['python', 'java', 'C++', 'Go']

    2.将偶数添加到新列表,最后将原始列表覆盖

    li_new =[]
    for i in li:
        if li.index(i) % 2 == 0:
            li_new.append(i)
    li = li_new
    print(li)

    执行结果

    ['python', 'java', 'C++', 'Go']

    3.如果想要在循环列表的时候,删除呢?

    倒着删除就可以了

    for i in range(len(li)-1, -1, -2):
        print(li[i])

    执行结果

    Go

    C++

    java

    python

    倒着删除不影响前面列表的索引顺序

    这个答案才是正确的,因为每次列表删除后,原列表的索引值都会改变,导致结果不一样


    dict(字典)中一些错误的使用方法

    重要:在循环列表或者字典的时候,千万不要做添加或者删除操作

    dic = dict.fromkeys('abc', 'sam') # 'abc'为一个可迭代对象
    print(dic)

    执行结果

    {'c': 'sam', 'a': 'sam', 'b': 'sam'}


    这里有个坑

    dic = dict.fromkeys([1, 2, 3], [])
    print(dic)

    执行结果

    {1: [], 2: [], 3: []}

    给上面的空列表添加一元素

    dic[1].append('你好')

    print(dic)

    执行结果

    {1: ['你好'], 2: ['你好'], 3: ['你好']}

    上面,dic里面的3个列表,在内存中对应的是同一个列表,所以里面的内容相同


    例2

    dic = {'k1':'value1','k2':'value2','name':'sam'}

    将dic字典中含有k元素的键,对应的键值对删除

    错误的方法

    for i in dic.keys():
        if 'k' in i:
            del dic[i]
    print(dic)

    执行报错

    RuntimeError: dictionary changed size during iteration

    意思就是,在循环字典过程中,不允许改变字典

    不能删除,那么尝试一下能否添加吧

    count = 0

    for i in dic:

        dic[i + str(count)] = dic[i]

        count += 1

    上面代码,第一次添加k10,第二次添加k21

    执行代码也报错

    RuntimeError: dictionary changed size during iteration

    那么如果一定要添加,怎么做?

    先将含有k的键值对,添加到列表,然后循环列表,删除字典的key

    s = []
    for i in dic:
        if 'k' in i:
            s.append(i)
    for x in s:
        del dic[x]
    print(dic)

    执行结果

    {'name': 'sam'}


    set集合

    数据类型:

    不重复,无序,它里面的元素是可哈希的,他本是不可哈希的,他不能作为字典的key

    去重有2种方法。1,用集合,2.用算法

    set的作用:

    1,去重

    2,数据关系的测试

    例子

    li = [11, 11, 22, 22, 33, 33, 33, 44]
    li = list(set(li))
    print(li)

    执行结果为

    [33, 11, 44, 22]

    列表的去重,直接转换为集合,就可以了

    set集合的用法

    add 增

    s1 = set()
    s1.add('sam')
    print(s1, type(s1))

    执行结果

    {'sam'}


    update迭代增加

    s1 = set()
    s1.add('sam')
    s1.update('abc')
    print(s1)


    2.set 删

    set1 = {'sam', 'tom', 'zhangsan', 'lisi', 'wangwu'}
    set1.remove('sam') #删除一个指定元素
    print(set1)
    set1.pop()  #随机删除一个元素
    print(set1)
    set1.clear() #清空集合
    print(set1)
    del set1    #删除集合

    pop随机删除方法有返回值

    set()表示一个空集合

    集合没有改的方法,查只能for循环

    for i in set1:

        print(i)

    执行结果

    tom

    sam

    lisi

    zhangsan

    wangwu


    set关系测试

    交集& ,intersection

    set1 = {1, 2, 3, 4, 5}
    set2 = {4, 5, 6, 7, 8}
    print(set1 & set2)
    print(set1.intersection(set2))

    执行输出

    {4, 5}

    {4, 5}


    并集 |,union

    print(set1 | set2)

    print(set1.union(set2))

    执行输出

    {1, 2, 3, 4, 5, 6, 7, 8}

    {1, 2, 3, 4, 5, 6, 7, 8}


    反交集 ^  symmetric_difference

    print(set1 ^ set2)

    print(set1.symmetric_difference(set2))

    执行输出

    {1, 2, 3, 6, 7, 8}

    {1, 2, 3, 6, 7, 8}


    差集

    print(set1 - set2)

    执行输出

    {1, 2, 3}


    子集 issubset

    例子

    set1 = {1, 2, 3}
    set2 = {1, 2, 3, 4, 5, 6}
    print(set1.issubset(set2))

    执行结果

    True


    超集

    print(set2.issuperset(set1)) #set2是set1的超集

    执行结果

    True


    将集合转换为可哈希的类型,可以作为字典的key

    set1 = {'barry', 'tom'}
    set2 = frozenset(set1)
    print(set2)

    执行结果为

    frozenset({'tom', 'barry'})


    深浅copy

    l1 = [1, 2, 3]
    l2 = l1
    l2.append(111)
    print(l1, l2)

    执行结果,结果是一样的

    [1, 2, 3, 111] [1, 2, 3, 111]

    对于赋值运算,指向的是同一个内存地址,字典,列表,集合都一样


    copy不是指向同一个,在内存中开辟了一个内存空间

    l1 = [1, 2, 3]
    l2 = l1.copy()
    l1.append(111)
    print(l1, l2)
    print(id(l1), id(l2)) #打印出内存地址

    执行结果

    [1, 2, 3, 111] [1, 2, 3]

    2230811766152 2230811765256

    例子2

    l1 = [1, 2, [1, 2, 3], 4]
    l2 = l1.copy()
    l1[2].append(666)
    print(l1)
    print(l2)

    执行结果

    [1, 2, [1, 2, 3, 666], 4]

    [1, 2, [1, 2, 3, 666], 4]

    重点:对于浅copy来说,第一层创建的是新的内存地址,而从第二层开始,指向的都是同一个内存地址


    深copy,需要导入一个模块copy

    import copy
    l1 = [1, 2, [1, 2, 3], 4]
    l2 = copy.deepcopy(l1)
    l1[2].append(666)
    print(l1)
    print(l2)

    执行结果

    [1, 2, [1, 2, 3, 666], 4]

    [1, 2, [1, 2, 3], 4]

    重点:

    深copy,两个是完全独立的,改变任意一个的任何元素(无论多少层),另一个绝对不会改变

    浅copy,第一层是新的,从第二次开始,共用一个


    python开发面试题:

    下面的例子,l2是深copy还是浅copy

    l1 = [1, 2, 3, [22, 33]]
    l2 = l1[:]
    l1[3].append(666)
    print(l2)

    对于切片来说,它是执行了浅copy

    总结,切片就是浅copy


    编码补充

    python内部编码,使用unicode

    s = 'sam'

    s1 = s.encode('utf-8') # unicode ---> utf-8

    s2 = s.encode('gbk') # unicode ---> gbk

    utf-8转换成unicode

    s3 = s1.decode('utf-8')

    print(s3)

    sam

    blob.png


    重点:utf-8和gbk不能直接互相转化,必须通过unicode才可以

    例子

    s = '你好'
    s1 = s.encode('gbk') #unicode转化为gbk
    s2 = s1.decode('gbk') #gbk转化为unicode
    s2.encode('utf-8') #unicode转化为utf-8
    print(s2)

    执行为

    你好

关键字