Python开发中常见的10个陷阱你踩过几个(附解决方案)

Written by

in

文章目录
  • def append_to(element, to=[]): to.append(element) return to print(append_to(1)) # 输出: [1] print(append_to(2)) # 输出: [1, 2] 而不是预期的[2] 问题原因:默认参数在函数定义时就被创建,而不是每次调用时创建。 解决方案: def append_to(element, to=None): if to is None: to = [] to.append(element) return to
  • lst = [1, 2, 3, 4] for item in lst: if item % 2 == 0: lst.remove(item) print(lst) # 输出: [1, 3] 而不是预期的[1, 3] 看似正确,但如果列表连续有两个偶数元素,会出问题: lst = [1, 2, 4, 5] for item in lst: if item % 2 == 0: lst.remove(item) print(lst) # 输出: [1, 4, 5] 因为删除2后,4的索引变成了1被跳过了 解决方案:使用列表推导式或创建副本 lst = [x for x in lst if x % 2 != 0] # 或 for item in lst[:]: if item % 2 == 0: lst.remove(item)
  • funcs = [] for i in range(3): def func(): return i funcs.append(func) print([f() for f in funcs]) # 输出: [2, 2, 2] 而不是预期的[0, 1, 2] 问题原因:闭包中的变量是延迟绑定的。 解决方案:使用默认参数或functools.partial for i in range(3): def func(i=i): return i funcs.append(func)
  • a = [1, 2, 3] b = a c = [1, 2, 3] print(a == b) # True print(a is b) # True print(a == c) # True print(a is c) # False 解释:==比较值,is比较对象标识(内存地址)。
  • a = 256 b = 256 print(a is b) # True a = 257 b = 257 print(a is b) # False (在交互式环境中) 解释:Python会缓存小整数(-5到256),大整数每次创建新对象。
  • class A: x = 1 class B(A): pass class C(A): pass B.x = 2 print(A.x, B.x, C.x) # 输出: 1 2 1 A.x = 3 print(A.x, B.x, C.x) # 输出: 3 2 3 解释:类变量在继承时会被共享,除非子类显式覆盖。
  • a = “hello” b = “hello” print(a is b) # True a = “hello world” b = “hello world” print(a is b) # False (取决于实现) 解释:Python会对短字符串进行驻留优化,但不要依赖这种行为。
  • gen = (x for x in range(3)) print(list(gen)) # [0, 1, 2] print(list(gen)) # [] 因为生成器已耗尽 解决方案:如果需要多次使用,可以转换为列表或重新创建生成器。
  • lst = [1, [2, 3]] lst2 = lst.copy() lst2[1][0] = 4 print(lst) # [1, [4, 3]] 原始列表也被修改了 解决方案:需要深拷贝时使用copy.deepcopy import copy lst2 = copy.deepcopy(lst)
  • def func(): try: return 1 finally: return 2 print(func()) # 输出: 2 解释:finally中的return会覆盖try中的return。 到此这篇关于Python开发中常见的10个陷阱你踩过几个(附解决方案)的文章就介绍到这了,更多相关Python开发常见陷阱内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 您可能感兴趣的文章: 使用Python时要注意的十大陷阱汇总 Python中如何避免默认参数的陷阱 Python编程新手必知的十个避免代码陷阱秘诀 Python中的一些陷阱与技巧小结 Python新手最容易踩的坑及避坑指南
  • 目录
    • 1. 可变默认参数
    • 2. 循环中修改列表
    • 3. 闭包变量绑定
    • 4. == 和 is 的区别
    • 5. 整数缓存问题
    • 6. 类变量和实例变量
    • 7. 字符串驻留
    • 8. 生成器只能遍历一次
    • 9. 浅拷贝与深拷贝
    • 10. try-except中的return

    作为一门简洁优雅的语言,Python深受开发者喜爱。然而,即使是经验丰富的Python开发者,也难免会遇到一些"坑"。本文将介绍Python中10个最常见的陷阱,帮助大家避免这些错误,写出更健壮的代码。

    def append_to(element, to=[]):
        to.append(element)
        return to
    
    print(append_to(1))  # 输出: [1]
    print(append_to(2))  # 输出: [1, 2] 而不是预期的[2]
    

    问题原因:默认参数在函数定义时就被创建,而不是每次调用时创建。

    解决方案:

    def append_to(element, to=None):
        if to is None:
            to = []
        to.append(element)
        return to
    

    lst = [1, 2, 3, 4]
    for item in lst:
        if item % 2 == 0:
            lst.remove(item)
    print(lst)  # 输出: [1, 3] 而不是预期的[1, 3]
    

    看似正确,但如果列表连续有两个偶数元素,会出问题:

    lst = [1, 2, 4, 5]
    for item in lst:
        if item % 2 == 0:
            lst.remove(item)
    print(lst)  # 输出: [1, 4, 5] 因为删除2后,4的索引变成了1被跳过了
    

    解决方案:使用列表推导式或创建副本

    lst = [x for x in lst if x % 2 != 0]
    # 或
    for item in lst[:]:
        if item % 2 == 0:
            lst.remove(item)
    

    funcs = []
    for i in range(3):
        def func():
            return i
        funcs.append(func)
        
    print([f() for f in funcs])  # 输出: [2, 2, 2] 而不是预期的[0, 1, 2]
    

    问题原因:闭包中的变量是延迟绑定的。

    解决方案:使用默认参数或functools.partial

    for i in range(3):
        def func(i=i):
            return i
        funcs.append(func)
    

    a = [1, 2, 3]
    b = a
    c = [1, 2, 3]
    
    print(a == b)  # True
    print(a is b)  # True
    print(a == c)  # True
    print(a is c)  # False
    

    解释:==比较值,is比较对象标识(内存地址)。

    a = 256
    b = 256
    print(a is b)  # True
    
    a = 257
    b = 257
    print(a is b)  # False (在交互式环境中)
    

    解释:Python会缓存小整数(-5到256),大整数每次创建新对象。

    class A:
        x = 1
        
    class B(A):
        pass
        
    class C(A):
        pass
    
    B.x = 2
    print(A.x, B.x, C.x)  # 输出: 1 2 1
    
    A.x = 3
    print(A.x, B.x, C.x)  # 输出: 3 2 3
    

    解释:类变量在继承时会被共享,除非子类显式覆盖。

    a = "hello"
    b = "hello"
    print(a is b)  # True
    
    a = "hello world"
    b = "hello world"
    print(a is b)  # False (取决于实现)
    

    解释:Python会对短字符串进行驻留优化,但不要依赖这种行为。

    gen = (x for x in range(3))
    print(list(gen))  # [0, 1, 2]
    print(list(gen))  # [] 因为生成器已耗尽
    

    解决方案:如果需要多次使用,可以转换为列表或重新创建生成器。

    lst = [1, [2, 3]]
    lst2 = lst.copy()
    lst2[1][0] = 4
    print(lst)  # [1, [4, 3]] 原始列表也被修改了
    

    解决方案:需要深拷贝时使用copy.deepcopy

    import copy
    lst2 = copy.deepcopy(lst)
    

    def func():
        try:
            return 1
        finally:
            return 2
    
    print(func())  # 输出: 2
    

    解释:finally中的return会覆盖try中的return。

    到此这篇关于Python开发中常见的10个陷阱你踩过几个(附解决方案)的文章就介绍到这了,更多相关Python开发常见陷阱内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

    您可能感兴趣的文章:

    • 使用Python时要注意的十大陷阱汇总
    • Python中如何避免默认参数的陷阱
    • Python编程新手必知的十个避免代码陷阱秘诀
    • Python中的一些陷阱与技巧小结
    • Python新手最容易踩的坑及避坑指南

    站内搜索