Python修养2

Python修养2

元组

  • 一个元组由数个逗号分隔的值组成, 前后可加括号
  • ⚠️可认为是个指针vector数组, 数组元素不可修改, 不可增删元素, 指向的东西可以修改

具体操作

定义:

1
t=1,3.14,[1,'hello']

取值:

1
2
3
4
5
6
print(t[2])
# 可修改其中的列表中的元素
t[2][0]=2
# 下标访问元组
print(t[0])
print(t[2])

解包:

1
print(t)

元组拼接

1
tup3=tup1+tup2

运算与迭代

1
2
3
4
x=(1,2,3)*3 #表示复制三份拼接
print(3 in (1,2,3))
for i in x:
print(i)

Tips

  • 元组元素本身可能被修改, 例如其中的列表

    组建的球队人员不可更改, 但球员的特性可以修改

  • 关于逗号

    1
    2
    3
    4
    5
    6
    empty=()
    singleton='hello', #此处逗号不省略, 表示元组
    print(len(empty))
    print(len(singleton))
    x=('hello',) # 无逗号则为字符串
    print(x)
  • 1
    2
    3
    4
    5
    6
    x = (1,2,3)
    b = x
    print(b is x) # true
    x += (100,)
    print (x) # (1, 2, 3, 100)
    print (b) # (1, 2, 3)

    b = x 确实是引用赋值bx 一开始指向同一个对象。问题出在:元组是不可变的(immutable),+= 对它来说不是"原地追加",而是创建一个新元组

列表

  • 可以有任意数量个元素, 下标访问
  • 可以增删, 可以修改, 元素类型随意

操作

基本操作

1
2
3
4
5
6
7
8
9
# 空初始化
my_list=[]
# 追加任意类型元素
my_list.append(10)
my_list.append("hello")
#删除元素
del my_list[1]
#列表合并
list1+=[100.0]

“运算”

[a]+[b][a,b][a]+[b] \rightarrow [a,b]

[a]2[a,a][a]*2 \rightarrow [a,a]

python的变量是引用

1
2
3
4
5
6
7
8
9
10
11
a=[1,2,3]
x=['a','b','c']
n=[a,x]
print(n)
#注意!此时n[1]和a指向同一个对象[1, 2, 3]
a.append(4)
print(n)
#a.append()操作改变原对象,n也改变
a=[1,2,3]
print(n)
#a指向新对象,x仍指向原对象,n不改变

in关键字

可用于判断列表是否包含某个元素

x in list返回bool值

1
2
3
4
l=[1,2,3,4,5]
ll=[1]
print(4 in l, 4 in ll)
#True False

切片

基本语法( 左开右闭 )

1
2
a[start:end:step]
#缺省情况为为开头,结尾+1,1

范围

1
2
a=[1,2,3,4]
b=a[1:3]

负数

1
2
3
c=a[-1] #取尾元素
#逆序
d=a[::-1]

列表深拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import copy
a=[1,[2]]
b=copy.deepcopy(a) #深拷贝
bb=a[:]

b.append(4)
bb.append(4)

a[1].append(3)

print(a)
print(b)
print(bb)

# [1, [2,3]]
# [1, [2], 4]
# [1, [2,3], 4]

a=a+b先创建一个新对象,a后指向新对象

a+=b原地追加

⚠️对于元组: 则是无论如何都是重新创建并指向,因为元素不可修改

列表生成式

1
2
3
4
5
6
7
8
9
[x*x for x in range(1,11)]
# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

[m+n for m in 'ABC' for n in 'XYZ']
#['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

L=['Hello',18,'Apple',None]
[s.lower() for s in L if isinstance(s,str)]
#['hello','apple']

元组生成式

print(tuple(x*x for x in range(1,11)))

用列表生成式处理输入

1
2
3
4
5
6
7
8
9
10
11
try:
while True:
s=input()
if s.strip()=="":
continue
a=s.split()
b=[x for x in a if x!=''] #去除空串
name,age,gpa=b[0],b[1],b[2]
print(name,age,gpa)
except EOFError:
pass
1
2
3
4
5
6
7
8
标准输入:
jack 12 3.5
marry 34 7.8
Jane 34 7.8
输出:
jack 12 3.5
marry 34 7.8
Jane 34 7.8

