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]