当前位置:首页>python>Python 语法的 5 个反直觉设计,知道的都是老手

Python 语法的 5 个反直觉设计,知道的都是老手

  • 2026-10-11 07:47:16
Python 语法的 5 个反直觉设计,知道的都是老手

入职第一周,我以为 Python 是最简单的语言。直到 SQL 查询前面多了一堆空格、装饰器在导入时就偷偷连了数据库。

才发现这门简单语言,挖坑的姿势相当刁钻。


坑 1:多行字符串的缩进

先看这段代码,猜猜输出是什么:

def get_sql():    query = """    SELECT *    FROM users    WHERE active = 1    """    return queryprint(repr(get_sql()))

你以为是没有前导空格?

实际上输出的是每行前面有 4 个空格。

三引号字符串会保留所有空白字符,包括缩进产生的空格。在函数内部使用多行字符串时,代码缩进会变成字符串内容的一部分。用 textwrap.dedent() 可以去掉公共前导空白。

正确写法:

import textwrapdef get_sql():    query = textwrap.dedent("""\    SELECT *    FROM users    WHERE active = 1    """)    return query.strip()

踩坑现场:SQL 查询拼接出来的语句前面多了一堆空格,数据库报语法错误。


坑 2:装饰器执行时机

先看这段代码,猜猜输出是什么:

def register(func):    print(f'注册: {func.__name__}')    return func@registerdef hello():    print('hello')print('--- 程序开始 ---')

你以为是先打印程序开始?

实际上输出的是先打印注册: hello。

装饰器在函数定义时就执行,不是在函数调用时。@register 等价于 hello = register(hello),这行代码在模块加载时就运行了。如果装饰器做了网络请求、数据库连接等操作,导入模块就会触发这些副作用。

正确写法:

# 如果需要延迟执行,装饰器只做标记REGISTRY = []def register(func):    REGISTRY.append(func)  # 只记录,不执行    return func@registerdef hello():    print('hello')# 后续统一处理def run_all():    for func in REGISTRY:        func()

踩坑现场:测试框架的装饰器在导入时就执行了初始化,导致测试环境还没配置好就开始连数据库。


坑 3:海象运算符的限制

报错信息:SyntaxError: invalid syntax

出问题的代码:

# 不能用在普通赋值位置(x := 10)y := 20  # 这个不行

海象运算符 := 只能在表达式中使用,不能作为独立的赋值语句。它的设计目的是在 if、while 等需要表达式的地方同时赋值和判断。

修复方法:

# 正确用法:在表达式中赋值if (n := len(data)) > 10:    print(f'数据量 {n} 条')# while 中也很好用while (line := f.readline()):    process(line)

坑 4:缩进混用空格和 Tab

报错信息:TabError: inconsistent use of tabs and spaces in indentation

出问题的代码:

def foo():    if True:        print('spaces')print('tab')

Python 3 不允许混用空格和 Tab 作为缩进。这个问题在复制粘贴代码时特别容易发生,因为不同编辑器对 Tab 的显示宽度不同。最佳实践是配置编辑器把 Tab 转换为 4 个空格。

修复方法:

# 配置编辑器:Tab 自动转为 4 空格def foo():    if True:        print('spaces')        print('also spaces')

坑 5:链式比较的隐含 and

最后来一道送分题,这段代码输出什么:

print(1 < 2 < 3)print(1 < 2 > 0)print(1 == 1 in [1, 2])

看起来应该是 True True True,实际也是 True True True。

Python 的链式比较会展开为 and 连接:1 < 2 < 3 等于 1 < 2 and 2 < 3。这个特性很强大,但混合不同类型的比较时容易让人困惑。特别是 1 == 1 in [1,2] 不是 (1 == 1) in [1,2],而是 1 == 1 and 1 in [1,2]。


以上 5 个坑,挑一个今天就记牢。写代码不怕慢,怕的是跑出来结果不对。

你还知道哪些类似的坑?评论区交流一下。


关于作者

写了 10 年 Python,赶上了机器学习的热潮,又撞上了大模型的浪头,每次以为学明白了,行业又变了一次。把自己踩过的坑、走过的弯路、看过的热闹,说给还在路上的人听。

关注「鲁叶的Python」,一起穿越迷茫期。

最新文章

随机文章