相关函数

  • index(v)查找元素v, 返回首次出现的下标, 如果没有则异常
  • insert(i,v)插入元素v到下标i处
  • remove(v)删除首次出现的元素v
  • append(value)
  • len(x)
  • extend(list)添加其他表中的元素到尾部
  • reverse()颠倒

更多函数

map和filter

此处返回的迭代器对象–表示延时求值, 只是规划, 不占内存

  • map(function,sequence)将一个列表(元组)中的元素一一作用, 返回迭代器对象
  • fliter(function,sequence)将一个列表(元组)中的不满足function元素过滤掉, 返回迭代器对象
1
2
3
4
5
6
7
8
9
10
11
def f1(x):
return x*2
def f2(x):
return x%2==0
ls=[1,2,3,4,5]
ls1=tuple(map(f1,ls))
print(ls1)
# (2, 4, 6, 8, 10)
ls1=list(filter(f2,ls))
print(ls1)
# [2, 4]

高级用法

map(func,iterable1,itrable2,...)

函数传入参数个数要对应

reduce

reduce(function,sequence,startValue)

将一个列表累积起来

1
2
3
4
5
6
from functools import reduce
def f2(x,y):
return x+y
ls=[1,2,3,4,5]
print(reduce(f2,ls)) #15
print(reduce(f2,ls,10)) #25

定义二维数组

1
2
3
#直接定义
#生成定义
matrix=[[i*3+j for j in range(3)] for i in range(3)]

❌错误做法:

1
2
3
4
5
6
7
8
9
10
array=[1,2,4]
matrix=[array*3]
print(matrix)
#得到[[1, 2, 3, 1, 2, 3, 1, 2, 3]]非目的
matrix=[array]*3
print(matrix)
#得到[[1, 2, 4], [1, 2, 4], [1, 2, 4]]但是三行指向同一对象,参见:(非目的)
matrix[0][0]=0
print(matrix)
#得到[[0, 2, 4], [0, 2, 4], [0, 2, 4]],三行首元素被同改,非目的

⚠️注意:

这里确实有个比较奇怪的事实:

对于[1]*3表示的是深拷贝三遍形成一个列表,修改a[0]其余元素不变

而对于[[1]]*3表示的是浅拷贝三遍一维列表形成一个二维数组,修改a[0][0]其余行元素也改变

列表大小比较

  • 逐元素相比,直到分出胜负

  • 若出现不能比较情况, 报错

列表排序

python的排序是稳定的, 相同key排序前后顺序不变

1
2
3
4
5
6
7
8
a.sort()
a.sort(reverse=True)
b=sorted(a) #a不变

#此外还内置key用于生成被排序的值以自定义排序
a=[1,2,3,4,5,6,7,8,9]
b=sorted(a,key=(lambda x:x%5),reverse=True)
print(b)

⚠️key: 传入一个参数生成一个用于排序的值

元组不可修改, 因此无sort, 但可用sorted

对于二维数组的指定排序

1
2
3
from operator import *
print(sorted(students,key=itemgetter(0,1)))
#先按第一个排,再按第二个排

itemgetter(n)取对象的第n个元素

字典

概念

  • dict
  • 每个元素由键:值构成, 可根据 查找, 必须可哈希
  • 键的内容不能一样, 且键必须是不可变数据类型 ( 尤其不可是list )
  • 快速查找, 速度高于list, 查找速度与元素个数无关
  • 可以混合不同类型的键值

格式

1
2
3
4
5
6
d={
key1:value1,
key2:value2,
...
}
# 定义中键不能重复, 否则最终只会保留一个

重复定义的键, 后面的覆盖前面的, 最后只保留最后的那个元素

操作

构造

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# way 1
items=[('name','Gumby'),('age',42)]
d=dict(items)
print(d)

# way 2
d=dict(name='Gumby',age=42)
print(d)
#{'name': 'Gumby', 'age': 42}

#查询键是否在字典内
print('age' in d)
#True

#正常=指向同一对象, 正常元素赋值
d={'name': 'Gumby', 'age': 42}
b = d;
b['name'] = "Tom"
print(d)
# {'name': 'Tom', 'age': 42}

