Python从入门到入土之奇技淫巧(一)

· · 科技·工程

众所周知 Python 的语法糖又多又甜,可以有效提高可读性和编程效率。本文旨在快速生动地向 Python 初学者介绍一些几乎独属于 Python 的语法糖和实用技巧,让你感受到 Python 的魅力。

它会告诉你一切的

# 获取属性和方法
print(dir('Hello World'))
print(dir(str))
# 获取文档(建议在REPL环境下使用)
print(help('Hello World'))
print(help(str))

输入

:::warning{open} 任何情况下input函数都会读入整行字符串。

# 输入:Hello World
print(input())
# 输出:Hello World

:::

# 读入空格分隔的多个整数
a, b, c = map(int, input().split())
# 读入逗号分隔的多个整数
a, b, c = map(int, input().split(','))
# 读入空格分隔的列表
l = list(map(int, input().split()))

输出

a = [1, 2, 3, 4, 5]
print(*a)  # 1 2 3 4 5
print(', '.join(a))  # 1, 2, 3, 4, 5
print(*a, sep=', ')  # 1, 2, 3, 4, 5
print(1, 2, 3)  # 1 2 3

print('no', end=' ')
print('break')
# no break

print()  # 输出空行

## 内置数据结构

```python
l = [1, 2, 3]  # 列表(可变)
t = (1, 2, 3)  # 元组(不可变)
m = {'Alice': 1, 'Bob': 2}  # 字典
empty = {}  # 空字典
s = {1, 2, 3}  # 集合
fai = set()  # 空集

各种推导式

# 列表推导式
l1 = [i for i in range(10)]
print(f1)  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 条件
l2 = [i for i in l1 if i % 2 == 0]
print(l2)  # [0, 2, 4, 6, 8]
# 集合推导式
s = {i for i in range(10)}
print(s)  # {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
# 字典推导式
m = {i: 2 * i for i in range(10)}
print(m)  # {0: 0, 1: 2, 2: 4, 3: 6, 4: 8, 5: 10, 6: 12, 7: 14, 8: 16, 9: 18}

for-else/while-else

鲜为人知的猎奇语法。

for 和 while 语句后可以接 else,else 中的内容将在循环没有通过 break 语句结束时执行。

:::error[Bad 👎]{open}

a = [2, 4, 6, 8, 10]
flag = True
for i in a:
    if i % 2 != 0:
        print('No')
        flag = False
        break
if flag:
    print('Yes')
# Yes

::: :::success[Good 👍]{open}

a = [2, 4, 6, 8, 10]
for i in a:
    if i % 2 != 0:
        print('No')
        break
else:
    print('Yes')
# Yes

::: :::success[Better 👍👍👍]{open}

a = [2, 4, 6, 8, 10]
print('Yes' if all(map(lambda x: x % 2 == 0, a)) else 'No')
# Yes

:::

i = 0
while i < 100:
    i += 1  # Python 没有自增运算(
    if i >= 50:
        print('stop')
        break
else:
    print('???')

# stop

元组解包

:::error[Bad 👎]{open}

t = (1, 2, 3)
a = t[0]
b = t[1]
c = t[2]

::: :::success[Good 👍]{open}

t = 1, 2, 3  # 括号可省略
a, b, c = t

:::

:::error[Bad 👎]{open}

c = a
a = b
b = c
del c  # 释放c

::: :::success[Good 👍]{open}

a, b = b, a

:::

星号表达式

由于 Python 没有指针,前置*号用于解包可迭代对象:

def f(a, b, c):
    print(f'{a = }, {b = }, {c = }')
f(1, 2, 3)  # a = 1, b = 2, c = 3
t = 1, 2, 3
print(*t)  # 1 2 3
f(*t)  # a = 1, b = 2, c = 3

解包中可以利用星号表达式提取多个元素

t = 1, 2, 3, 4, 5
a, *_, b = t
print(a, _, b)  # 1 [2, 3, 4] 5

大数分隔符

a = 1_145_141_919_810
b = 114514_1919810

等价于:

a = 1145141919810
b = 1145141919810

格式化字符串

C 风格

print('%s %d %.2f' % ('test', 114514, 1919810))  # test 114514 1919810.00

格式化修饰符语法

很重要,也是简洁易懂的 Python 中最复杂的语法之一,用于控制格式,f-string 与 str.format 共用。

案例参考 f-string 章节。

format_spec     ::=  [[fill]align][sign]["z"]["#"]["0"][width][grouping_option]["." precision][type]
fill            ::=  <any character>
align           ::=  "<" | ">" | "=" | "^"
sign            ::=  "+" | "-" | " "
width           ::=  digit+
grouping_option ::=  "_" | ","
precision       ::=  digit+
type            ::=  "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"

:::align{center} ^ Python 文档中的 format spec 语法 :::

名称 取值 < 含义
fill 任意字符 < 用于填充空白的字符
align < < 左对齐
^ ^ < 居中
^ > < 右对齐
^ = < 右对齐,但符号居左
sign + < 强制正数使用正号
^ - < 负数使用负号,默认
^ (空格) < 用空格代替正号
z 可选 < 将 -0 改为 0,仅对浮点数生效
# 可选 < 输出当前进制的前缀(见 type)
0 可选 < 前导零
width 正整数 < 对齐的最小宽度
grouping_option _, < 千位分隔符,只支持这两种
"." precision 正整数 < 保留几位小数
type 字符串 s 默认,没卵用
^ 整数 b 二进制
^ ^ c ASCII 码转字符
^ ^ d 十进制(默认),无前缀
^ ^ o 八进制
^ ^ x 十六进制
^ ^ X 大写(含前缀)十六进制
^ 浮点数 e 强制使用科学计数法
^ ^ E 同上,但后缀大写
^ ^ f 输出小数
^ ^ F 同上,但 nan 和 inf 大写
^ ^ g 大数使用科学计数法
^ ^ G 同上,但 nan、inf 后缀大写
^ ^ % 百分比

修饰符可以通过变量读取。

a = '^'
print(f'{114514:{a}{a}20}')  # ^^^^^^^114514^^^^^^^
print('{:{a}{a}20}'.format(114514, a='^'))  # ^^^^^^^114514^^^^^^^

str.format

print('{}+{}={}'.format(114514, 1919810, 114514 + 1919810))  # 114514+1919810=2034324
print('{0}+{0}={1}'.format(1, 2))  # 1+1=2
print('{alice}{bob:.2f}'.format(alice=114514, bob=1919810))  # 1145141919810.00

f-string

推荐使用。

相信你根本记不住这么多语法,没关系,最常用的也就这三行:

print(f'{114514:010}')  # 0000114514
print(f'{114514:.2f}')  # 114514.00
print(f'{114.514:.0f}')  # 115

f-string 特有的按原样输出表达式:

print(f'{114514 + 1919810 = }')  # 114514 + 1919810 = 2034324

海象运算符

m = {'Alice': 1, 'Bob': 2}
k = input()
if v := m.get(k):
    print(v)
else:
    print('nope')  # v is None

引用

def f():
    return f
# 以下代码输出均为 <function f at 十六进制地址>
print(f())
print(f()())
print(f()()()()()()()()()())

:::warning{open} Python 中的对象常常通过引用传递,在使用时要多加小心。 :::

:::error{open}

a = [[]] * 10
print(a)  # [[], [], [], [], [], [], [], [], [], []]
a[0].append(1)
print(a)  # [[1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]
# ???

:::

:::success[正确]{open}

a = [[] for i in range(10)]
print(a)  # [[], [], [], [], [], [], [], [], [], []]
a[0].append(1)
print(a)  # [[1], [], [], [], [], [], [], [], [], []]
# Wonderful Answer!

:::

三元运算符

flag = True
print('Yes' if flag else 'No')  # Yes

匿名函数

f = lambda x, y: x if x > y else y
print(f(1, 2))  # 2

排序

a = list(map(int, '1145141919810'))

a.sort()  # 会更改a
print(a)  # [0, 1, 1, 1, 1, 1, 1, 4, 4, 5, 8, 9, 9]

a.sort(key=lambda x: -x)  # 排序关键字,注意不是比较函数
print(a)  # [9, 9, 8, 5, 4, 4, 1, 1, 1, 1, 1, 1, 0]

b = sorted(a)  # 不更改原列表
print(a)  # [9, 9, 8, 5, 4, 4, 1, 1, 1, 1, 1, 1, 0]
print(b)  # [0, 1, 1, 1, 1, 1, 1, 4, 4, 5, 8, 9, 9]