python语法

列表

list可变,tuple不变

tuple定义

1
a = (1,)

条件判断

1
if x:

Python 会自动判断“真假”。

这些通常是假:

1
2
3
4
5
6
7
8
False
0
0.0
None
""
[]
{}
set()

其他大多数对象是真。

模式匹配

match

1
2
3
4
5
6
7
8
9
10
11
12
13
age = 15

match age:
case x if x < 10://age赋值给x并进行判断
print(f'< 10 years old: {x}')
case 10:
print('10 years old.')
case 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18:
print('11~18 years old.')
case 19:
print('19 years old.')
case _://和default一样
print('not sure.')

还可以直接拆对象列表

1
2
3
4
5
6
7
8
9
10
11
12
args = ["gcc", "hello.c", "world.c"]

match args:
case ["gcc"]:
print("没有源文件")

case ["gcc", file, *files]:
print(file)
print(files)

case ["clean"]:
print("clean")

循环

1
2
for i in range(10)://从0到9
print(i)
1
2
3
4
5
6
7
8
9
10
11
for x in iterable:
...

for i in range(10):
...

while condition:
...

break
continue

dict

1
2
3
Python dict
≈ Java HashMap
≈ C++ unordered_map
1
2
3
>>> d.get('Thomas')//不定义则返回None
>>> d.get('Thomas', -1)//查找失败自定义返回-1
-1

set

set和dict的唯一区别仅在于没有存储对应的value

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
定义
s = {1, 2, 3}
s = set([1,2,3])

s.add(4)
s.remove(2)

1 in s

>>> s1 = {1, 2, 3}
>>> s2 = {2, 3, 4}
>>> s1 & s2//交集
{2, 3}
>>> s1 | s2//并集
{1, 2, 3, 4}

set可以看成数学意义上的无序和无重复元素的集合

Tips:

空 set定义为:s = set()

不是:s = {}

因为:{}表示空字典。

可变/不可变对象

“可变 / 不可变” ≈ 对象本身能不能原地修改。

函数

可以返回多个值

1
2
3
4
def position():
return 10, 20

x, y = position()

看起来是两个返回值,其实:

1
return (10, 20)

返回的是 tuple。

所以理解为:

1
2
3
Python 多返回值
=
返回 tuple + 解包

参数

默认参数

定义默认参数要牢记一点:默认参数必须指向不变对象

1
2
3
def add_end(L=[]):
L.append('END')
return L
1
2
3
4
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']

避免这种情况,让L指向不变对象

1
2
3
4
5
def add_end(L=None):
if L is None:
L = []
L.append('END')
return L

位置参数靠位置,关键字参数靠名字。

可变参数

可以直接使用*number

1
2
3
4
5
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum

如果传入list或者tuple,也一样

1
2
3
>>> nums = [1, 2, 3]
>>> calc(*nums)
14

关键字参数

可传入参数名和参数值来组装成dict

传入的a=1,b=2这种形式是关键字参数

**kw是可变关键字参数,专门接收额外的关键字参数

1
2
3
4
def person(name, age, **kw):
print('name:', name,
'age:', age,
'other:', kw)
1
2
>>> person('Adam', 45, gender='M', job='Engineer')
name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}

**extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra。

命名关键字参数

过滤不想接收的关键字参数

1
2
def person(name, age, *, city, job):
print(name, age, city, job)

如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:

1
2
def person(name, age, *args, city, job):
print(name, age, args, city, job)
1
2
3
4
def f(a, *, b):
↑
单独的 *:
后面只能是关键字参数
1
2
3
4
5
def f(a, *args, b):
↑
*args:
既收集额外位置参数,
又自然把后面的 b 变成命名关键字参数

参数定义顺序

必选参数、默认参数、可变参数、命名关键字参数和关键字参数。

1
2
3
4
5
6
7
定义函数时:
*args → 收集位置参数,变成 tuple
**kwargs → 收集关键字参数,变成 dict

调用函数时:
*容器 → 拆成多个位置参数//所以传入的可以是(1,2,3)也可以是[1,2,3]
**dict → 拆成多个关键字参数