添加元素

1
2
scope={}
scope['a']=3

删除操作

1
del scope['a']

删除和[]访问没有的键都会报错

安全访问

1
scope.get(key,default)
  • 这里的default缺省为None, 可自行设置默认返回值
  • 若不存在返回默认返回值

输出

1
2
3
4
phonebook={'Alice':'2341','Beth':'9102','Cecil':'3258'}
print("Cecil's phone number is %(Cecil)s."%phonebook)
print("Cecil's phone number is %s."%phonebook[Cecil])
#同样输出, 如今更常用f字符串

字典函数

  • clear: 清空字典

  • keys: 用于取字典的键, 为一种只读,支持集合运算的数据类型

    可以理解成是监视字典键的窗口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    d = {'Alice': 90}
    keys = d.keys() # 拿到窗口

    print(keys) # dict_keys(['Alice'])

    d['Bob'] = 85 # 字典变了
    print(keys) # dict_keys(['Alice', 'Bob']) ← 窗口自动变了!

    d.pop('Alice') # 删掉 Alice
    print(keys) # dict_keys(['Bob']) ← 又自动变了!

    支持集合运算

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    d1 = {'Alice': 1, 'Bob': 2, 'Charlie': 3}
    d2 = {'Bob': 4, 'David': 5, 'Alice': 6}

    # 交集:两个字典都有的键
    print(d1.keys() & d2.keys()) # {'Alice', 'Bob'}

    # 并集:所有出现过的键
    print(d1.keys() | d2.keys()) # {'Alice', 'Bob', 'Charlie', 'David'}

    # 差集:d1 有但 d2 没有的键
    print(d1.keys() - d2.keys()) # {'Charlie'}
  • items: 取字典的元素

  • values: 取字典的值

    1
    2
    3
    4
    5
    6
    7
    8
    #常用
    #遍历字典⚠️
    for x in d.items():
    print(x,end=",")
    for x in d.values():
    print(x,end=",")
    for x in d.keys():
    print(x,end=",")
  • copy: 浅拷贝

  • 深拷贝:

    1
    2
    3
    4
    5
    6
    7
    import copy
    x={'username':'admin','machine':['foo','bar','baz']}
    y=copy.deepcopy(x)
    y['username']='mlh'
    y['machine'].remove('bar')
    print(y)
    print(x)

集合

概念

  • set
  • 可修改, 概念同数学
  • 无重复元素
  • 无序
  • 列表和集合不可作为集合的元素, 元素必须可哈希
  • 快速查找, 查找时间和元素个数无关
  • 若有重复, 会自动去重

操作

  • 创建

    1
    2
    3
    4
    5
    6
    7
    8
    9
    s={}
    s={1,2,'ok',(1,3)}
    print(s)
    #{'ok', 1, 2, (1, 3)}
    s=set('abc') #字符串转集合
    print(s)
    #{'a', 'b', 'c'}
    s=set([1,'ok',2.4])
    print(s)
  • add(x): 增加

  • 集合运算

    1
    2
    3
    4
    5
    6
    7
    a={1,3,3,'e'}
    b={2,3,'e'}
    print(a&b) #求交
    print(a|b) #求并
    print(a-b) #求差
    a-=b
    print(a)
  • update(x): 将参数分开并加入集合(参数可以是集合\字典\列表\元组等, x可有多个(逗号隔开))

    1
    2
    3
    4
    5
    a={1}
    a.update([34,22,1])
    print(a)
    a.update("hello")
    print(a)
  • remove(x): 删除元素, 若不存在会报错

  • discard(x):移除元素, 若不存在不会异常

  • 比较运算符, 判断是不是超集

  • clear(): 清空

  • difference(x): 返回在s而不在x中的元素的集合,不改变原内容

  • symmetric_difference(x): 返回对称差集,即只在其中一个集合中出现的元素, 不改变原内容,

  • in

  • union(x): 返回s和x的并集,不改变原内容

  • intersection(x) 返回交集,不改变原内容

  • issubset(x) 判断集合s是否是集合x子集

  • issuperset(x) s是否是x的超集

  • pop(): 随机删除并返回集合中的某个值

⚠️集合和字典都没有+的相关运算, set有add方法, 字典没有