小结

Python的函数具有非常灵活的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数。

默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误!

要注意定义可变参数和关键字参数的语法:

*args是可变参数,args接收的是一个tuple;

**kw是关键字参数,kw接收的是一个dict。

以及调用函数时如何传入可变参数和关键字参数的语法:

可变参数既可以直接传入:func(1, 2, 3),又可以先组装list或tuple,再通过*args传入:func(*(1, 2, 3));

关键字参数既可以直接传入:func(a=1, b=2),又可以先组装dict,再通过**kw传入:func(**{'a': 1, 'b': 2})。

使用*args和**kw是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。

命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。

定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符*,否则定义的将是位置参数。

切片

从序列里按“起点、终点、步长”取出一部分。

基本语法:

1
序列[start:end:step]

其中:

  • start:从哪里开始,包含
  • end:到哪里结束,不包含
  • step:每隔几个取一个
1
2
3
L = ['A', 'B', 'C', 'D', 'E']
L[1:3]
# ['B', 'C']

要点

1
2
3
[:end]     # 从开头到 end 前
[start:] # 从 start 到末尾
[:] # 全部

常见写法可以这样记:

1
2
3
4
5
6
L[:3]      # 前3个
L[2:] # 从索引2开始一直到最后
L[:] # 全部元素,相当于复制一份
L[::2] # 每隔一个取一个
L[::-1] # 倒序
L[-2:] # 最后2个

切片不只用于 list

tuple、str 也可以:

1
2
3
4
5
6
7
>>> (0, 1, 2, 3, 4, 5)[:3]
(0, 1, 2)

>>> 'ABCDEFG'[:3]
'ABC'
>>> 'ABCDEFG'[::2]
'ACEG'
1
2
3
4
5
6
7
8
9
10
11
12
1. 切片格式:[start:end:step]

2. start 包含,end 不包含
[1:4] → 取 1、2、3

3. start/end 可以省略
[:3] 前3个
[3:] 从3到最后

4. step 可以控制间隔和方向
[::2] 每隔一个取
[::-1] 倒序

迭代

默认情况下,dict迭代的是key。

如果要迭代value,可以用for value in d.values(),

如果要同时迭代key和value,可以用for k, v in d.items()。

列表生成式

1
[要放进列表的东西 for 元素 in 集合 if 筛选条件]
1
2
3
4
5
>>> [x * x for x in range(1, 11)]

>>> L = []
>>> for x in range(1, 11):
... L.append(x * x)

两个生成的都是

1
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

for前面的if … else是表达式,而for后面的if是过滤条件,不能带else

顺序是:先筛选,再处理,再放入列表。

比如:

1
[x * 2 for x in range(10) if x % 2 == 0]

执行思路是:

1
2
3
for x in range(10):
if x % 2 == 0: # 先筛选
result.append(x * 2) # 再处理并放入列表

列表生成器

创建L和g的区别仅在于最外层的[]和(),

L是一个list

g是一个generator,保存的是算法,可使用next(g)调用下一个元素

也可使用for循环

1
2
3
4
5
6
7
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b//直接使用yield就行,每次返回这个元素,next()继续从这个位置构造
a, b = b, a + b
n = n + 1
return 'done'
1
2
3
4
5
6
7
8
9
>>> for n in fib(6):
... print(n)
...
1
1
2
3
5
8

例题 杨辉三角

1
2
3
4
5
def triangles():#yield list t
t = [1]
while 1:
yield t
t = [1] + [t[i] + t[i+1] for i in range(len(t) - 1)] + [1]

迭代器

是数据流,也就是生成器还有带yield的生成器函数才是迭代器,未知长度只能不断通过next调用

虽然,如list、tuple、dict、set、str等可迭代

1
2
3
4
5
6
7
8
9
10
11
>>> from collections.abc import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

但是不是迭代器

可以使用isinstance()判断一个对象是否是Iterator对象:

1
2
3
4
5
6
7
8
9
>>> from collections.abc import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False

生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。